./ 0000755 0000156 0000165 00000000000 12704153542 011100 5 ustar jenkins jenkins ./autogen.sh 0000755 0000156 0000165 00000001176 12704153542 013106 0 ustar jenkins jenkins #!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="notify-osd"
REQUIRED_AUTOCONF_VERSION=2.59
REQUIRED_AUTOMAKE_VERSION=1.8
REQUIRED_MACROS="python.m4"
ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4"
(test -f $srcdir/configure.in) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory"
exit 1
}
which gnome-autogen.sh || {
echo "You need to install the gnome-common module and make"
echo "sure the gnome-autogen.sh script is in your \$PATH."
exit 1
}
USE_GNOME2_MACROS=1 . gnome-autogen.sh
./tests/ 0000755 0000156 0000165 00000000000 12704153542 012242 5 ustar jenkins jenkins ./tests/notifyosd.py 0000755 0000156 0000165 00000004105 12704153542 014635 0 ustar jenkins jenkins #!/usr/bin/python
import sys
import time
from optparse import OptionParser
import gtk
import pynotify
ICON_ONLY_HINT = "x-canonical-private-icon-only"
APPEND_HINT = "x-canonical-append"
SYNCHRONOUS_HINT = "x-canonical-private-synchronous"
VALUE_HINT = "value"
def create_gauge_notification(title, icon, value):
n = pynotify.Notification(title, "", icon)
n.set_hint_string(SYNCHRONOUS_HINT, "")
n.set_hint_int32(VALUE_HINT, value)
return n
def create_icon_only_notification(title, icon):
n = pynotify.Notification(title, "", icon)
n.set_hint_string(ICON_ONLY_HINT, "")
return n
USAGE = \
"""%prog [options]
[]
If body-text is "-" %prog will display the content of stdin.
"""
def main ():
if not pynotify.init("notifyosd"):
return 1
parser = OptionParser()
parser.usage = USAGE
parser.add_option("-i", "--icon", dest="icon",
help = "Name of the icon to show")
parser.add_option("--icon-data", dest="icon_data",
help = "Load icon data from a custom file")
parser.add_option("-v", "--value", dest="value",
help = "Start in value mode and display the percentage VALUE in a gauge")
parser.add_option("--icon-only", dest="icon_only",
help = "Only show icon, ignoring body",
action="store_true", default=False)
(options, args) = parser.parse_args()
if len(args) == 0:
parser.print_usage()
return 1
title = args[0]
if len(args) > 1:
if args[1] == "-":
body = sys.stdin.read()
else:
body = " ".join(args[1:])
else:
body = ""
if options.value:
if body:
print "Note: ignoring body in value mode"
n = create_gauge_notification(title, options.icon, int(options.value))
elif options.icon_only:
if body:
print "Note: ignoring body in icon_only mode"
if not options.icon:
print "Error: icon name is missing"
return 1
n = create_icon_only_notification(title, options.icon)
else:
n = pynotify.Notification(title, body, options.icon)
if options.icon_data:
pixbuf = gtk.gdk.pixbuf_new_from_file(options.icon_data)
n.set_icon_from_pixbuf(pixbuf)
n.show ()
if __name__ == "__main__":
sys.exit (main ())
./tests/test-bubble.c 0000644 0000156 0000165 00000007755 12704153542 014634 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-bubble.c - implements unit-tests for rendering/displaying a bubble
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include "bubble.h"
#include "util.h"
static
gboolean
stop_main_loop (GMainLoop *loop)
{
g_main_loop_quit (loop);
return FALSE;
}
static
void
test_bubble_new (gpointer fixture, gconstpointer user_data)
{
Bubble* bubble;
Defaults* defaults;
defaults = defaults_new ();
bubble = bubble_new (defaults);
g_assert (bubble != NULL);
g_object_unref (bubble);
g_object_unref (defaults);
}
static
void
test_bubble_del (gpointer fixture, gconstpointer user_data)
{
Bubble* bubble;
Defaults* defaults;
defaults = defaults_new ();
bubble = bubble_new (defaults);
g_assert (bubble != NULL);
g_object_unref (bubble);
g_object_unref (defaults);
}
static
void
test_bubble_set_attributes (gpointer fixture, gconstpointer user_data)
{
Bubble* bubble;
GMainLoop* loop;
Defaults* defaults;
defaults = defaults_new ();
bubble = bubble_new (defaults);
bubble_set_icon (bubble, "/usr/share/icons/Human/scalable/status/notification-message-im.svg");
bubble_set_title (bubble, "Unit Testing");
bubble_set_message_body (bubble, "Long text that is hopefully wrapped");
bubble_determine_layout (bubble);
bubble_move (bubble, 30, 30);
bubble_show (bubble);
/* let the main loop run */
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (2000, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
g_object_unref (bubble);
g_object_unref (defaults);
}
static
void
test_bubble_get_attributes (gpointer fixture, gconstpointer user_data)
{
Bubble* bubble;
Defaults* defaults;
defaults = defaults_new ();
bubble = bubble_new (defaults);
bubble_set_title (bubble, "Foo Bar");
bubble_set_message_body (bubble, "Some message-body text.");
bubble_set_value (bubble, 42);
g_assert_cmpstr (bubble_get_title (bubble), ==, "Foo Bar");
g_assert_cmpstr (bubble_get_message_body (bubble),
==,
"Some message-body text.");
g_assert_cmpint (bubble_get_value (bubble), ==, 42);
g_object_unref (bubble);
g_object_unref (defaults);
}
GTestSuite *
test_bubble_create_test_suite (void)
{
GTestSuite *ts = NULL;
GTestCase *tc = NULL;
ts = g_test_create_suite ("bubble");
tc = g_test_create_case ("can create a new bubble",
0,
NULL,
NULL,
test_bubble_new,
NULL);
g_test_suite_add (ts, tc);
g_test_suite_add(ts,
g_test_create_case ("can delete a bubble",
0,
NULL,
NULL,
test_bubble_del,
NULL)
);
g_test_suite_add (ts,
g_test_create_case ("can set bubble attributes",
0,
NULL,
NULL,
test_bubble_set_attributes,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can get bubble attributes",
0,
NULL,
NULL,
test_bubble_get_attributes,
NULL));
return ts;
}
./tests/test-i18n.c 0000644 0000156 0000165 00000012270 12704153542 014144 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-i18n.c - unit-tests for internationalization
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include "bubble.h"
#include "stack.h"
#include "observer.h"
#include "defaults.h"
static
gboolean
stop_main_loop (GMainLoop *loop)
{
g_main_loop_quit (loop);
return FALSE;
}
static
void
wait_a_little (guint interval)
{
/* let the main loop run to have the slide being performed */
GMainLoop *loop;
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (interval, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
}
static void
test_stack_layout (gpointer fixture, gconstpointer user_data)
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
stack = stack_new (defaults, observer);
g_assert (stack != NULL);
gtk_widget_set_default_direction (GTK_TEXT_DIR_LTR);
Bubble *bubble = bubble_new (defaults);
bubble_set_icon (bubble, SRCDIR"/icons/chat.svg");
bubble_set_title (bubble, "LTR Text");
bubble_set_message_body (bubble, "This should be displayed at the right of your screen. Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu");
bubble_determine_layout (bubble);
stack_push_bubble (stack, bubble);
wait_a_little (10000);
stack_del (stack);
}
static void
test_stack_layout_rtl (gpointer fixture, gconstpointer user_data)
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
stack = stack_new (defaults, observer);
g_assert (stack != NULL);
gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
Bubble *bubble = bubble_new (defaults);
bubble_set_icon (bubble, SRCDIR"/icons/chat.svg");
bubble_set_title (bubble, "RTL Text");
bubble_set_message_body (bubble, "This should be displayed at the left of your screen. Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu Ubuntu");
bubble_determine_layout (bubble);
stack_push_bubble (stack, bubble);
wait_a_little (10000);
stack_del (stack);
}
#define GENERATE(x, y) \
static void x (gpointer fixture, gconstpointer user_data) \
{ \
Defaults* defaults = defaults_new (); \
Bubble *bubble = bubble_new (defaults); \
bubble_set_icon (bubble, SRCDIR"/icons/chat.svg"); \
bubble_set_title (bubble, y); \
bubble_set_message_body (bubble, #y#y#y#y#y); \
bubble_determine_layout (bubble); \
bubble_move (bubble, 30, 30); \
bubble_show (bubble); \
wait_a_little (1000); \
g_object_unref (G_OBJECT(bubble)); \
g_object_unref (defaults); \
}
GENERATE(en, "About Ubuntu")
GENERATE(ca, "Quant a Ubuntu")
GENERATE(da, "Om Ubuntu")
GENERATE(de, "Über Ubuntu")
GENERATE(el, "Περί Ubuntu")
GENERATE(es, "Acerca de Ubuntu")
GENERATE(fa, "درباره Ubuntu")
GENERATE(fi, "Tietoja Ubuntusta")
GENERATE(fr, "À propos d'Ubuntu")
GENERATE(he, "אודות אובונטו")
GENERATE(hu, "Az Ubuntu névjegye")
GENERATE(is, "Um Ubuntu")
GENERATE(it, "Informazioni su Ubuntu")
GENERATE(nl, "Over Ubuntu")
GENERATE(pt, "Sobre o Ubuntu")
GENERATE(pt_BR, "Sobre o Ubuntu")
GENERATE(ro, "Despre Ubuntu")
GENERATE(sk, "O Ubuntu")
GENERATE(sv, "Om Ubuntu")
GENERATE(xh, "Malunga ne-Ubuntu")
GENERATE(zh_CN, "关于 Ubuntu")
GTestSuite *
test_i18n_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("i18n");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_stack_layout));
g_test_suite_add(ts, TC(test_stack_layout_rtl));
g_test_suite_add(ts, TC(en));
g_test_suite_add(ts, TC(ca));
g_test_suite_add(ts, TC(da));
g_test_suite_add(ts, TC(de));
g_test_suite_add(ts, TC(el));
g_test_suite_add(ts, TC(es));
g_test_suite_add(ts, TC(fa));
g_test_suite_add(ts, TC(fi));
g_test_suite_add(ts, TC(fr));
g_test_suite_add(ts, TC(he));
g_test_suite_add(ts, TC(hu));
g_test_suite_add(ts, TC(is));
g_test_suite_add(ts, TC(it));
g_test_suite_add(ts, TC(nl));
g_test_suite_add(ts, TC(pt));
g_test_suite_add(ts, TC(pt_BR));
g_test_suite_add(ts, TC(ro));
g_test_suite_add(ts, TC(sk));
g_test_suite_add(ts, TC(sv));
g_test_suite_add(ts, TC(xh));
g_test_suite_add(ts, TC(zh_CN));
return ts;
}
./tests/test-withlib.c 0000644 0000156 0000165 00000025016 12704153542 015031 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-withlib.c - libnotify based unit-tests
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include "dbus.h"
#include "stack.h"
#include "config.h"
/* #define DBUS_NAME "org.freedesktop.Notifications" */
static
gboolean
stop_main_loop (GMainLoop *loop)
{
g_main_loop_quit (loop);
return FALSE;
}
static void
test_withlib_setup (gpointer fixture, gconstpointer user_data)
{
notify_init ("libnotify");
}
static void
test_withlib_get_server_information (gpointer fixture, gconstpointer user_data)
{
gchar *name = NULL, *vendor = NULL, *version = NULL, *specver = NULL;
gboolean ret = FALSE;
ret = notify_get_server_info (&name, &vendor, &version, &specver);
g_assert (ret);
g_assert (g_strrstr (name, "notify-osd"));
g_assert (g_strrstr (specver, "1.1"));
}
static void
test_withlib_get_server_caps (gpointer fixture, gconstpointer user_data)
{
GList *cap, *caps = NULL;
gboolean test = FALSE;
caps = notify_get_server_caps ();
g_assert (caps);
for (cap = g_list_first (caps);
cap != NULL;
cap = g_list_next (cap))
{
if (!g_strcmp0 (cap->data, "x-canonical-private-synchronous") ||
!g_strcmp0 (cap->data, "x-canonical-append") ||
!g_strcmp0 (cap->data, "x-canonical-private-icon-only") ||
!g_strcmp0 (cap->data, "x-canonical-truncation"))
test = TRUE;
}
g_assert (test);
}
static void
test_withlib_show_notification (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
n = notify_notification_new ("Test",
"You should see a normal notification",
"");
notify_notification_show (n, NULL);
sleep (3);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_update_notification (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
gboolean res = FALSE;
n = notify_notification_new ("Test",
"New notification",
"");
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (1);
res = notify_notification_update (n, "Test (updated)",
"The message body has been updated...",
"");
g_assert (res);
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (3);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_pass_icon_data (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
GdkPixbuf* pixbuf;
GMainLoop* loop;
n = notify_notification_new ("Image Test",
"You should see an image",
"");
g_print ("iconpath: %s\n", SRCDIR"/icons/avatar.png");
pixbuf = gdk_pixbuf_new_from_file_at_scale (SRCDIR"/icons/avatar.png",
64, 64, TRUE, NULL);
notify_notification_set_icon_from_pixbuf (n, pixbuf);
notify_notification_show (n, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add (2000, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_priority (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n1, *n2, *n3, *n4;
GMainLoop* loop;
n1 = notify_notification_new ("Dummy Notification",
"This is a test notification",
"");
notify_notification_show (n1, NULL);
n2 = notify_notification_new ("Normal Notification",
"You should see this *after* the urgent notification.",
"");
notify_notification_set_urgency (n2, NOTIFY_URGENCY_LOW);
notify_notification_show (n2, NULL);
n3 = notify_notification_new ("Synchronous Notification",
"You should immediately see this notification.",
"");
notify_notification_set_hint_string (n3, "synchronous", "test");
notify_notification_set_urgency (n3, NOTIFY_URGENCY_NORMAL);
notify_notification_show (n3, NULL);
n4 = notify_notification_new ("Urgent Notification",
"You should see a dialog box, and after, a normal notification.",
"");
notify_notification_set_urgency (n4, NOTIFY_URGENCY_CRITICAL);
notify_notification_show (n4, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add (8000, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
g_object_unref(G_OBJECT(n1));
g_object_unref(G_OBJECT(n2));
g_object_unref(G_OBJECT(n3));
g_object_unref(G_OBJECT(n4));
}
static GMainLoop* loop;
static char* test_action_callback_data = "Some string to pass to the action callback";
static void
callback (NotifyNotification *n,
const char *action,
void *user_data)
{
g_assert (g_strcmp0 (action, "action") == 0);
g_assert (user_data == test_action_callback_data);
g_main_loop_quit (loop);
}
static void
test_withlib_actions (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n1;
n1 = notify_notification_new ("Notification with an action",
"You should see that in a dialog box. Click the 'Action' button for the test to succeed.",
"");
notify_notification_add_action (n1,
"action",
"Action",
(NotifyActionCallback)callback,
test_action_callback_data,
NULL);
notify_notification_show (n1, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run (loop);
g_object_unref(G_OBJECT(n1));
}
static void
test_withlib_close_notification (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
GMainLoop* loop;
gboolean res = FALSE;
n = notify_notification_new ("Test Title",
"This notification will be closed prematurely...",
"");
notify_notification_show (n, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_timeout_add (1000, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
res = notify_notification_close (n, NULL);
g_assert (res);
g_timeout_add (2000, (GSourceFunc) stop_main_loop, loop);
g_main_loop_run (loop);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_append_hint (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
gboolean res = FALSE;
/* init notification, supply first line of body-text */
n = notify_notification_new ("Test (append-hint)",
"The quick brown fox jumps over the lazy dog.",
SRCDIR"/icons/avatar.png");
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (1);
/* append second part of body-text */
res = notify_notification_update (n,
" ",
"Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. (first append)",
NULL);
notify_notification_set_hint_string (n, "append", "allowed");
g_assert (res);
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (1);
/* append third part of body-text */
res = notify_notification_update (n,
" ",
"Съешь ещё этих мягких французских булок, да выпей чаю. (last append)",
NULL);
notify_notification_set_hint_string (n, "append", "allowed");
g_assert (res);
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (1);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_icon_only_hint (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
gboolean res = FALSE;
/* init notification, supply first line of body-text */
n = notify_notification_new (" ", /* needs this to be non-NULL */
NULL,
"notification-audio-play");
notify_notification_set_hint_string (n, "icon-only", "allowed");
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (1);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_swallow_markup (gpointer fixture, gconstpointer user_data)
{
NotifyNotification *n;
gboolean res = FALSE;
n = notify_notification_new ("Swallow markup test",
"This text is hopefully neither bold, italic nor underlined.\n\nA little math-notation:\n\n\ta > b < c = 0",
SRCDIR"/icons/avatar.png");
res = notify_notification_show (n, NULL);
g_assert (res);
sleep (2);
g_object_unref(G_OBJECT(n));
}
static void
test_withlib_throttle (gpointer fixture, gconstpointer user_data)
{
NotifyNotification* n;
gint i;
gboolean res;
gchar buf[20];
GError* error = NULL;
// see https://wiki.ubuntu.com/NotifyOSD#Flood%20prevention
for (i = 0; i < MAX_STACK_SIZE + 10; i++)
{
// pretty-ify the output a bit
if (i == 0)
g_print ("\n");
// create dummy notification
snprintf (buf, 19, "Test #%.2d", i);
n = notify_notification_new (buf, buf, "");
// inject it into the queue
res = notify_notification_show (n, &error);
// spit out error from notification-daemon
if (!res && error)
{
g_print ("Error \"%s\" while trying to show #%.2d\n",
error->message,
i);
g_error_free (error);
error = NULL;
}
// check if reaching limit causes error
if (i > MAX_STACK_SIZE)
g_assert (!res);
g_object_unref (n);
}
}
GTestSuite *
test_withlib_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("libnotify");
#define ADD_TEST(x) g_test_suite_add(ts, \
g_test_create_case(#x, 0, NULL, test_withlib_setup, x, NULL) \
)
ADD_TEST(test_withlib_get_server_information);
ADD_TEST(test_withlib_get_server_caps);
ADD_TEST(test_withlib_show_notification);
ADD_TEST(test_withlib_update_notification);
ADD_TEST(test_withlib_pass_icon_data);
ADD_TEST(test_withlib_close_notification);
ADD_TEST(test_withlib_priority);
ADD_TEST(test_withlib_append_hint);
ADD_TEST(test_withlib_icon_only_hint);
ADD_TEST(test_withlib_swallow_markup);
// FIXME: Disable action test until we can make it non-interactive
//ADD_TEST(test_withlib_actions);
ADD_TEST(test_withlib_throttle);
return ts;
}
./tests/test-stack.c 0000644 0000156 0000165 00000015204 12704153542 014472 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-stack.c - unit-tests for stack class
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "stack.h"
#include "defaults.h"
#include "bubble.h"
static
void
test_stack_new ()
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
stack = stack_new (defaults, observer);
g_assert (stack != NULL);
}
static
void
test_stack_del ()
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
stack = stack_new (defaults, observer);
stack_del (stack);
}
static
void
test_stack_push ()
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
Bubble* bubble = bubble_new (defaults);
guint id = -1;
guint replaced_id = -1;
stack = stack_new (defaults, observer);
id = stack_push_bubble (stack, bubble);
g_assert (id > 0);
replaced_id = stack_push_bubble (stack, bubble);
g_assert (replaced_id == id);
g_object_unref (G_OBJECT (stack));
}
static void
test_stack_slots ()
{
Stack* stack = NULL;
Defaults* defaults = defaults_new ();
Observer* observer = observer_new ();
gint x;
gint y;
Bubble* one;
Bubble* two;
stack = stack_new (defaults, observer);
// check if stack_is_slot_vacant() can take "crap" without crashing
g_assert_cmpint (stack_is_slot_vacant (NULL, SLOT_TOP), ==, FALSE);
g_assert_cmpint (stack_is_slot_vacant (stack, 832), ==, FALSE);
g_assert_cmpint (stack_is_slot_vacant (NULL, 4321), ==, FALSE);
// check if stack_get_slot_position can take "crap" without crashing
stack_get_slot_position (NULL, SLOT_TOP, 0, &x, &y);
g_assert_cmpint (x, ==, -1);
g_assert_cmpint (y, ==, -1);
stack_get_slot_position (stack, 4711, 0, &x, &y);
g_assert_cmpint (x, ==, -1);
g_assert_cmpint (y, ==, -1);
stack_get_slot_position (NULL, 42, 0, NULL, NULL);
// check if stack_allocate_slot() can take "crap" without crashing
one = bubble_new (defaults);
two = bubble_new (defaults);
g_assert_cmpint (stack_allocate_slot (NULL, one, SLOT_TOP), ==, FALSE);
g_assert_cmpint (stack_allocate_slot (stack, NULL, SLOT_TOP), ==, FALSE);
g_assert_cmpint (stack_allocate_slot (stack, one, 4711), ==, FALSE);
// check if stack_free_slot() can take "crap" without crashing
g_assert_cmpint (stack_free_slot (NULL, two), ==, FALSE);
g_assert_cmpint (stack_free_slot (stack, NULL), ==, FALSE);
// initially both slots should be empty
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
g_object_unref (one);
g_object_unref (two);
// fill top slot, verify it's occupied, free it, verify again
one = bubble_new (defaults);
g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_TOP), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, OCCUPIED);
g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
g_object_unref (one);
// fill bottom slot, verify it's occupied, free it, verify again
two = bubble_new (defaults);
g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_BOTTOM), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, OCCUPIED);
g_assert_cmpint (stack_free_slot (stack, two), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
g_object_unref (two);
// try to free vacant slots
one = bubble_new (defaults);
two = bubble_new (defaults);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
g_assert_cmpint (stack_free_slot (stack, one), ==, FALSE);
g_assert_cmpint (stack_free_slot (stack, two), ==, FALSE);
g_object_unref (one);
g_object_unref (two);
// allocate top slot, verify, try to allocate top slot again
one = bubble_new (defaults);
two = bubble_new (defaults);
g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_TOP), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, OCCUPIED);
g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_TOP), ==, FALSE);
g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
g_object_unref (one);
g_object_unref (two);
// allocate bottom slot, verify, try to allocate bottom slot again
one = bubble_new (defaults);
two = bubble_new (defaults);
g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_BOTTOM), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, OCCUPIED);
g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_BOTTOM), ==, FALSE);
g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
g_object_unref (one);
g_object_unref (two);
// check if we can get reasonable values from stack_get_slot_position()
// FIXME: disabled this test for the moment, hopefully it works within
// a real environment
/*stack_get_slot_position (stack, SLOT_TOP, &x, &y);
g_assert_cmpint (x, >, -1);
g_assert_cmpint (y, >, -1);
stack_get_slot_position (stack, SLOT_BOTTOM, &x, &y);
g_assert_cmpint (x, >, -1);
g_assert_cmpint (y, >, -1);*/
g_object_unref (G_OBJECT (stack));
}
GTestSuite *
test_stack_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("stack");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_stack_new));
g_test_suite_add(ts, TC(test_stack_del));
g_test_suite_add(ts, TC(test_stack_push));
g_test_suite_add(ts, TC(test_stack_slots));
return ts;
}
./tests/Makefile.am 0000644 0000156 0000165 00000011434 12704153542 014301 0 ustar jenkins jenkins noinst_PROGRAMS = test-modules \
test-timeline \
test-timeline-dup-frames \
test-timeline-interpolate \
test-timeline-rewind \
test-timeline-smoothness \
test-alpha-animation \
test-raico \
test-tile \
test-grow-bubble \
test-scroll-text
check_PROGRAMS = test-modules
TESTS = test-modules
GCOV_CFLAGS = -fprofile-arcs -ftest-coverage
test_modules_SOURCES = \
$(top_srcdir)/src/bubble.c \
$(top_srcdir)/src/defaults.c \
$(top_srcdir)/src/dialog.c \
$(top_srcdir)/src/notification.c \
$(top_srcdir)/src/observer.c \
$(top_srcdir)/src/stack.c \
$(top_srcdir)/src/dbus.c \
$(top_srcdir)/src/dnd.c \
$(top_srcdir)/src/apport.c \
$(top_srcdir)/src/util.c \
$(top_srcdir)/src/stack-blur.c \
$(top_srcdir)/src/exponential-blur.c \
$(top_srcdir)/src/gaussian-blur.c \
$(top_srcdir)/src/raico-blur.c \
$(top_srcdir)/src/tile.c \
$(top_srcdir)/src/bubble-window.c \
$(top_srcdir)/src/bubble-window-accessible.c \
$(top_srcdir)/src/bubble-window-accessible-factory.c \
$(top_srcdir)/src/log.c \
$(top_srcdir)/src/timings.c \
$(EGG_MODULES) \
test-modules-main.c \
test-apport.c \
test-dbus.c \
test-withlib.c \
test-bubble.c \
test-defaults.c \
test-notification.c \
test-observer.c \
test-i18n.c \
test-synchronous.c \
test-dnd.c \
test-stack.c \
test-timings.c \
test-text-filtering.c
test_modules_CFLAGS = \
$(GCOV_CFLAGS) \
-Wall \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS) \
-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
$(WNCK_CFLAGS) \
$(DBUS_CFLAGS) \
$(LIBNOTIFY_CFLAGS) \
-DSRCDIR=\""$(abs_top_srcdir)"\" \
-I$(top_srcdir)/src \
-I$(top_srcdir)/
test_modules_LDADD = \
$(LIBM) \
$(X_LIBS) \
$(GLIB_LIBS) \
$(WNCK_LIBS) \
$(DBUS_LIBS) \
$(LIBNOTIFY_LIBS) \
$(NOTIFY_OSD_LIBS) \
$(GTK_LIBS) \
-lnotify
EGG_MODULES = \
$(top_srcdir)/egg/egg-fixed.c \
$(top_srcdir)/egg/egg-units.c \
$(top_srcdir)/egg/egg-timeline.c \
$(top_srcdir)/egg/egg-timeout-pool.c \
$(top_srcdir)/egg/egg-alpha.c \
$(top_srcdir)/egg/egg-hack.c
VALGRIND_FLAGS = \
--tool=memcheck --suppressions=$(srcdir)/tests.suppression \
--leak-check=yes --show-reachable=yes
OLD_ENVIRONMENT = $(ENV)
AM_CFLAGS = \
$(GCOV_CFLAGS) \
-Wall \
$(GLIB_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/egg -I$(top_srcdir)
LDADD = $(GLIB_LIBS) -lm
test_timeline_SOURCES = $(top_srcdir)/egg/test-timeline.c \
$(EGG_MODULES)
test_timeline_dup_frames_SOURCES = $(top_srcdir)/egg/test-timeline-dup-frames.c \
$(EGG_MODULES)
test_timeline_interpolate_SOURCES = $(top_srcdir)/egg/test-timeline-interpolate.c \
$(EGG_MODULES)
test_timeline_rewind_SOURCES = $(top_srcdir)/egg/test-timeline-rewind.c \
$(EGG_MODULES)
test_timeline_smoothness_SOURCES = $(top_srcdir)/egg/test-timeline-smoothness.c \
$(EGG_MODULES)
test_alpha_animation_SOURCES = test-alpha-animation.c \
$(EGG_MODULES)
RAICO_MODULES = \
$(top_srcdir)/src/stack-blur.c \
$(top_srcdir)/src/exponential-blur.c \
$(top_srcdir)/src/gaussian-blur.c \
$(top_srcdir)/src/raico-blur.c
test_raico_SOURCES = \
$(RAICO_MODULES) \
test-raico.c
test_raico_CFLAGS = \
-Wall -O0 -ggdb \
$(GTK_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/
test_raico_LDADD = \
$(LIBM) \
$(NOTIFY_OSD_LIBS) \
$(GTK_LIBS)
TILE_MODULES = \
$(RAICO_MODULES) \
$(top_srcdir)/src/util.c \
$(top_srcdir)/src/tile.c
test_tile_SOURCES = \
$(TILE_MODULES) \
test-tile.c
test_tile_CFLAGS = \
-Wall -O0 -ggdb \
$(GTK_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)
test_tile_LDADD = \
$(LIBM) \
$(X_LIBS) \
$(NOTIFY_OSD_LIBS) \
$(GTK_LIBS)
GROW_BUBBLE_MODULES = \
$(RAICO_MODULES) \
$(top_srcdir)/src/tile.c
test_grow_bubble_SOURCES = \
$(TILE_MODULES) \
test-grow-bubble.c
test_grow_bubble_CFLAGS = \
-Wall -O0 -ggdb \
$(GTK_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)
test_grow_bubble_LDADD = \
$(LIBM) \
$(X_LIBS) \
$(NOTIFY_OSD_LIBS) \
$(GTK_LIBS)
SCROLL_TEXT_MODULES = \
$(RAICO_MODULES) \
../src/tile.c
test_scroll_text_SOURCES = \
$(TILE_MODULES) \
test-scroll-text.c
test_scroll_text_CFLAGS = \
-Wall -O0 -ggdb \
$(GTK_CFLAGS) \
-I$(top_srcdir)/src \
-I$(top_srcdir)/
test_scroll_text_LDADD = \
$(LIBM) \
$(X_LIBS) \
$(NOTIFY_OSD_LIBS) \
$(GTK_LIBS)
check-valgrind:
$(MAKE) $(AM_MAKEFLAGS) check G_SLICE=always-malloc G_DEBUG=gc-friendly TESTS_ENVIRONMENT='$(OLD_ENVIRONMENT) $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
test: test-modules
gtester -o=test-modules.xml -k ./test-modules
i18n: test-modules
gtester --verbose -p=/i18n -k ./test-modules
test-report-html: test
gtester-report test-modules.xml >test-modules.html
test-report-display: test-report-html
gnome-open test-modules.html
distclean-local:
rm -rf *.gcno
rm -rf *.gcda
./tests/test-defaults.c 0000644 0000156 0000165 00000011000 12704153542 015162 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-defaults.c - implements unit-tests for defaults class
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "defaults.h"
static
void
test_defaults_new ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_assert (defaults != NULL);
g_object_unref (defaults);
}
static
void
test_defaults_del ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_object_unref (defaults);
}
static
void
test_defaults_get_desktop_width ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_assert_cmpint (defaults_get_desktop_width (defaults), <=, G_MAXINT);
g_assert_cmpint (defaults_get_desktop_width (defaults), >=, 640);
g_object_unref (defaults);
}
static
void
test_defaults_get_desktop_height ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_assert_cmpint (defaults_get_desktop_height (defaults), <=, G_MAXINT);
g_assert_cmpint (defaults_get_desktop_height (defaults), >=, 600);
g_object_unref (defaults);
}
static
void
test_defaults_get_stack_height ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_assert_cmpint (defaults_get_stack_height (defaults), <=, G_MAXINT);
g_assert_cmpint (defaults_get_stack_height (defaults), >=, 0);
g_object_unref (defaults);
}
static
void
test_defaults_get_bubble_width ()
{
Defaults* defaults = NULL;
defaults = defaults_new ();
g_assert_cmpfloat (defaults_get_bubble_width (defaults), <=, 256.0f);
g_assert_cmpfloat (defaults_get_bubble_width (defaults), >=, 0.0f);
g_object_unref (defaults);
}
static void
test_defaults_get_gravity ()
{
Defaults* defaults = defaults_new ();
// upon creation the gravity should not be unset
g_assert_cmpint (defaults_get_gravity (defaults), !=, GRAVITY_NONE);
// currently the default value should be NE (top-right) gravity
g_assert_cmpint (defaults_get_gravity (defaults), ==, GRAVITY_NORTH_EAST);
// check if we can pass "crap" to the call without causing a crash
g_assert_cmpint (defaults_get_gravity (NULL), ==, GRAVITY_NONE);
g_object_unref (G_OBJECT (defaults));
}
static void
test_defaults_get_slot_allocation ()
{
Defaults* defaults = defaults_new ();
// upon creation slot-allocation should not be unset
g_assert_cmpint (defaults_get_slot_allocation (defaults),
!=,
SLOT_ALLOCATION_NONE);
// currently the default value should be SLOT_ALLOCATION_FIXED
g_assert_cmpint (defaults_get_slot_allocation (defaults),
==,
SLOT_ALLOCATION_FIXED);
// check if we can pass "crap" to the call without causing a crash
g_assert_cmpint (defaults_get_slot_allocation (NULL),
==,
SLOT_ALLOCATION_NONE);
g_object_unref (G_OBJECT (defaults));
}
GTestSuite *
test_defaults_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("defaults");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_defaults_new));
g_test_suite_add(ts, TC(test_defaults_del));
g_test_suite_add(ts, TC(test_defaults_get_desktop_width));
g_test_suite_add(ts, TC(test_defaults_get_desktop_height));
g_test_suite_add(ts, TC(test_defaults_get_stack_height));
g_test_suite_add(ts, TC(test_defaults_get_bubble_width));
g_test_suite_add(ts, TC(test_defaults_get_gravity));
g_test_suite_add(ts, TC(test_defaults_get_slot_allocation));
return ts;
}
./tests/test-synchronous.c 0000644 0000156 0000165 00000005767 12704153542 015774 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-synchronous.c - unit-tests for synchronous bubbles
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include "dbus.h"
static void
send_normal (const gchar *message)
{
NotifyNotification *n;
n = notify_notification_new ("Test notification",
g_strdup (message),
"");
notify_notification_show (n, NULL);
g_object_unref(G_OBJECT(n));
}
static void
send_synchronous (const char *type,
const char *icon,
gint value)
{
static NotifyNotification *n = NULL;
if (n == NULL)
n = notify_notification_new (" ",
"",
g_strdup (icon));
else
notify_notification_update (n,
" ",
"",
g_strdup (icon));
notify_notification_set_hint_int32(n, "value", value);
notify_notification_set_hint_string(n, "x-canonical-private-synchronous", g_strdup (type));
notify_notification_show (n, NULL);
}
#define set_volume(x) send_synchronous ("volume", "notification-audio-volume-medium", x)
#define set_brightness(x) send_synchronous ("brightness", "notification-display-brightness-medium", x)
static void
test_synchronous_layout (gpointer fixture, gconstpointer user_data)
{
notify_init (__FILE__);
send_normal ("Hey, what about this restaurant? http://www.blafasel.org"
""
"Would you go from your place by train or should I pick you up from work? What do you think?"
);
sleep (1);
set_volume (0);
sleep (1);
set_volume (75);
sleep (1);
set_volume (90);
sleep (1);
set_volume (100);
sleep (1);
send_normal ("Ok, let's go for this one");
sleep (1);
set_volume (99);
}
GTestSuite *
test_synchronous_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("synchronous");
g_test_suite_add(ts,
g_test_create_case ("synchronous layout",
0,
NULL,
NULL,
(GTestFixtureFunc) test_synchronous_layout,
NULL)
);
return ts;
}
./tests/test-raico.c 0000644 0000156 0000165 00000005011 12704153542 014455 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// raico-test.c - exercises the raico-API for blurring cairo image-surfaces
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include "raico-blur.h"
#define WIDTH 500
#define HEIGHT 500
int
main (int argc,
char** argv)
{
cairo_surface_t* surface = NULL;
cairo_t* cr = NULL;
raico_blur_t* blur = NULL;
// create and setup image-surface and context
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
WIDTH,
HEIGHT);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
g_debug ("Could not create image-surface!");
return 1;
}
cr = cairo_create (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
g_debug ("Could not create cairo-context!");
return 2;
}
// create and setup blur
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, 5);
// draw something
cairo_scale (cr, WIDTH, HEIGHT);
cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f);
cairo_paint (cr);
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 1.0f);
cairo_set_line_width (cr, 0.02f);
cairo_arc (cr, 0.5f, 0.5f, 0.4f, 0.0f, 360.0f * G_PI / 180.0f);
cairo_stroke (cr);
// now blur it
raico_blur_apply (blur, surface);
// save surface to a PNG-file
cairo_surface_write_to_png (surface, "./raico-result.png");
g_print ("See file raico-result.png in current directory for output.\n");
// clean up
cairo_destroy (cr);
cairo_surface_destroy (surface);
raico_blur_destroy (blur);
return 0;
}
./tests/test-notification.c 0000644 0000156 0000165 00000041221 12704153542 016051 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// test-notification.c - implements unit-tests for exercising API of abstract
// notification object
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#define _XOPEN_SOURCE 500 // needed for usleep() from unistd.h
#include
#include "notification.h"
static void
test_notification_new (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
GTimeVal* timestamp;
// create new object
n = notification_new ();
// test validity of main notification object
g_assert (n);
// test validity of initialized notification object
g_assert_cmpint (notification_get_id (n), ==, -1);
g_assert (!notification_get_title (n));
g_assert (!notification_get_body (n));
g_assert_cmpint (notification_get_value (n), ==, -2);
g_assert (!notification_get_icon_themename (n));
g_assert (!notification_get_icon_filename (n));
g_assert (!notification_get_icon_pixbuf (n));
g_assert_cmpint (notification_get_onscreen_time (n), ==, 0);
g_assert (!notification_get_sender_name (n));
g_assert_cmpint (notification_get_sender_pid (n), ==, 0);
timestamp = notification_get_timestamp (n);
g_assert_cmpint (timestamp->tv_sec, ==, 0);
g_assert_cmpint (timestamp->tv_usec, ==, 0);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NONE);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_destroy (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// test validity of main notification object
g_assert (n != NULL);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_id (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if nothing has been set yet it should return -1
g_assert_cmpint (notification_get_id (n), ==, -1);
// a negative id should not be stored
notification_set_id (n, -3);
g_assert_cmpint (notification_get_id (n), >=, -1);
// smallest possible id is 0
notification_set_id (n, 0);
g_assert_cmpint (notification_get_id (n), ==, 0);
// largest possible id is G_MAXINT
notification_set_id (n, G_MAXINT);
g_assert_cmpint (notification_get_id (n), ==, G_MAXINT);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_title (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no title has been set yet it should return NULL
g_assert (notification_get_title (n) == NULL);
// set an initial title-text and verify it
notification_set_title (n, "Some title text");
g_assert_cmpstr (notification_get_title (n), ==, "Some title text");
// set a new title-text and verify it
notification_set_title (n, "The new summary");
g_assert_cmpstr (notification_get_title (n), !=, "Some title text");
g_assert_cmpstr (notification_get_title (n), ==, "The new summary");
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_body (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no body has been set yet it should return NULL
g_assert (notification_get_body (n) == NULL);
// set an initial body-text and verify it
notification_set_body (n, "Example body text");
g_assert_cmpstr (notification_get_body (n), ==, "Example body text");
// set a new body-text and verify it
notification_set_body (n, "Some new body text");
g_assert_cmpstr (notification_get_body (n), !=, "Example body text");
g_assert_cmpstr (notification_get_body (n), ==, "Some new body text");
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_value (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no value has been set yet it should return 0
g_assert_cmpint (notification_get_value (n), ==, -2);
// set an initial value and verify it
notification_set_value (n, 25);
g_assert_cmpint (notification_get_value (n), ==, 25);
// set a new value and verify it
notification_set_value (n, 45);
g_assert_cmpint (notification_get_value (n), !=, 25);
g_assert_cmpint (notification_get_value (n), ==, 45);
// test allowed range
notification_set_value (n, NOTIFICATION_VALUE_MAX_ALLOWED + 1);
g_assert_cmpint (notification_get_value (n),
==,
NOTIFICATION_VALUE_MAX_ALLOWED);
notification_set_value (n, NOTIFICATION_VALUE_MIN_ALLOWED - 2);
g_assert_cmpint (notification_get_value (n),
==,
NOTIFICATION_VALUE_MIN_ALLOWED);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_icon_themename (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no icon-themename has been set yet it should return NULL
g_assert (notification_get_icon_themename (n) == NULL);
// set an initial icon-themename and verify it
notification_set_icon_themename (n, "notification-message-im");
g_assert_cmpstr (notification_get_icon_themename (n),
==,
"notification-message-im");
// set a new icon-themename and verify it
notification_set_icon_themename (n, "notification-device-usb");
g_assert_cmpstr (notification_get_icon_themename (n),
!=,
"notification-message-im");
g_assert_cmpstr (notification_get_icon_themename (n),
==,
"notification-device-usb");
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_icon_filename (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no icon-filename has been set yet it should return NULL
g_assert (notification_get_icon_filename (n) == NULL);
// set an initial icon-filename and verify it
notification_set_icon_filename (n, "/usr/share/icon/photo.png");
g_assert_cmpstr (notification_get_icon_filename (n),
==,
"/usr/share/icon/photo.png");
// set a new icon-filename and verify it
notification_set_icon_filename (n, "/tmp/drawing.svg");
g_assert_cmpstr (notification_get_icon_filename (n),
!=,
"/usr/share/icon/photo.png");
g_assert_cmpstr (notification_get_icon_filename (n),
==,
"/tmp/drawing.svg");
// passing an invalid/NULL pointer should not change the stored
// icon-filename
notification_set_icon_filename (n, NULL);
g_assert_cmpstr (notification_get_icon_filename (n),
==,
"/tmp/drawing.svg");
// pass an empty (but not NULL) strings
notification_set_icon_filename (n, "");
g_assert_cmpstr (notification_get_icon_filename (n),
==,
"");
notification_set_icon_filename (n, "\0");
g_assert_cmpstr (notification_get_icon_filename (n),
==,
"\0");
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_icon_pixbuf (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
GdkPixbuf* pixbuf = NULL;
// create new object
n = notification_new ();
// if no icon-pixbuf has been set yet it should return NULL
g_assert (notification_get_icon_pixbuf (n) == NULL);
// create pixbuf for testing
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 100, 100);
// set an initial icon-pixbuf and verify it
g_assert (pixbuf);
notification_set_icon_pixbuf (n, pixbuf);
g_assert (notification_get_icon_pixbuf (n) != NULL);
// passing an invalid/NULL pointer should not change the stored
// icon-pixbuf
notification_set_icon_pixbuf (n, NULL);
g_assert (notification_get_icon_pixbuf (n) != NULL);
// clean up
g_object_unref (n);
n = NULL;
// more clean up
g_object_unref (pixbuf);
pixbuf = NULL;
}
static void
test_notification_setget_onscreen_time (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no onscreen-time has been set yet it should return 0
g_assert_cmpint (notification_get_onscreen_time (n), ==, 0);
// setting a negative onscreen-time should fail
notification_set_onscreen_time (n, -1);
g_assert_cmpint (notification_get_onscreen_time (n), ==, 0);
// set an positive onscreen-time and verify it
notification_set_onscreen_time (n, 1000);
g_assert_cmpint (notification_get_onscreen_time (n), ==, 1000);
// set a new onscreen-time and verify it
notification_set_onscreen_time (n, 5000);
g_assert_cmpint (notification_get_onscreen_time (n), !=, 1000);
g_assert_cmpint (notification_get_onscreen_time (n), ==, 5000);
// setting a new onscreen-time smaller than the currently stored one
// should fail
notification_set_onscreen_time (n, 4000);
g_assert_cmpint (notification_get_onscreen_time (n), ==, 5000);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_sender_name (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no sender-name has been set yet it should return NULL
g_assert (notification_get_sender_name (n) == NULL);
// set an initial sender-name and verify it
notification_set_sender_name (n, "evolution");
g_assert_cmpstr (notification_get_sender_name (n), ==, "evolution");
// set a new sender-name and verify it
notification_set_sender_name (n, "pidgin");
g_assert_cmpstr (notification_get_sender_name (n), !=, "evolution");
g_assert_cmpstr (notification_get_sender_name (n), ==, "pidgin");
// passing an invalid/NULL pointer should not change the stored
// sender-name
notification_set_sender_name (n, NULL);
g_assert_cmpstr (notification_get_sender_name (n), ==, "pidgin");
// pass an empty (but not NULL) strings
notification_set_sender_name (n, "");
g_assert_cmpstr (notification_get_sender_name (n), ==, "");
notification_set_sender_name (n, "\0");
g_assert_cmpstr (notification_get_sender_name (n), ==, "\0");
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_sender_pid (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if nothing has been set yet it should return 0
g_assert_cmpint (notification_get_sender_pid (n), ==, 0);
// a negative pid makes no sense and should therefore not be stored
notification_set_sender_pid (n, -1);
g_assert_cmpint (notification_get_sender_pid (n), ==, 0);
// smallest possible pid is 1
notification_set_sender_pid (n, 1);
g_assert_cmpint (notification_get_sender_pid (n), ==, 1);
// largest possible id is G_MAXINT
notification_set_sender_pid (n, G_MAXINT);
g_assert_cmpint (notification_get_sender_pid (n), ==, G_MAXINT);
// a pid of 0 would mean something before the init process is sending us
// a notification, leave the stored pid untouched
notification_set_sender_pid (n, 0);
g_assert_cmpint (notification_get_sender_pid (n), ==, G_MAXINT);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_timestamp (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
GTimeVal* tvptr = NULL;
GTimeVal tv_old;
GTimeVal tv_new;
// create new object
n = notification_new ();
// if no reception-time has been set yet it should return 0/0
tvptr = notification_get_timestamp (n);
g_assert_cmpint (tvptr->tv_sec, ==, 0);
g_assert_cmpint (tvptr->tv_usec, ==, 0);
// ehm... well, get current time
g_get_current_time (&tv_old);
// store current time as reception-time and verify it
notification_set_timestamp (n, &tv_old);
tvptr = notification_get_timestamp (n);
g_assert_cmpint (tvptr->tv_sec, ==, tv_old.tv_sec);
g_assert_cmpint (tvptr->tv_usec, ==, tv_old.tv_usec);
// wait at least two seconds
sleep (2);
// get current time
g_get_current_time (&tv_new);
// trying to store an older timestamp over a newer one should fail
// second-granularity
notification_set_timestamp (n, &tv_new);
notification_set_timestamp (n, &tv_old);
tvptr = notification_get_timestamp (n);
g_assert_cmpint (tvptr->tv_sec, !=, tv_old.tv_sec);
g_assert_cmpint (tvptr->tv_sec, ==, tv_new.tv_sec);
// get current time
g_get_current_time (&tv_old);
notification_set_timestamp (n, &tv_old);
// wait some micro-seconds
usleep (10000);
// get current time
g_get_current_time (&tv_new);
// trying to store an older timestamp over a newer one should fail
// microsecond-granularity
notification_set_timestamp (n, &tv_new);
notification_set_timestamp (n, &tv_old);
tvptr = notification_get_timestamp (n);
g_assert_cmpint (tvptr->tv_usec, !=, tv_old.tv_usec);
g_assert_cmpint (tvptr->tv_usec, ==, tv_new.tv_usec);
// clean up
g_object_unref (n);
n = NULL;
}
static void
test_notification_setget_urgency (gpointer fixture, gconstpointer user_data)
{
Notification* n = NULL;
// create new object
n = notification_new ();
// if no urgency has been set yet it should return urgency-none
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NONE);
// test all three urgency-levels
notification_set_urgency (n, URGENCY_HIGH);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_HIGH);
notification_set_urgency (n, URGENCY_LOW);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_LOW);
notification_set_urgency (n, URGENCY_NORMAL);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NORMAL);
// test non-urgency levels, last valid urgency should be returned
notification_set_urgency (n, 5);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NORMAL);
notification_set_urgency (n, 23);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NORMAL);
notification_set_urgency (n, -2);
g_assert_cmpint (notification_get_urgency (n), ==, URGENCY_NORMAL);
// clean up
g_object_unref (n);
n = NULL;
}
GTestSuite *
test_notification_create_test_suite (void)
{
GTestSuite *ts = NULL;
GTestCase *tc = NULL;
ts = g_test_create_suite ("notification");
tc = g_test_create_case ("can create",
0,
NULL,
NULL,
test_notification_new,
NULL);
g_test_suite_add (ts, tc);
g_test_suite_add (
ts,
g_test_create_case (
"can destroy",
0,
NULL,
NULL,
test_notification_destroy,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get id",
0,
NULL,
NULL,
test_notification_setget_id,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get title",
0,
NULL,
NULL,
test_notification_setget_title,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get body",
0,
NULL,
NULL,
test_notification_setget_body,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get value",
0,
NULL,
NULL,
test_notification_setget_value,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get icon-themename",
0,
NULL,
NULL,
test_notification_setget_icon_themename,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get icon-filename",
0,
NULL,
NULL,
test_notification_setget_icon_filename,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get icon-pixbuf",
0,
NULL,
NULL,
test_notification_setget_icon_pixbuf,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get onscreen-time",
0,
NULL,
NULL,
test_notification_setget_onscreen_time,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get sender-name",
0,
NULL,
NULL,
test_notification_setget_sender_name,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get sender-pid",
0,
NULL,
NULL,
test_notification_setget_sender_pid,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get timestamp",
0,
NULL,
NULL,
test_notification_setget_timestamp,
NULL));
g_test_suite_add (
ts,
g_test_create_case (
"can set|get urgency",
0,
NULL,
NULL,
test_notification_setget_urgency,
NULL));
return ts;
}
./tests/test-tile.c 0000644 0000156 0000165 00000016135 12704153542 014326 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// tile-test.c - exercises the tile-API doing surface- and blur-caching
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include "tile.h"
#define WIDTH 270
#define HEIGHT 320
#define TILE_WIDTH 250
#define TILE_HEIGHT 100
#define BLUR_RADIUS 6
cairo_surface_t*
render_text_to_surface (gchar* text,
gint width,
gint height,
guint blur_radius)
{
cairo_surface_t* surface;
cairo_t* cr;
PangoFontDescription* desc;
PangoLayout* layout;
PangoRectangle ink_rect;
PangoRectangle log_rect;
const cairo_font_options_t* font_opts;
gdouble dpi;
// sanity check
if (!text ||
width <= 0 ||
height <= 0)
return NULL;
// create surface
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width,
height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
return NULL;
// create context
cr = cairo_create (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return NULL;
}
// clear context
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
// setup pango's layout and font-decription structures
layout = pango_cairo_create_layout (cr);
desc = pango_font_description_new ();
pango_font_description_set_size (desc, 15 * PANGO_SCALE);
pango_font_description_set_family_static (desc, "Candara");
pango_font_description_set_weight (desc, PANGO_WEIGHT_NORMAL);
pango_font_description_set_style (desc, PANGO_STYLE_NORMAL);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_width (layout,
(width - 2 * blur_radius) * PANGO_SCALE);
pango_layout_set_height (layout,
(height - 2 * blur_radius) * PANGO_SCALE);
pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
// get font-options and screen-DPI
font_opts = gdk_screen_get_font_options (gdk_screen_get_default ());
dpi = gdk_screen_get_resolution (gdk_screen_get_default ());
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (pango_layout_get_context (layout),
font_opts);
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
dpi);
pango_layout_context_changed (layout);
// print and layout string (pango-wise)
pango_layout_set_text (layout, text, -1);
pango_layout_get_extents (layout, &ink_rect, &log_rect);
cairo_move_to (cr, (gdouble) blur_radius, (gdouble) blur_radius);
// draw pango-text as path to our cairo-context
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f);
pango_cairo_show_layout (cr, layout);
// clean up
g_object_unref (layout);
cairo_destroy (cr);
return surface;
}
gboolean
on_expose (GtkWidget* widget,
GdkEventExpose* event,
gpointer data)
{
tile_t* tile = (tile_t*) data;
cairo_pattern_t* pattern = NULL;
cairo_t* cr = NULL;
// create and setup result-surface and context
cr = gdk_cairo_create (gtk_widget_get_window (widget));
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
g_debug ("Could not create context for rendering to window!");
return FALSE;
}
// use the tile for drawing onto result-surface
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 0.75f, 0.75f, 0.75f, 1.0f);
cairo_paint (cr);
// colored drop-shadow trick
cairo_push_group (cr);
tile_paint (tile, cr, 10.0f, 10.0f, 0.0f, 1.0f);
pattern = cairo_pop_group (cr);
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 0.75f);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
// draw the normal tile-state over drop-shadow, but slightly offset-ed
tile_paint (tile, cr, 8.5f, 8.5f, 1.0f, 0.0f);
// just draw the normal tile-state
tile_paint (tile, cr, 10.0f, 110.0f, 1.0f, 0.0f);
// just draw the blurred tile-state
tile_paint (tile, cr, 10.0f, 210.0f, 0.0f, 1.0f);
// clean up
cairo_destroy (cr);
return FALSE;
}
gboolean
on_delete (GtkWidget* widget,
GdkEvent* event,
gpointer data)
{
gtk_main_quit ();
return FALSE;
}
int
main (int argc,
char** argv)
{
GtkWidget* window = NULL;
cairo_surface_t* tile_surface = NULL;
cairo_t* cr = NULL;
tile_t* tile = NULL;
// needed because we want to make use of the system-wide font-settings
gtk_init (&argc, &argv);
// create main window
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
if (!window)
{
g_debug ("Could not create window!");
return 1;
}
// create and setup image-surface and context
tile_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
TILE_WIDTH,
TILE_HEIGHT);
if (cairo_surface_status (tile_surface) != CAIRO_STATUS_SUCCESS)
{
g_debug ("Could not create tile-surface!");
return 2;
}
cr = cairo_create (tile_surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tile_surface);
g_debug ("Could not create context for tile-surface!");
return 3;
}
// draw something onto the tile-surface
tile_surface = render_text_to_surface (
"Polyfon zwitschernd aßen Mäxchens"
" Vögel Rüben, Joghurt und Quark.\0",
TILE_WIDTH,
TILE_HEIGHT,
BLUR_RADIUS);
// create and setup tile from that with a blur-radius of 6px
tile = tile_new (tile_surface, BLUR_RADIUS);
cairo_surface_destroy (tile_surface);
cairo_destroy (cr);
// setup window
gtk_widget_set_size_request (window, WIDTH, HEIGHT);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_widget_set_app_paintable (window, TRUE);
gtk_widget_show_all (window);
g_signal_connect (G_OBJECT (window),
"expose-event",
G_CALLBACK (on_expose),
tile);
g_signal_connect (G_OBJECT (window),
"delete-event",
G_CALLBACK (on_delete),
NULL);
// enter event-loop
gtk_main ();
// clean up
tile_destroy (tile);
return 0;
}
./tests/test-apport.c 0000644 0000156 0000165 00000003020 12704153542 014663 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-apport.c - implements unit-tests for apport hooks
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "apport.h"
static
void
test_apport ()
{
if (g_test_thorough ()) {
g_assert (0 == 1); // ie, fail...
}
}
GTestSuite *
test_apport_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("apport");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_apport));
return ts;
}
./tests/test-modules-main.c 0000644 0000156 0000165 00000006020 12704153542 015753 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-modules-main.c - pulling together all the unit-tests
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
/* Declare entries located in the individual test modules
(avoids a superflous .h file)
*/
GTestSuite *test_bubble_create_test_suite (void);
GTestSuite *test_defaults_create_test_suite (void);
GTestSuite *test_notification_create_test_suite (void);
GTestSuite *test_observer_create_test_suite (void);
GTestSuite *test_stack_create_test_suite (void);
GTestSuite *test_dbus_create_test_suite (void);
GTestSuite *test_apport_create_test_suite (void);
GTestSuite *test_i18n_create_test_suite (void);
GTestSuite *test_withlib_create_test_suite (void);
GTestSuite *test_synchronous_create_test_suite (void);
GTestSuite *test_dnd_create_test_suite (void);
GTestSuite *test_filtering_create_test_suite (void);
GTestSuite *test_timings_create_test_suite (void);
int
main (int argc,
char** argv)
{
gint result;
g_test_init (&argc, &argv, NULL);
gtk_init (&argc, &argv);
GTestSuite *suite = NULL;
suite = g_test_get_root ();
g_test_suite_add_suite (suite, test_bubble_create_test_suite ());
g_test_suite_add_suite (suite, test_defaults_create_test_suite ());
g_test_suite_add_suite (suite, test_notification_create_test_suite ());
g_test_suite_add_suite (suite, test_observer_create_test_suite ());
g_test_suite_add_suite (suite, test_stack_create_test_suite ());
g_test_suite_add_suite (suite, test_filtering_create_test_suite ());
g_test_suite_add_suite (suite, test_dbus_create_test_suite ());
g_test_suite_add_suite (suite, test_apport_create_test_suite ());
g_test_suite_add_suite (suite, test_i18n_create_test_suite ());
g_test_suite_add_suite (suite, test_withlib_create_test_suite ());
g_test_suite_add_suite (suite, test_synchronous_create_test_suite ());
g_test_suite_add_suite (suite, test_dnd_create_test_suite ());
g_test_suite_add_suite (suite, test_timings_create_test_suite ());
result = g_test_run ();
return result;
}
./tests/test-alpha-animation.c 0000644 0000156 0000165 00000004073 12704153542 016431 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-alpha-animation.c - implements unit-tests for egg/clutter alphas
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#include
static void
fade_cb (EggTimeline *timeline,
gint frame_no,
EggAlpha *alpha)
{
g_debug ("new frame %d, alpha=%d",
frame_no,
egg_alpha_get_alpha (alpha));
}
static void
completed_cb (EggTimeline *timeline,
gpointer *state)
{
g_debug ("completed");
exit (EXIT_SUCCESS);
}
int
main (int argc, char **argv)
{
EggTimeline *timeline;
EggAlpha *alpha;
timeline = egg_timeline_new_for_duration (700);
alpha = egg_alpha_new_full (timeline,
EGG_ALPHA_SINE_DEC,
NULL,
NULL);
g_signal_connect (G_OBJECT(timeline),
"completed",
G_CALLBACK(completed_cb),
NULL);
g_signal_connect (G_OBJECT(timeline),
"new-frame",
G_CALLBACK(fade_cb),
alpha);
egg_timeline_start (timeline);
egg_main ();
return EXIT_FAILURE;
}
./tests/tests.suppression 0000644 0000156 0000165 00000012300 12704153542 015714 0 ustar jenkins jenkins #
# Valgrind suppression file for Gtk+ 2.12
#
# Format specification:
# http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress
#
#
# glibc Ubuntu Edgy
#
{
libc: getpwnam_r
Memcheck:Addr4
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libc-*.so
obj:/lib/ld-*.so
fun:__libc_dlopen_mode
fun:__nss_lookup_function
obj:/lib/tls/i686/cmov/libc-*.so
fun:__nss_passwd_lookup
fun:getpwnam_r
fun:g_get_any_init_do
fun:g_get_home_dir
fun:gtk_rc_add_initial_default_files
fun:_gtk_rc_init
fun:post_parse_hook
fun:g_option_context_parse
fun:gtk_parse_args
fun:gtk_init_check
fun:gtk_init
}
{
libc: getpwnam_r
Memcheck:Addr4
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libc-*.so
obj:/lib/ld-*.so
fun:__libc_dlopen_mode
fun:__nss_lookup_function
obj:/lib/tls/i686/cmov/libc-*.so
fun:__nss_passwd_lookup
fun:getpwnam_r
fun:g_get_any_init_do
fun:g_get_home_dir
fun:gtk_rc_add_initial_default_files
fun:_gtk_rc_init
fun:post_parse_hook
fun:g_option_context_parse
fun:gtk_parse_args
fun:gtk_init_check
fun:gtk_init
}
{
libc: getpwnam_r
Memcheck:Addr4
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libc-*.so
obj:/lib/ld-*.so
fun:__libc_dlopen_mode
fun:__nss_lookup_function
fun:__nss_next
fun:getpwnam_r
fun:g_get_any_init_do
fun:g_get_home_dir
fun:gtk_rc_add_initial_default_files
fun:_gtk_rc_init
fun:post_parse_hook
fun:g_option_context_parse
fun:gtk_parse_args
fun:gtk_init_check
fun:gtk_init
}
{
libc: getpwnam_r
Memcheck:Addr4
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libc-*.so
obj:/lib/ld-*.so
fun:__libc_dlopen_mode
fun:__nss_lookup_function
fun:__nss_next
fun:getpwnam_r
fun:g_get_any_init_do
fun:g_get_home_dir
fun:gtk_rc_add_initial_default_files
fun:_gtk_rc_init
fun:post_parse_hook
fun:g_option_context_parse
fun:gtk_parse_args
fun:gtk_init_check
fun:gtk_init
}
#
# glibc Ubuntu feisty
#
{
getpwnam_r
Memcheck:Leak
fun:malloc
obj:/lib/libc-2.5.so
fun:__nss_database_lookup
obj:*
obj:*
fun:getpwnam_r
}
#
# X
#
{
XSupportsLocale
Memcheck:Addr4
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libdl-*.so
obj:/lib/ld-*.so
obj:/lib/tls/i686/cmov/libdl-*.so
fun:dlopen
obj:/usr/lib/libX11.so.6.2.0
fun:_XlcDynamicLoad
fun:_XOpenLC
fun:_XlcCurrentLC
fun:XSupportsLocale
fun:_gdk_x11_initialize_locale
fun:_gdk_windowing_init
fun:gdk_pre_parse_libgtk_only
fun:pre_parse_hook
fun:g_option_context_parse
fun:gtk_parse_args
fun:gtk_init_check
fun:gtk_init
fun:main
}
{
Xcursor
Memcheck:Leak
fun:malloc
obj:/usr/lib/libXcursor.so.1.0.2
obj:/usr/lib/libXcursor.so.1.0.2
fun:XcursorXcFileLoadImages
fun:XcursorFileLoadImages
fun:XcursorLibraryLoadImages
fun:XcursorShapeLoadImages
fun:XcursorTryShapeCursor
fun:XCreateGlyphCursor
fun:XCreateFontCursor
fun:gdk_cursor_new_for_display
}
{
XcursorGetTheme
Memcheck:Leak
fun:malloc
fun:/usr/lib/libX11.so.6.2.0
fun:/usr/lib/libX11.so.6.2.0
fun:XrmGetStringDatabase
fun:XGetDefault
fun:_XcursorGetDisplayInfo
fun:XcursorGetTheme
}
{
XOpenDisplay
Memcheck:Leak
fun:calloc
fun:XOpenDisplay
}
{
XOpenDisplay
Memcheck:Leak
fun:malloc
fun:XOpenDisplay
}
#
# fontconfig
#
{
fontconfig
Memcheck:Leak
fun:realloc
fun:FcPatternObjectInsertElt
fun:FcPatternObjectAddWithBinding
}
{
pango_fc_font_map_load_fontset
Memcheck:Leak
fun:malloc
fun:FcLangSetCreate
fun:FcLangSetCopy
fun:FcValueSave
fun:FcPatternObjectAddWithBinding
fun:FcPatternObjectAdd
fun:FcFontRenderPrepare
fun:pango_fc_font_map_load_fontset
fun:pango_font_map_load_fontset
}
{
pango_font_map_load_fontset
Memcheck:Leak
fun:malloc
fun:FcPatternObjectAddWithBinding
fun:FcPatternObjectAdd
fun:FcFontRenderPrepare
fun:pango_fc_font_map_load_fontset
fun:pango_font_map_load_fontset
}
{
pango_fc_font_map_load_fontset
Memcheck:Leak
fun:malloc
fun:FcStrStaticName
fun:FcPatternObjectAddWithBinding
fun:FcPatternObjectAdd
fun:FcFontRenderPrepare
fun:pango_fc_font_map_load_fontset
}
{
pango_fc_font_map_list_families
Memcheck:Leak
fun:malloc
fun:FcStrStaticName
fun:FcPatternObjectAddWithBinding
fun:FcPatternAdd
fun:FcFontSetList
fun:FcFontList
fun:pango_fc_font_map_list_families
}
#
# freetype
#
{
freetype FT_Init_FreeType
Memcheck:Leak
fun:malloc
obj:/usr/lib/libfreetype.so.6.3.10
fun:ft_mem_qalloc
fun:ft_mem_alloc
fun:FT_New_Library
fun:FT_Init_FreeType
}
#
# glib
#
{
glib g_rand_new
Memcheck:Leak
fun:calloc
fun:g_malloc0
fun:g_rand_new_with_seed_array
fun:g_rand_new
fun:g_random_int
}
./tests/test-timings.c 0000644 0000156 0000165 00000032216 12704153542 015041 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// test-timings.c - implements unit-tests for exercising API of timings object
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// to see timings working in a more obvious way start it with DEBUG=1 set in
// the environment (example: "DEBUG=1 ./test-modules -p /timings")
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include "timings.h"
gboolean
_stop_main_loop (GMainLoop *loop)
{
g_main_loop_quit (loop);
return FALSE;
}
gboolean
_trigger_pause (gpointer data)
{
Timings* t;
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_pause (t);
return FALSE;
}
gboolean
_trigger_continue (gpointer data)
{
Timings* t;
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_continue (t);
return FALSE;
}
gboolean
_trigger_start (gpointer data)
{
Timings* t;
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_start (t);
return FALSE;
}
gboolean
_trigger_stop (gpointer data)
{
Timings* t;
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_stop (t);
return FALSE;
}
void
_on_completed (gpointer data)
{
Timings* t;
g_print ("\n_on_completed() called\n");
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_stop (t);
}
void
_on_limit_reached (gpointer data)
{
Timings* t;
g_print ("\n_on_limit_reached() called\n");
g_assert (data);
t = TIMINGS (data);
g_assert (t);
timings_stop (t);
}
static void
test_timings_new (gpointer fixture, gconstpointer user_data)
{
Timings* t;
guint initial_duration = 1000;
guint max_time_limit = 3000;
// create new timings-object
t = timings_new (initial_duration, max_time_limit);
// test validity of main timings-object
g_assert (t);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_start (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new timings-object
t = timings_new (initial_duration, max_time_limit);
// test validity of timings-object
g_assert (t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_extend (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of main notification object
g_assert (t);
// try to extend without being started
g_assert (timings_extend (t, extension) == FALSE);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// try to extend by 1000 ms after being started
g_assert (timings_extend (t, extension));
// try to extend by 0 ms
g_assert (timings_extend (t, 0) == FALSE);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_pause (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of timings-object
g_assert (t);
// trigger pause after 500 ms, this will run into _on_limit_reached()
g_timeout_add (500,
(GSourceFunc) _trigger_pause,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_continue (gpointer fixture, gconstpointer user_data)
{
Timings* t = NULL;
GMainLoop* loop = NULL;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (initial_duration + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of timings-object
g_assert (t != NULL);
// trigger pause after 500 ms
g_timeout_add (500,
(GSourceFunc) _trigger_pause,
(gpointer) t);
// trigger continue after 750 ms, should still end with _on_completed()
g_timeout_add (750,
(GSourceFunc) _trigger_continue,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_intercept_pause (gpointer fixture, gconstpointer user_data)
{
Timings* t = NULL;
GMainLoop* loop = NULL;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of timings-object
g_assert (t);
// trigger 1st pause after 500 ms
g_timeout_add (500,
(GSourceFunc) _trigger_pause,
(gpointer) t);
// trigger 2nd pause after 750 ms
g_timeout_add (750,
(GSourceFunc) _trigger_pause,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_intercept_continue (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of main notification object
g_assert (t);
// trigger pause after 250 ms
g_timeout_add (250,
(GSourceFunc) _trigger_pause,
(gpointer) t);
// trigger 1st continue after 500 ms
g_timeout_add (500,
(GSourceFunc) _trigger_continue,
(gpointer) t);
// trigger 2nd continue after 750 ms
g_timeout_add (750,
(GSourceFunc) _trigger_continue,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_intercept_start (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of main notification object
g_assert (t);
// trigger start after 750 ms
g_timeout_add (750,
(GSourceFunc) _trigger_start,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
static void
test_timings_intercept_stop (gpointer fixture, gconstpointer user_data)
{
Timings* t;
GMainLoop* loop;
guint initial_duration = 1000;
guint extension = 1000;
guint max_time_limit = 3000;
// setup the main loop
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (max_time_limit + extension,
(GSourceFunc) _stop_main_loop,
loop);
// create new object
t = timings_new (initial_duration, max_time_limit);
// test validity of main notification object
g_assert (t);
// trigger stop after initial_duration+extension ms
g_timeout_add (initial_duration + extension,
(GSourceFunc) _trigger_stop,
(gpointer) t);
// hook up to "completed" signal
g_signal_connect (t,
"completed",
G_CALLBACK (_on_completed),
(gpointer) t);
// hook up to "limit-reached" signal
g_signal_connect (t,
"limit-reached",
G_CALLBACK (_on_limit_reached),
(gpointer) t);
// start the thing
timings_start (t);
// let the main loop run
g_main_loop_run (loop);
// clean up
g_object_unref (t);
t = NULL;
}
GTestSuite*
test_timings_create_test_suite (void)
{
GTestSuite* ts = NULL;
ts = g_test_create_suite ("timings");
g_test_suite_add (ts,
g_test_create_case ("can create",
0,
NULL,
NULL,
test_timings_new,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can start",
0,
NULL,
NULL,
test_timings_start,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can extend",
0,
NULL,
NULL,
test_timings_extend,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can pause",
0,
NULL,
NULL,
test_timings_pause,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can continue",
0,
NULL,
NULL,
test_timings_continue,
NULL));
g_test_suite_add (ts,
g_test_create_case ("can intercept pause if paused",
0,
NULL,
NULL,
test_timings_intercept_pause,
NULL));
g_test_suite_add (ts,
g_test_create_case (
"can intercept continue if running",
0,
NULL,
NULL,
test_timings_intercept_continue,
NULL));
g_test_suite_add (ts,
g_test_create_case (
"can intercept start if started",
0,
NULL,
NULL,
test_timings_intercept_start,
NULL));
g_test_suite_add (ts,
g_test_create_case (
"can intercept stop if stopped",
0,
NULL,
NULL,
test_timings_intercept_stop,
NULL));
return ts;
}
./tests/test-grow-bubble.c 0000644 0000156 0000165 00000046213 12704153542 015600 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// test-grow-bubble
//
// test-grow-bubble.c - test using tile to animate growing bubble
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include "raico-blur.h"
#include "tile.h"
#include "util.h"
#define BUBBLE_SHADOW_SIZE 10.0f
#define CORNER_RADIUS 6.0f
#define BUBBLE_WIDTH 320.0f
#define BUBBLE_HEIGHT 125.0f
#define BUBBLE_BG_COLOR_R 0.2f
#define BUBBLE_BG_COLOR_G 0.2f
#define BUBBLE_BG_COLOR_B 0.2f
#define POS_X 0
#define POS_Y 30
gboolean g_composited = FALSE;
gboolean g_mouse_over = FALSE;
tile_t* g_tile = NULL;
gfloat g_distance = 1.0f;
gfloat g_step = 5.0f;
void
draw_round_rect (cairo_t* cr,
gdouble aspect, /* aspect-ratio */
gdouble x, /* top-left corner */
gdouble y, /* top-left corner */
gdouble corner_radius, /* "size" of the corners */
gdouble width, /* width of the rectangle */
gdouble height /* height of the rectangle */)
{
gdouble radius = corner_radius / aspect;
/* top-left, right of the corner */
cairo_move_to (cr, x + radius, y);
/* top-right, left of the corner */
cairo_line_to (cr,
x + width - radius,
y);
/* top-right, below the corner */
cairo_arc (cr,
x + width - radius,
y + radius,
radius,
-90.0f * G_PI / 180.0f,
0.0f * G_PI / 180.0f);
/* bottom-right, above the corner */
cairo_line_to (cr,
x + width,
y + height - radius);
/* bottom-right, left of the corner */
cairo_arc (cr,
x + width - radius,
y + height - radius,
radius,
0.0f * G_PI / 180.0f,
90.0f * G_PI / 180.0f);
/* bottom-left, right of the corner */
cairo_line_to (cr,
x + radius,
y + height);
/* bottom-left, above the corner */
cairo_arc (cr,
x + radius,
y + height - radius,
radius,
90.0f * G_PI / 180.0f,
180.0f * G_PI / 180.0f);
/* top-left, below the corner */
cairo_line_to (cr,
x,
y + radius);
/* top-left, right of the corner */
cairo_arc (cr,
x + radius,
y + radius,
radius,
180.0f * G_PI / 180.0f,
270.0f * G_PI / 180.0f);
}
void
screen_changed_handler (GtkWidget* window,
GdkScreen* old_screen,
gpointer data)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (window));
GdkVisual* visual = gdk_screen_get_rgba_visual (screen);
if (!visual)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (GTK_WIDGET (window), visual);
}
static
void
update_input_shape (GtkWidget* window,
gint width,
gint height)
{
cairo_region_t* region = NULL;
const cairo_rectangle_int_t rect = {0, 0, 1, 1};
region = cairo_region_create_rectangle (&rect);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_input_shape_combine_region (window, NULL);
gtk_widget_input_shape_combine_region (window, region);
}
}
static void
update_shape (GtkWidget* window,
gint radius,
gint shadow_size)
{
if (g_composited)
{
/* remove any current shape-mask */
gtk_widget_input_shape_combine_region (window, NULL);
return;
}
int width;
int height;
gtk_widget_get_size_request (window, &width, &height);
const cairo_rectangle_int_t rects[] = {{2, 0, width - 4, height},
{1, 1, width - 2, height - 2},
{0, 2, width, height - 4}};
cairo_region_t* region = NULL;
region = cairo_region_create_rectangles (rects, 3);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_shape_combine_region (window, NULL);
gtk_widget_shape_combine_region (window, region);
}
}
void
composited_changed_handler (GtkWidget* window,
gpointer data)
{
g_composited = gdk_screen_is_composited(gtk_widget_get_screen (window));
update_shape (window,
(gint) CORNER_RADIUS,
(gint) BUBBLE_SHADOW_SIZE);
}
void
draw_shadow (cairo_t* cr,
gdouble width,
gdouble height,
gint shadow_radius,
gint corner_radius)
{
cairo_surface_t* tmp_surface = NULL;
cairo_surface_t* new_surface = NULL;
cairo_pattern_t* pattern = NULL;
cairo_t* cr_surf = NULL;
cairo_matrix_t matrix;
raico_blur_t* blur = NULL;
tmp_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
4 * shadow_radius,
4 * shadow_radius);
if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS)
return;
cr_surf = cairo_create (tmp_surface);
if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
return;
}
cairo_scale (cr_surf, 1.0f, 1.0f);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr_surf);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 0.75f);
cairo_arc (cr_surf,
2 * shadow_radius,
2 * shadow_radius,
2.0f * corner_radius,
0.0f,
360.0f * (G_PI / 180.f));
cairo_fill (cr_surf);
cairo_destroy (cr_surf);
// create and setup blur
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, shadow_radius);
// now blur it
raico_blur_apply (blur, tmp_surface);
// blur no longer needed
raico_blur_destroy (blur);
new_surface = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (tmp_surface),
cairo_image_surface_get_format (tmp_surface),
cairo_image_surface_get_width (tmp_surface) / 2,
cairo_image_surface_get_height (tmp_surface) / 2,
cairo_image_surface_get_stride (tmp_surface));
pattern = cairo_pattern_create_for_surface (new_surface);
if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
return;
}
// top left
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_set_source (cr, pattern);
cairo_rectangle (cr,
0.0f,
0.0f,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// bottom left
cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
cairo_matrix_translate (&matrix, 0.0f, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
0.0f,
2 * shadow_radius,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// top right
cairo_matrix_init_scale (&matrix, -1.0f, 1.0f);
cairo_matrix_translate (&matrix, -width, 0.0f);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
width - 2 * shadow_radius,
0.0f,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// bottom right
cairo_matrix_init_scale (&matrix, -1.0f, -1.0f);
cairo_matrix_translate (&matrix, -width, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
2 * shadow_radius,
height - 2 * shadow_radius,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// clean up
cairo_pattern_destroy (pattern);
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
}
gboolean
expose_handler (GtkWidget* window,
cairo_t* cr,
gpointer data)
{
GtkAllocation a;
gtk_widget_get_allocation (window, &a);
/* clear and render drop-shadow and bubble-background */
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (g_distance < 1.0f)
{
tile_paint_with_padding (g_tile,
cr,
0.0f,
0.0f,
a.width,
a.height,
g_distance,
1.0f - g_distance);
gtk_widget_set_opacity (window, 0.3f + g_distance * 0.7f);
}
else
{
tile_paint_with_padding (g_tile,
cr,
0.0f,
0.0f,
a.width,
a.height,
g_distance,
0.0f);
gtk_widget_set_opacity (window, 1.0f);
}
return TRUE;
}
void
set_bg_blur (GtkWidget* window,
gboolean blur)
{
GtkAllocation a;
GdkWindow *gdkwindow;
gint shadow = BUBBLE_SHADOW_SIZE;
if (!window)
return;
gtk_widget_get_allocation (window, &a);
gdkwindow = gtk_widget_get_window (window);
if (blur)
{
glong data[] = {
2, /* threshold */
0, /* filter */
NorthWestGravity, /* gravity of top-left */
shadow, /* x-coord of top-left */
-a.height/2 + shadow,/* y-coord of top-left */
NorthWestGravity, /* gravity of bottom-right */
a.width - shadow, /* bottom-right x-coord */
a.height/2 - shadow /* bottom-right y-coord */};
XChangeProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom(GDK_WINDOW_XDISPLAY(gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE),
XA_INTEGER,
32,
PropModeReplace,
(guchar *) data,
8);
}
else
{
XDeleteProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom(GDK_WINDOW_XDISPLAY(gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE));
}
}
gboolean
quit (gpointer data)
{
gtk_main_quit ();
return FALSE;
}
gboolean grow (GtkWidget* window);
gboolean
shrink (GtkWidget* window)
{
gint width = 0;
gint height = 0;
if (!GTK_IS_WINDOW (window))
return TRUE;
gtk_widget_get_size_request (window, &width, &height);
if (g_step <= 2.0f)
{
g_step = 5.0f;
g_timeout_add (1000/40,
(GSourceFunc) grow,
(gpointer) window);
return FALSE;
}
height -= (gint) g_step;
g_step /= 1.125f;
gtk_widget_set_size_request (window, width, height);
gtk_widget_queue_draw (window);
return TRUE;
}
gboolean
grow (GtkWidget* window)
{
gint width = 0;
gint height = 0;
if (!GTK_IS_WINDOW (window))
return TRUE;
gtk_widget_get_size_request (window, &width, &height);
if (g_step <= 2.0f)
{
g_step = 5.0f;
g_timeout_add (1000/40,
(GSourceFunc) shrink,
(gpointer) window);
return FALSE;
}
height += (gint) g_step;
g_step /= 1.125f;
gtk_widget_set_size_request (window, width, height);
gtk_widget_queue_draw (window);
return TRUE;
}
gboolean
pointer_update (GtkWidget* window)
{
gint pointer_rel_x;
gint pointer_rel_y;
gint pointer_abs_x;
gint pointer_abs_y;
gint win_x;
gint win_y;
gint width;
gint height;
gboolean old_mouse_over;
gfloat old_distance = 0;
if (!GTK_IS_WINDOW (window))
return FALSE;
old_mouse_over = g_mouse_over;
if (gtk_widget_get_realized (window))
{
GdkDeviceManager *device_manager;
GdkDevice *device;
gint distance_x;
gint distance_y;
device_manager = gdk_display_get_device_manager (gtk_widget_get_display (window));
device = gdk_device_manager_get_client_pointer (device_manager);
gdk_window_get_device_position (gtk_widget_get_window (window),
device,
&pointer_rel_x,
&pointer_rel_y,
NULL);
gtk_window_get_position (GTK_WINDOW (window), &win_x, &win_y);
pointer_abs_x = win_x + pointer_rel_x;
pointer_abs_y = win_y + pointer_rel_y;
gtk_window_get_size (GTK_WINDOW (window), &width, &height);
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width &&
pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
g_mouse_over = TRUE;
else
g_mouse_over = FALSE;
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width)
distance_x = 0;
else
{
if (pointer_abs_x < win_x)
distance_x = abs (pointer_rel_x);
if (pointer_abs_x > win_x + width)
distance_x = abs (pointer_rel_x - width);
}
if (pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
distance_y = 0;
else
{
if (pointer_abs_y < win_y)
distance_y = abs (pointer_rel_y);
if (pointer_abs_y > win_y + height)
distance_y = abs (pointer_rel_y - height);
}
old_distance = g_distance;
g_distance = sqrt (distance_x * distance_x +
distance_y * distance_y) /
(double) 40;
}
if (old_mouse_over != g_mouse_over)
set_bg_blur (window, !g_mouse_over);
if (old_distance != g_distance)
gtk_widget_queue_draw (window);
return TRUE;
}
void
setup_tile (gint w, gint h)
{
cairo_status_t status;
cairo_t* cr = NULL;
cairo_surface_t* cr_surf = NULL;
cairo_surface_t* tmp = NULL;
cairo_surface_t* dummy_surf = NULL;
cairo_surface_t* norm_surf = NULL;
cairo_surface_t* blur_surf = NULL;
gdouble width = (gdouble) w;
gdouble height = (gdouble) h;
raico_blur_t* blur = NULL;
cr_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3 * BUBBLE_SHADOW_SIZE,
3 * BUBBLE_SHADOW_SIZE);
status = cairo_surface_status (cr_surf);
if (status != CAIRO_STATUS_SUCCESS)
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
cr = cairo_create (cr_surf);
status = cairo_status (cr);
if (status != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (cr_surf);
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
}
// clear and render drop-shadow and bubble-background
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (g_composited)
{
draw_shadow (cr,
width,
height,
BUBBLE_SHADOW_SIZE,
CORNER_RADIUS);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
draw_round_rect (cr,
1.0f,
(gdouble) BUBBLE_SHADOW_SIZE,
(gdouble) BUBBLE_SHADOW_SIZE,
(gdouble) CORNER_RADIUS,
(gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE),
(gdouble) (height - 2.0f* BUBBLE_SHADOW_SIZE));
cairo_fill (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr,
BUBBLE_BG_COLOR_R,
BUBBLE_BG_COLOR_G,
BUBBLE_BG_COLOR_B,
0.95f);
}
else
cairo_set_source_rgb (cr,
BUBBLE_BG_COLOR_R,
BUBBLE_BG_COLOR_G,
BUBBLE_BG_COLOR_B);
draw_round_rect (cr,
1.0f,
BUBBLE_SHADOW_SIZE,
BUBBLE_SHADOW_SIZE,
CORNER_RADIUS,
(gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE),
(gdouble) (height - 2.0f * BUBBLE_SHADOW_SIZE));
cairo_fill (cr);
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (cr_surf),
cairo_image_surface_get_format (cr_surf),
3 * BUBBLE_SHADOW_SIZE,
3 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (cr_surf));
dummy_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (dummy_surf),
cairo_image_surface_get_format (dummy_surf),
2 * BUBBLE_SHADOW_SIZE,
2 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (dummy_surf));
norm_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, 6);
raico_blur_apply (blur, dummy_surf);
raico_blur_destroy (blur);
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (dummy_surf),
cairo_image_surface_get_format (dummy_surf),
2 * BUBBLE_SHADOW_SIZE,
2 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (dummy_surf));
blur_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
cairo_surface_destroy (dummy_surf);
g_tile = tile_new_for_padding (norm_surf, blur_surf, width, height);
cairo_surface_destroy (norm_surf);
cairo_surface_destroy (blur_surf);
cairo_surface_destroy (cr_surf);
cairo_destroy (cr);
}
int
main (int argc,
char** argv)
{
GtkWidget* window;
GdkRGBA transparent = {0.0, 0.0, 0.0, 0.0};
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
if (!window)
return 0;
gtk_window_set_type_hint (GTK_WINDOW (window),
GDK_WINDOW_TYPE_HINT_DOCK);
gtk_widget_add_events (window,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
// hook up input/event handlers to window
g_signal_connect (G_OBJECT (window),
"screen-changed",
G_CALLBACK (screen_changed_handler),
NULL);
g_signal_connect (G_OBJECT (window),
"composited-changed",
G_CALLBACK (composited_changed_handler),
NULL);
gtk_window_move (GTK_WINDOW (window), POS_X, POS_Y);
// make sure the window opens with a RGBA-visual
screen_changed_handler (window, NULL, NULL);
gtk_widget_realize (window);
gdk_window_set_background_rgba (gtk_widget_get_window (window),
&transparent);
// hook up window-event handlers to window
g_signal_connect (G_OBJECT (window),
"draw",
G_CALLBACK (expose_handler),
NULL);
// FIXME: read out current mouse-pointer position every 1/25 second
g_timeout_add (1000/40,
(GSourceFunc) pointer_update,
(gpointer) window);
g_timeout_add (10000,
(GSourceFunc) quit,
NULL);
g_timeout_add (1000/40,
(GSourceFunc) grow,
(gpointer) window);
// "clear" input-mask, set title/icon/attributes
gtk_widget_set_app_paintable (window, TRUE);
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_accept_focus (GTK_WINDOW (window), FALSE);
gtk_widget_set_opacity (window, 1.0f);
gtk_widget_set_size_request (window,
(gint) (BUBBLE_WIDTH + 2.0f *
BUBBLE_SHADOW_SIZE),
(gint) (BUBBLE_HEIGHT + 2.0f *
BUBBLE_SHADOW_SIZE));
gtk_widget_show (window);
g_composited = gdk_screen_is_composited(gtk_widget_get_screen (window));
update_input_shape (window, 1, 1);
update_shape (window,
(gint) CORNER_RADIUS,
(gint) BUBBLE_SHADOW_SIZE);
set_bg_blur (window, TRUE);
setup_tile ((gint) (BUBBLE_WIDTH + 2.0f * BUBBLE_SHADOW_SIZE),
(gint) (BUBBLE_HEIGHT + 2.0f * BUBBLE_SHADOW_SIZE));
g_print ("This test will run for 10 seconds and then quit.\n");
gtk_main ();
tile_destroy (g_tile);
return 0;
}
./tests/test-dbus.c 0000644 0000156 0000165 00000007066 12704153542 014331 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-dbus.c - implements unit-tests for dbus glue-code
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "dbus.h"
#include "stack.h"
#define TEST_DBUS_NAME "org.freedesktop.Notificationstest"
static
void
test_dbus_instance (gpointer fixture, gconstpointer user_data)
{
DBusGConnection* connection = NULL;
connection = dbus_create_service_instance (TEST_DBUS_NAME);
g_assert (connection != NULL);
}
static
void
test_dbus_collision (gpointer fixture, gconstpointer user_data)
{
//DBusGConnection* connection = NULL;
/* HACK: as we did not destroy the instance after the first test above,
this second creation should fail */
if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT |
G_TEST_TRAP_SILENCE_STDERR))
{
dbus_create_service_instance (TEST_DBUS_NAME);
exit (0); /* should never be triggered */
}
g_test_trap_assert_failed();
}
static void
test_dbus_get_capabilities (gpointer fixture, gconstpointer user_data)
{
char **caps = NULL;
gboolean ret = FALSE;
ret = stack_get_capabilities (NULL, &caps);
g_assert (ret);
g_assert (!g_strcmp0 (caps[0], "body"));
int i = 0;
while (caps[i] != NULL)
{
g_assert (!g_strrstr (caps[i++], "actions"));
}
}
static void
test_dbus_get_server_information (gpointer fixture, gconstpointer user_data)
{
gchar *name = NULL, *vendor = NULL, *version = NULL, *specver = NULL;
gboolean ret = FALSE;
ret = stack_get_server_information (NULL, &name, &vendor,
&version, &specver);
g_assert (ret);
g_assert (g_strrstr (name, "notify-osd"));
g_assert (g_strrstr (specver, "1.1"));
}
GTestSuite *
test_dbus_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("dbus");
g_test_suite_add(ts,
g_test_create_case ("can create an instance on the bus",
0,
NULL,
NULL,
(GTestFixtureFunc) test_dbus_instance,
NULL)
);
g_test_suite_add(ts,
g_test_create_case ("refuse to have multiple instance on the bus",
0,
NULL,
NULL,
(GTestFixtureFunc) test_dbus_collision,
NULL)
);
g_test_suite_add(ts,
g_test_create_case ("can get server capabilities",
0,
NULL,
NULL,
(GTestFixtureFunc) test_dbus_get_capabilities,
NULL)
);
g_test_suite_add(ts,
g_test_create_case ("can get server info",
0,
NULL,
NULL,
(GTestFixtureFunc) test_dbus_get_server_information,
NULL)
);
return ts;
}
./tests/test-text-filtering.c 0000644 0000156 0000165 00000014041 12704153542 016330 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-text-filtering.c - unit-tests for text filtering
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Cody Russell
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "util.h"
typedef struct {
const gchar *before;
const gchar *expected;
} TextComparisons;
typedef struct {
const gchar* before;
guint expected;
} IntegerExtraction;
static void
test_text_filter ()
{
static const TextComparisons tests[] = {
{ "Ubuntu", "Ubuntu" },
{ "Don't rock the boat", "Don't rock the boat" },
{ "Kick him while he's down", "Kick him while he's down" },
{ "\"Film spectators are quiet vampires.\"", "\"Film spectators are quiet vampires.\"" },
{ "Peace & Love", "Peace & Love" },
{ "War & Peace", "War & Peace" },
{ "Law & Order", "Law & Order" },
{ "Love & War", "Love & War" },
{ "7 > 3", "7 > 3" },
{ "7 > 3", "7 > 3" },
{ "7 > 3", "7 > 3" },
{ "7 > 3", "7 > 3" },
{ "14 < 42", "14 < 42" },
{ "14 < 42", "14 < 42" },
{ "14 < 42", "14 < 42" },
{ "14 < 42", "14 < 42" },
{ "><", "><" },
{ "<>", "<>" },
{ "< this is not a tag >", "< this is not a tag >" },
{ "Not italic", "Not italic" },
{ "So broken", "So broken" },
{ "
Nothing to see", "Nothing to see" },
{ "Test", "Test" },
{ "Bold", "Bold" },
{ "Span", "Span" },
{ "E-flat", "E-flat" },
{ "Sandwich", "Sandwich", },
{ "Fry", "Fry" },
{ "Testing tag", "Testing tag" },
{ "Surrounded by html", "Surrounded by html" },
{ "Surrounded by qt", "Surrounded by qt" },
{ "First line
\r \n Second line", "First line\nSecond line" },
{ "First line\n
\n2nd line\r\n3rd line", "First line\n2nd line\n3rd line" },
{ NULL, NULL }
};
for (int i = 0; tests[i].before != NULL; i++) {
char *filtered = filter_text (tests[i].before);
g_assert_cmpstr (filtered, ==, tests[i].expected);
g_free (filtered);
}
}
static void
test_newline_to_space ()
{
static const TextComparisons tests[] = {
{ "one\ntwo\nthree\nfour\nfive\nsix", "one two three four five six" },
{ "1\n2\n3\n4\n5\n6", "1 2 3 4 5 6" },
{ NULL, NULL }
};
for (int i = 0; tests[i].before != NULL; i++) {
char *filtered = newline_to_space (tests[i].before);
g_assert_cmpstr (filtered, ==, tests[i].expected);
g_free (filtered);
}
}
static void
test_extract_font_face ()
{
static const TextComparisons tests[] = {
{ "", "" },
{ "Sans 10", "Sans " },
{ "Candara 9", "Candara " },
{ "Bitstream Vera Serif Italic 1", "Bitstream Vera Serif Italic " },
{ "Calibri Italic 100", "Calibri Italic " },
{ "Century Schoolbook L Italic 10", "Century Schoolbook L Italic " },
{ NULL, NULL }
};
for (int i = 0; tests[i].before != NULL; i++)
{
GString* filtered = extract_font_face (tests[i].before);
g_assert_cmpstr (filtered->str, ==, tests[i].expected);
g_string_free (filtered, TRUE);
}
}
GTestSuite *
test_filtering_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("text-filter");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_text_filter));
g_test_suite_add(ts, TC(test_newline_to_space));
g_test_suite_add(ts, TC(test_extract_font_face));
return ts;
}
./tests/test-observer.c 0000644 0000156 0000165 00000004506 12704153542 015217 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** Codename "alsdorf"
**
** test-observer.c - unit-tests for observer class
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "observer.h"
static
void
test_observer_new ()
{
Observer* observer = NULL;
observer = observer_new ();
g_assert (observer != NULL);
observer_del (observer);
}
static
void
test_observer_del ()
{
Observer* observer = NULL;
observer = observer_new ();
observer_del (observer);
/*g_assert (observer == NULL);*/
}
static
void
test_observer_get_x ()
{
Observer* observer = NULL;
observer = observer_new ();
g_assert_cmpint (observer_get_x (observer), <=, 4096);
g_assert_cmpint (observer_get_x (observer), >=, 0);
observer_del (observer);
}
static
void
test_observer_get_y ()
{
Observer* observer = NULL;
observer = observer_new ();
g_assert_cmpint (observer_get_y (observer), <=, 4096);
g_assert_cmpint (observer_get_y (observer), >=, 0);
observer_del (observer);
}
GTestSuite *
test_observer_create_test_suite (void)
{
GTestSuite *ts = NULL;
ts = g_test_create_suite ("observer");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
g_test_suite_add(ts, TC(test_observer_new));
g_test_suite_add(ts, TC(test_observer_del));
g_test_suite_add(ts, TC(test_observer_get_x));
g_test_suite_add(ts, TC(test_observer_get_y));
return ts;
}
./tests/test-dnd.c 0000644 0000156 0000165 00000007074 12704153542 014140 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** test-dnd.c - test the do-not-disturb mode code
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include "dnd.h"
#include "util.h"
#include
#define TEST_DBUS_NAME "org.freedesktop.Notificationstest"
static
gboolean
check_fullscreen (GMainLoop *loop)
{
g_assert (dnd_has_one_fullscreen_window());
g_main_loop_quit (loop);
return FALSE;
}
static
gboolean
check_no_fullscreen (GMainLoop *loop)
{
g_assert (!dnd_has_one_fullscreen_window());
g_main_loop_quit (loop);
return FALSE;
}
// FIXME: fails under compiz, needs to be able handle compiz' viewports
static
WnckWorkspace *
find_free_workspace (WnckScreen *screen)
{
WnckWorkspace *active_workspace = wnck_screen_get_active_workspace (screen);
GList *lst = wnck_screen_get_workspaces (screen);
if (lst->data != active_workspace) {
return WNCK_WORKSPACE(lst->data);
}
lst = g_list_next (lst);
g_assert (lst);
return WNCK_WORKSPACE(lst->data);
}
static
void
test_dnd_fullscreen (gpointer fixture, gconstpointer user_data)
{
g_assert (!dnd_has_one_fullscreen_window());
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_fullscreen (GTK_WINDOW (window));
gtk_widget_show_now (window);
GMainLoop* loop = g_main_loop_new (NULL, FALSE);
g_timeout_add (2000, (GSourceFunc) check_fullscreen, loop);
g_main_loop_run (loop);
// Move window to a free workspace, dnd_has_one_fullscreen_window should
// not find it anymore
WnckScreen *screen = wnck_screen_get_default ();
WnckWindow *wnck_window = wnck_screen_get_active_window (screen);
g_assert (wnck_window);
WnckWorkspace *free_workspace = find_free_workspace (screen);
g_assert (free_workspace);
wnck_window_move_to_workspace (wnck_window, free_workspace);
g_timeout_add (2000, (GSourceFunc) check_no_fullscreen, loop);
g_main_loop_run (loop);
gtk_widget_destroy (window);
}
GTestSuite *
test_dnd_create_test_suite (void)
{
GTestSuite* ts = NULL;
gchar* wm_name = NULL;
ts = g_test_create_suite ("dnd");
#define TC(x) g_test_create_case(#x, 0, NULL, NULL, x, NULL)
// FIXME: test_dnd_fullscreen() fails under compiz because of it using
// viewports instead of workspaces
wm_name = get_wm_name (gdk_x11_display_get_xdisplay (gdk_display_get_default ()));
if (wm_name && g_ascii_strcasecmp (WM_NAME_COMPIZ, wm_name))
g_test_suite_add (ts, TC(test_dnd_fullscreen));
else
{
g_print ("*** WARNING: Skipping /dnd/test_dnd_fullscreen ");
g_print ("because it does currently not work under compiz!\n");
}
return ts;
}
./tests/test-scroll-text.c 0000644 0000156 0000165 00000063665 12704153542 015663 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// test-scroll-text
//
// test-scroll-text.c - test using tile to animate scrolling text in a bubble
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
#include "raico-blur.h"
#include "tile.h"
#include "util.h"
#define BUBBLE_SHADOW_SIZE 10.0f
#define CORNER_RADIUS 6.0f
#define BUBBLE_WIDTH 320.0f
#define BUBBLE_HEIGHT 175.0f
#define BUBBLE_BG_COLOR_R 0.2f
#define BUBBLE_BG_COLOR_G 0.2f
#define BUBBLE_BG_COLOR_B 0.2f
#define POS_X 0
#define POS_Y 30
gboolean g_composited = FALSE;
gboolean g_mouse_over = FALSE;
tile_t* g_tile = NULL;
tile_t* g_text = NULL;
gfloat g_distance = 1.0f;
gint g_offset = -50;
gint g_step = 1;
cairo_surface_t*
render_text_to_surface (gchar* text,
gint width,
gint height,
const cairo_font_options_t* font_opts,
gdouble dpi)
{
cairo_surface_t* surface;
cairo_t* cr;
PangoFontDescription* desc;
PangoLayout* layout;
// sanity check
if (!text ||
width <= 0 ||
height <= 0)
return NULL;
// create surface
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width,
height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
return NULL;
// create context
cr = cairo_create (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return NULL;
}
// clear context
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
//
layout = pango_cairo_create_layout (cr);
desc = pango_font_description_new ();
pango_font_description_set_size (desc, 12 * PANGO_SCALE);
pango_font_description_set_family_static (desc, "Candara");
pango_font_description_set_weight (desc, PANGO_WEIGHT_NORMAL);
pango_font_description_set_style (desc, PANGO_STYLE_NORMAL);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_width (layout, width * PANGO_SCALE);
pango_layout_set_height (layout, height * PANGO_SCALE);
pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
// print and layout string (pango-wise)
pango_layout_set_text (layout, text, -1);
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (pango_layout_get_context (layout),
font_opts);
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
dpi);
pango_layout_context_changed (layout);
// draw pango-text to our cairo-context
cairo_move_to (cr, 0.0f, 0.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f);
// this call leaks 3803 bytes, I've no idea how to fix that
pango_cairo_show_layout (cr, layout);
// clean up
g_object_unref (layout);
cairo_destroy (cr);
return surface;
}
void
draw_round_rect (cairo_t* cr,
gdouble aspect, // aspect-ratio
gdouble x, // top-left corner
gdouble y, // top-left corner
gdouble corner_radius, // "size" of the corners
gdouble width, // width of the rectangle
gdouble height) // height of the rectangle
{
gdouble radius = corner_radius / aspect;
// top-left, right of the corner
cairo_move_to (cr, x + radius, y);
// top-right, left of the corner
cairo_line_to (cr,
x + width - radius,
y);
// top-right, below the corner
cairo_arc (cr,
x + width - radius,
y + radius,
radius,
-90.0f * G_PI / 180.0f,
0.0f * G_PI / 180.0f);
// bottom-right, above the corner
cairo_line_to (cr,
x + width,
y + height - radius);
// bottom-right, left of the corner
cairo_arc (cr,
x + width - radius,
y + height - radius,
radius,
0.0f * G_PI / 180.0f,
90.0f * G_PI / 180.0f);
// bottom-left, right of the corner
cairo_line_to (cr,
x + radius,
y + height);
// bottom-left, above the corner
cairo_arc (cr,
x + radius,
y + height - radius,
radius,
90.0f * G_PI / 180.0f,
180.0f * G_PI / 180.0f);
// top-left, below the corner
cairo_line_to (cr,
x,
y + radius);
// top-left, right of the corner
cairo_arc (cr,
x + radius,
y + radius,
radius,
180.0f * G_PI / 180.0f,
270.0f * G_PI / 180.0f);
}
void
screen_changed_handler (GtkWidget* window,
GdkScreen* old_screen,
gpointer data)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (window));
GdkVisual* visual = gdk_screen_get_rgba_visual (screen);
if (!visual)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (GTK_WIDGET (window), visual);
}
static
void
update_input_shape (GtkWidget* window,
gint width,
gint height)
{
cairo_region_t* region = NULL;
const cairo_rectangle_int_t rect = {0, 0, 1, 1};
region = cairo_region_create_rectangle (&rect);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_input_shape_combine_region (window, NULL);
gtk_widget_input_shape_combine_region (window, region);
}
}
static void
update_shape (GtkWidget* window,
gint radius,
gint shadow_size)
{
if (g_composited)
{
/* remove any current shape-mask */
gtk_widget_input_shape_combine_region (window, NULL);
return;
}
int width;
int height;
gtk_widget_get_size_request (window, &width, &height);
const cairo_rectangle_int_t rects[] = {{2, 0, width - 4, height},
{1, 1, width - 2, height - 2},
{0, 2, width, height - 4}};
cairo_region_t* region = NULL;
region = cairo_region_create_rectangles (rects, 3);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_shape_combine_region (window, NULL);
gtk_widget_shape_combine_region (window, region);
}
}
void
composited_changed_handler (GtkWidget* window,
gpointer data)
{
g_composited = gdk_screen_is_composited(gtk_widget_get_screen (window));
update_shape (window,
(gint) CORNER_RADIUS,
(gint) BUBBLE_SHADOW_SIZE);
}
void
draw_shadow (cairo_t* cr,
gdouble width,
gdouble height,
gint shadow_radius,
gint corner_radius)
{
cairo_surface_t* tmp_surface = NULL;
cairo_surface_t* new_surface = NULL;
cairo_pattern_t* pattern = NULL;
cairo_t* cr_surf = NULL;
cairo_matrix_t matrix;
raico_blur_t* blur = NULL;
tmp_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
4 * shadow_radius,
4 * shadow_radius);
if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS)
return;
cr_surf = cairo_create (tmp_surface);
if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
return;
}
cairo_scale (cr_surf, 1.0f, 1.0f);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr_surf);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 0.75f);
cairo_arc (cr_surf,
2 * shadow_radius,
2 * shadow_radius,
2.0f * corner_radius,
0.0f,
360.0f * (G_PI / 180.f));
cairo_fill (cr_surf);
cairo_destroy (cr_surf);
// create and setup blur
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, shadow_radius);
// now blur it
raico_blur_apply (blur, tmp_surface);
// blur no longer needed
raico_blur_destroy (blur);
new_surface = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (tmp_surface),
cairo_image_surface_get_format (tmp_surface),
cairo_image_surface_get_width (tmp_surface) / 2,
cairo_image_surface_get_height (tmp_surface) / 2,
cairo_image_surface_get_stride (tmp_surface));
pattern = cairo_pattern_create_for_surface (new_surface);
if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
return;
}
// top left
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_set_source (cr, pattern);
cairo_rectangle (cr,
0.0f,
0.0f,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// bottom left
cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
cairo_matrix_translate (&matrix, 0.0f, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
0.0f,
2 * shadow_radius,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// top right
cairo_matrix_init_scale (&matrix, -1.0f, 1.0f);
cairo_matrix_translate (&matrix, -width, 0.0f);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
width - 2 * shadow_radius,
0.0f,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// bottom right
cairo_matrix_init_scale (&matrix, -1.0f, -1.0f);
cairo_matrix_translate (&matrix, -width, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
2 * shadow_radius,
height - 2 * shadow_radius,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// clean up
cairo_pattern_destroy (pattern);
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
}
gboolean
expose_handler (GtkWidget* window,
cairo_t* cr,
gpointer data)
{
cairo_pattern_t* pattern = NULL;
cairo_pattern_t* mask = NULL;
// clear and render drop-shadow and bubble-background
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (g_distance < 1.0f)
{
tile_paint (g_tile, cr, 0.0f, 0.0f, g_distance, 1.0f - g_distance);
cairo_push_group (cr);
tile_paint (g_text,
cr,
2 * BUBBLE_SHADOW_SIZE,
BUBBLE_SHADOW_SIZE - g_offset,
g_distance,
1.0f - g_distance);
pattern = cairo_pop_group (cr);
cairo_set_source (cr, pattern);
mask = cairo_pattern_create_linear (0.0f, 2 * BUBBLE_SHADOW_SIZE, 0.0f, BUBBLE_HEIGHT);
cairo_pattern_add_color_stop_rgba (mask,
0.0f,
0.0f,
0.0f,
0.0f,
0.0f);
cairo_pattern_add_color_stop_rgba (mask,
0.2f,
0.0f,
0.0f,
0.0f,
1.0f);
cairo_pattern_add_color_stop_rgba (mask,
0.8f,
0.0f,
0.0f,
0.0f,
1.0f);
cairo_pattern_add_color_stop_rgba (mask,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f);
cairo_mask (cr, mask);
cairo_pattern_destroy (mask);
cairo_pattern_destroy (pattern);
gtk_widget_set_opacity (window,
0.3f + g_distance * 0.7f);
}
else
{
tile_paint (g_tile, cr, 0.0f, 0.0f, g_distance, 0.0f);
cairo_push_group (cr);
tile_paint (g_text, cr, 2 * BUBBLE_SHADOW_SIZE, BUBBLE_SHADOW_SIZE - g_offset, g_distance, 0.0f);
pattern = cairo_pop_group (cr);
cairo_set_source (cr, pattern);
mask = cairo_pattern_create_linear (0.0f, 2 * BUBBLE_SHADOW_SIZE, 0.0f, BUBBLE_HEIGHT);
cairo_pattern_add_color_stop_rgba (mask, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
cairo_pattern_add_color_stop_rgba (mask, 0.2f, 0.0f, 0.0f, 0.0f, 1.0f);
cairo_pattern_add_color_stop_rgba (mask, 0.8f, 0.0f, 0.0f, 0.0f, 1.0f);
cairo_pattern_add_color_stop_rgba (mask, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
cairo_mask (cr, mask);
cairo_pattern_destroy (pattern);
gtk_widget_set_opacity (window, 1.0f);
}
return TRUE;
}
void
set_bg_blur (GtkWidget* window,
gboolean blur)
{
GtkAllocation a;
GdkWindow* gdkwindow;
gint shadow = BUBBLE_SHADOW_SIZE;
if (!window)
return;
gtk_widget_get_allocation (window, &a);
gdkwindow = gtk_widget_get_window (window);
if (blur)
{
glong data[] = {
2, // threshold
0, // filter
NorthWestGravity, // gravity of top-left
shadow, // x-coord of top-left
-a.height/2 + shadow, // y-coord of top-left
NorthWestGravity, // gravity of bottom-right
a.width - shadow, // bottom-right x-coord
a.height/2 - shadow}; // bottom-right y-coord
XChangeProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom(GDK_WINDOW_XDISPLAY(gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE),
XA_INTEGER,
32,
PropModeReplace,
(guchar *) data,
8);
}
else
{
XDeleteProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom(GDK_WINDOW_XDISPLAY(gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE));
}
}
gboolean
quit (gpointer data)
{
gtk_main_quit ();
return FALSE;
}
gboolean
pointer_update (GtkWidget* window)
{
gint pointer_rel_x;
gint pointer_rel_y;
gint pointer_abs_x;
gint pointer_abs_y;
gint win_x;
gint win_y;
gint width;
gint height;
gboolean old_mouse_over;
if (!GTK_IS_WINDOW (window))
return FALSE;
old_mouse_over = g_mouse_over;
if (gtk_widget_get_realized (window))
{
GdkDeviceManager *device_manager;
GdkDevice *device;
gint distance_x;
gint distance_y;
device_manager = gdk_display_get_device_manager (gtk_widget_get_display (window));
device = gdk_device_manager_get_client_pointer (device_manager);
gdk_window_get_device_position (gtk_widget_get_window (window),
device,
&pointer_rel_x,
&pointer_rel_y,
NULL);
gtk_window_get_position (GTK_WINDOW (window), &win_x, &win_y);
pointer_abs_x = win_x + pointer_rel_x;
pointer_abs_y = win_y + pointer_rel_y;
gtk_window_get_size (GTK_WINDOW (window), &width, &height);
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width &&
pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
g_mouse_over = TRUE;
else
g_mouse_over = FALSE;
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width)
distance_x = 0;
else
{
if (pointer_abs_x < win_x)
distance_x = abs (pointer_rel_x);
if (pointer_abs_x > win_x + width)
distance_x = abs (pointer_rel_x - width);
}
if (pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
distance_y = 0;
else
{
if (pointer_abs_y < win_y)
distance_y = abs (pointer_rel_y);
if (pointer_abs_y > win_y + height)
distance_y = abs (pointer_rel_y - height);
}
g_distance = sqrt (distance_x * distance_x +
distance_y * distance_y) /
(double) 40;
}
if (old_mouse_over != g_mouse_over)
set_bg_blur (window, !g_mouse_over);
if (g_offset < -50)
g_step = 1;
if (g_offset > 150)
g_step = -1;
g_offset += g_step;
gtk_widget_queue_draw (window);
return TRUE;
}
tile_t*
setup_text_tile (const cairo_font_options_t* font_opts,
gdouble dpi,
gint w,
gint h)
{
tile_t* tile = NULL;
cairo_status_t status;
cairo_surface_t* surface = NULL;
cairo_surface_t* text = NULL;
cairo_surface_t* shadow = NULL;
cairo_t* cr;
gdouble width = (gdouble) w;
gdouble height = (gdouble) h;
raico_blur_t* blur = NULL;
cairo_pattern_t* pattern = NULL;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
cr = cairo_create (surface);
status = cairo_status (cr);
if (status != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
}
// clear and render drop-shadow and bubble-background
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
text = render_text_to_surface (
"After an evening of hacking at the"
" Fataga hotel here at GUADEC I "
"can present you even text-scroll "
"with blur-cache and fade-out mask"
" and I dedicate this to Behdad who"
" sadly burst his upper lip during "
"the evening and had to go to the "
"hospital. Some spanish KDE-folks "
"kindly accompanied him to help out"
" with translation. True collaboration!\0",
width,
height,
font_opts,
dpi);
shadow = render_text_to_surface (
"After an evening of hacking at the"
" Fataga hotel here at GUADEC I "
"can present you even text-scroll "
"with blur-cache and fade-out mask"
" and I dedicate this to Behdad who"
" sadly burst his upper lip during "
"the evening and had to go to the "
"hospital. Some spanish KDE-folks "
"kindly accompanied him to help out"
" with translation. True collaboration!\0",
width,
height,
font_opts,
dpi);
// create and setup blur
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, 4);
// now blur it
raico_blur_apply (blur, shadow);
// blur no longer needed
raico_blur_destroy (blur);
cairo_push_group (cr);
cairo_set_source_surface (cr,
shadow,
0.0f,
0.0f);
cairo_paint (cr);
pattern = cairo_pop_group (cr);
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 1.0f);
cairo_mask (cr, pattern);
cairo_surface_destroy (shadow);
cairo_pattern_destroy (pattern);
cairo_set_source_surface (cr, text, 0.0f, 0.0f);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (text);
tile = tile_new (surface, 6);
cairo_surface_destroy (surface);
return tile;
}
void
setup_tile (gint w, gint h)
{
cairo_status_t status;
cairo_t* cr = NULL;
cairo_surface_t* cr_surf = NULL;
gdouble width = (gdouble) w;
gdouble height = (gdouble) h;
cairo_surface_t* tmp = NULL;
cairo_surface_t* dummy_surf = NULL;
cairo_surface_t* norm_surf = NULL;
cairo_surface_t* blur_surf = NULL;
raico_blur_t* blur = NULL;
tile_t* tile = NULL;
// create tmp. surface for scratch
cr_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
3 * BUBBLE_SHADOW_SIZE,
3 * BUBBLE_SHADOW_SIZE);
status = cairo_surface_status (cr_surf);
if (status != CAIRO_STATUS_SUCCESS)
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
// create context for that tmp. scratch surface
cr = cairo_create (cr_surf);
status = cairo_status (cr);
if (status != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (cr_surf);
g_print ("Error: \"%s\"\n", cairo_status_to_string (status));
}
// clear, render drop-shadow and bubble-background in scratch-surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (g_composited)
{
draw_shadow (cr,
width,
height,
BUBBLE_SHADOW_SIZE,
CORNER_RADIUS);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
draw_round_rect (cr,
1.0f,
(gdouble) BUBBLE_SHADOW_SIZE,
(gdouble) BUBBLE_SHADOW_SIZE,
(gdouble) CORNER_RADIUS,
(gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE),
(gdouble) (height - 2.0f* BUBBLE_SHADOW_SIZE));
cairo_fill (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr,
BUBBLE_BG_COLOR_R,
BUBBLE_BG_COLOR_G,
BUBBLE_BG_COLOR_B,
0.95f);
}
else
cairo_set_source_rgb (cr,
BUBBLE_BG_COLOR_R,
BUBBLE_BG_COLOR_G,
BUBBLE_BG_COLOR_B);
draw_round_rect (cr,
1.0f,
BUBBLE_SHADOW_SIZE,
BUBBLE_SHADOW_SIZE,
CORNER_RADIUS,
(gdouble) (width - 2.0f * BUBBLE_SHADOW_SIZE),
(gdouble) (height - 2.0f * BUBBLE_SHADOW_SIZE));
cairo_fill (cr);
// create tmp. copy of scratch-surface
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (cr_surf),
cairo_image_surface_get_format (cr_surf),
3 * BUBBLE_SHADOW_SIZE,
3 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (cr_surf));
dummy_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
// create normal-state surface for tile from copy of scratch-surface
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (dummy_surf),
cairo_image_surface_get_format (dummy_surf),
2 * BUBBLE_SHADOW_SIZE,
2 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (dummy_surf));
norm_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
// blur tmp. copy of scratch-surface
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, 6);
raico_blur_apply (blur, dummy_surf);
raico_blur_destroy (blur);
// create blurred-state surface for tile
tmp = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (dummy_surf),
cairo_image_surface_get_format (dummy_surf),
2 * BUBBLE_SHADOW_SIZE,
2 * BUBBLE_SHADOW_SIZE,
cairo_image_surface_get_stride (dummy_surf));
blur_surf = copy_surface (tmp);
cairo_surface_destroy (tmp);
// actually create the tile with padding in mind
tile = tile_new_for_padding (norm_surf, blur_surf, width, height);
cairo_surface_destroy (norm_surf);
cairo_surface_destroy (blur_surf);
cairo_surface_destroy (dummy_surf);
cairo_destroy (cr);
cairo_surface_destroy (cr_surf);
norm_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
cr = cairo_create (norm_surf);
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
tile_paint_with_padding (tile, cr, 0.0f, 0.0f, w, h, 1.0f, 0.0f);
cairo_destroy (cr);
blur_surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
cr = cairo_create (blur_surf);
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
tile_paint_with_padding (tile, cr, 0.0f, 0.0f, w, h, 0.0f, 1.0f);
cairo_destroy (cr);
g_tile = tile_new_for_padding (norm_surf, blur_surf, width, height);
// clean up
tile_destroy (tile);
cairo_surface_destroy (norm_surf);
cairo_surface_destroy (blur_surf);
}
int
main (int argc,
char** argv)
{
GtkWidget* window;
GdkRGBA transparent = {0.0, 0.0, 0.0, 0.0};
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
if (!window)
return 0;
gtk_window_set_type_hint (GTK_WINDOW (window),
GDK_WINDOW_TYPE_HINT_DOCK);
gtk_widget_add_events (window,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
// hook up input/event handlers to window
g_signal_connect (G_OBJECT (window),
"screen-changed",
G_CALLBACK (screen_changed_handler),
NULL);
g_signal_connect (G_OBJECT (window),
"composited-changed",
G_CALLBACK (composited_changed_handler),
NULL);
gtk_window_move (GTK_WINDOW (window), POS_X, POS_Y);
// make sure the window opens with a RGBA-visual
screen_changed_handler (window, NULL, NULL);
gtk_widget_realize (window);
gdk_window_set_background_rgba (gtk_widget_get_window (window),
&transparent);
// hook up window-event handlers to window
g_signal_connect (G_OBJECT (window),
"draw",
G_CALLBACK (expose_handler),
NULL);
// FIXME: read out current mouse-pointer position every 1/25 second
g_timeout_add (1000/40,
(GSourceFunc) pointer_update,
(gpointer) window);
g_timeout_add (10000,
(GSourceFunc) quit,
NULL);
// "clear" input-mask, set title/icon/attributes
gtk_widget_set_app_paintable (window, TRUE);
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_accept_focus (GTK_WINDOW (window), FALSE);
gtk_widget_set_opacity (window, 1.0f);
gtk_widget_set_size_request (window,
(gint) (BUBBLE_WIDTH + 2.0f *
BUBBLE_SHADOW_SIZE),
(gint) (BUBBLE_HEIGHT + 2.0f *
BUBBLE_SHADOW_SIZE));
gtk_widget_show (window);
g_composited = gdk_screen_is_composited(gtk_widget_get_screen (window));
update_input_shape (window, 1, 1);
update_shape (window,
(gint) CORNER_RADIUS,
(gint) BUBBLE_SHADOW_SIZE);
set_bg_blur (window, TRUE);
setup_tile ((gint) (BUBBLE_WIDTH + 2.0f * BUBBLE_SHADOW_SIZE),
(gint) (BUBBLE_HEIGHT + 2.0f * BUBBLE_SHADOW_SIZE));
g_text = setup_text_tile (gdk_screen_get_font_options (
gtk_widget_get_screen (window)),
gdk_screen_get_resolution (
gtk_widget_get_screen (window)),
(gint) (BUBBLE_WIDTH - 2*BUBBLE_SHADOW_SIZE),
(gint) (3.0f * BUBBLE_HEIGHT));
g_print ("This test will run for 10 seconds and then quit.\n");
gtk_main ();
tile_destroy (g_tile);
tile_destroy (g_text);
return 0;
}
./src/ 0000755 0000156 0000165 00000000000 12704153556 011674 5 ustar jenkins jenkins ./src/observer.h 0000644 0000156 0000165 00000004540 12704153542 013672 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** observer.h - meant to be a singelton watching for mouse-over-bubble cases
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __OBSERVER_H
#define __OBSERVER_H
#include
#include
G_BEGIN_DECLS
#define OBSERVER_TYPE (observer_get_type ())
#define OBSERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OBSERVER_TYPE, Observer))
#define OBSERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OBSERVER_TYPE, ObserverClass))
#define IS_OBSERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OBSERVER_TYPE))
#define IS_OBSERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OBSERVER_TYPE))
#define OBSERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OBSERVER_TYPE, ObserverClass))
typedef struct _Observer Observer;
typedef struct _ObserverClass ObserverClass;
/* instance structure */
struct _Observer
{
GObject parent;
/* private */
GtkWidget* window;
gint timeout_frequency;
guint timeout_id;
gint pointer_x;
gint pointer_y;
};
/* class structure */
struct _ObserverClass
{
GObjectClass parent;
};
GType Observer_get_type (void);
Observer*
observer_new (void);
void
observer_del (Observer* self);
gint
observer_get_x (Observer* self);
gint
observer_get_y (Observer* self);
G_END_DECLS
#endif /* __OBSERVER_H */
./src/bubble-window-accessible-factory.c 0000644 0000156 0000165 00000004727 12704153542 020345 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window-accessible-factory.c - implements an accessible object factory
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include "bubble-window-accessible-factory.h"
#include "bubble-window-accessible.h"
G_DEFINE_TYPE (BubbleWindowAccessibleFactory, bubble_window_accessible_factory, ATK_TYPE_OBJECT_FACTORY);
static AtkObject* bubble_window_accessible_factory_create_accessible (GObject *obj);
static GType bubble_window_accessible_factory_get_accessible_type (void);
static void
bubble_window_accessible_factory_init (BubbleWindowAccessibleFactory *object)
{
/* TODO: Add initialization code here */
}
static void
bubble_window_accessible_factory_class_init (BubbleWindowAccessibleFactoryClass *klass)
{
AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
class->create_accessible = bubble_window_accessible_factory_create_accessible;
class->get_accessible_type = bubble_window_accessible_factory_get_accessible_type;
}
AtkObjectFactory*
bubble_window_accessible_factory_new (void)
{
GObject *factory;
factory = g_object_new (BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY, NULL);
return ATK_OBJECT_FACTORY (factory);
}
static AtkObject*
bubble_window_accessible_factory_create_accessible (GObject *obj)
{
GtkWidget *widget;
g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
widget = GTK_WIDGET (obj);
return bubble_window_accessible_new (widget);
}
static GType
bubble_window_accessible_factory_get_accessible_type (void)
{
return BUBBLE_WINDOW_TYPE_ACCESSIBLE;
}
./src/dialog.h 0000644 0000156 0000165 00000003123 12704153542 013276 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// dialog.h - fallback to display when a notification is not spec-compliant
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
// David Barth
//
// Contributor(s):
// Abhishek Mukherjee (append fixes, rev. 280)
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_H
#define __DIALOG_H
#include
#include "defaults.h"
void
fallback_dialog_show (Defaults* defaults,
const gchar* sender,
const gchar* app_name,
int id,
const gchar* summary,
const gchar* body,
gchar** actions);
#endif // __DIALOG_H
./src/bubble.h 0000644 0000156 0000165 00000012477 12704153542 013306 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// bubble.h - implements all the rendering of a notification bubble
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
// David Barth
//
// Contributor(s):
// Eitan Isaacson (ATK interface for a11y, rev. 351)
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef __BUBBLE_H
#define __BUBBLE_H
#include
#include
#include "defaults.h"
typedef enum
{
LAYOUT_NONE = 0,
LAYOUT_ICON_ONLY,
LAYOUT_ICON_INDICATOR,
LAYOUT_ICON_TITLE,
LAYOUT_ICON_TITLE_BODY,
LAYOUT_TITLE_BODY,
LAYOUT_TITLE_ONLY
} BubbleLayout;
G_BEGIN_DECLS
#define BUBBLE_TYPE (bubble_get_type ())
#define BUBBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUBBLE_TYPE, Bubble))
#define BUBBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BUBBLE_TYPE, BubbleClass))
#define IS_BUBBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUBBLE_TYPE))
#define IS_BUBBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUBBLE_TYPE))
#define BUBBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BUBBLE_TYPE, BubbleClass))
typedef struct _Bubble Bubble;
typedef struct _BubbleClass BubbleClass;
typedef struct _BubblePrivate BubblePrivate;
// instance structure
struct _Bubble
{
GObject parent;
Defaults* defaults;
//< private >
BubblePrivate *priv;
};
// class structure
struct _BubbleClass
{
GObjectClass parent;
//< signals >
void (*timed_out) (Bubble* bubble);
void (*value_changed) (Bubble* bubble);
void (*message_body_deleted) (Bubble* bubble);
void (*message_body_inserted) (Bubble* bubble);
};
GType bubble_get_type (void);
Bubble*
bubble_new (Defaults* defaults);
gchar*
bubble_get_synchronous (Bubble *self);
gchar*
bubble_get_sender (Bubble *self);
void
bubble_set_title (Bubble* self,
const gchar* title);
const gchar*
bubble_get_title (Bubble* self);
void
bubble_set_message_body (Bubble* self,
const gchar* body);
const gchar*
bubble_get_message_body (Bubble* self);
void
bubble_set_icon (Bubble* self,
const gchar* name);
void
bubble_set_icon_from_pixbuf (Bubble* self,
GdkPixbuf* pixbuf);
GdkPixbuf*
bubble_get_icon_pixbuf (Bubble *self);
void
bubble_set_value (Bubble* self,
gint value);
gint
bubble_get_value (Bubble* self);
void
bubble_set_size (Bubble* self,
gint width,
gint height);
void
bubble_get_size (Bubble* self,
gint* width,
gint* height);
void
bubble_set_timeout (Bubble* self,
guint timeout);
guint
bubble_get_timeout (Bubble* self);
void
bubble_set_timer_id (Bubble* self,
guint timer_id);
guint
bubble_get_timer_id (Bubble* self);
void
bubble_set_mouse_over (Bubble* self,
gboolean flag);
gboolean
bubble_is_mouse_over (Bubble* self);
void
bubble_move (Bubble* self,
gint x,
gint y);
gboolean
bubble_timed_out (Bubble* self);
void
bubble_show (Bubble* self);
void
bubble_refresh (Bubble* self);
void
bubble_hide (Bubble* self);
void
bubble_set_id (Bubble* self,
guint id);
guint
bubble_get_id (Bubble* self);
gboolean
bubble_is_visible (Bubble* self);
void
bubble_start_timer (Bubble* self,
gboolean trigger);
void
bubble_clear_timer (Bubble* self);
void
bubble_get_position (Bubble* self,
gint* x,
gint* y);
gint
bubble_get_height (Bubble *self);
gint
bubble_get_future_height (Bubble *self);
void
bubble_recalc_size (Bubble *self);
gboolean
bubble_is_synchronous (Bubble *self);
void
bubble_set_synchronous (Bubble *self,
const gchar *sync);
void
bubble_set_sender (Bubble *self,
const gchar *sender);
gboolean
bubble_is_urgent (Bubble *self);
guint
bubble_get_urgency (Bubble *self);
void
bubble_set_urgency (Bubble *self,
guint urgency);
void
bubble_fade_out (Bubble *self,
guint msecs);
void
bubble_fade_in (Bubble *self,
guint msecs);
void
bubble_determine_layout (Bubble* self);
BubbleLayout
bubble_get_layout (Bubble* self);
void
bubble_set_icon_only (Bubble* self,
gboolean allowed);
void
bubble_set_append (Bubble* self,
gboolean allowed);
gboolean
bubble_is_append_allowed (Bubble* self);
void
bubble_append_message_body (Bubble* self,
const gchar* append_body);
void
bubble_sync_with (Bubble *self,
Bubble *other);
GObject*
bubble_show_dialog (Bubble *bubble,
const char *process_name,
gchar **actions);
G_END_DECLS
#endif // __BUBBLE_H
./src/gaussian-blur.h 0000644 0000156 0000165 00000002543 12704153542 014620 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// gaussian-blur.h - implements gaussian-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// based on filters in libpixman
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _GAUSSIAN_BLUR_H
#define _GAUSSIAN_BLUR_H
#include
#include
void
surface_gaussian_blur (cairo_surface_t* surface,
guint radius);
#endif // _GAUSSIAN_BLUR_H
./src/raico-blur.c 0000644 0000156 0000165 00000010564 12704153542 014100 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// raico-blur.c - implements public API for blurring cairo image-surfaces
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include "raico-blur.h"
#include "exponential-blur.h"
#include "stack-blur.h"
#include "gaussian-blur.h"
struct _raico_blur_private_t
{
raico_blur_quality_t quality; // low, medium, high
guint radius; // blur-radius
};
raico_blur_t*
raico_blur_create (raico_blur_quality_t quality)
{
raico_blur_t* blur = NULL;
raico_blur_private_t* priv = NULL;
blur = g_new0 (raico_blur_t, 1);
if (!blur)
{
g_debug ("raico_blur_create(): could not allocate blur struct");
return NULL;
}
priv = g_new0 (raico_blur_private_t, 1);
if (!priv)
{
g_debug ("raico_blur_create(): could not allocate priv struct");
g_free ((gpointer) blur);
return NULL;
}
priv->quality = quality;
priv->radius = 0;
blur->priv = priv;
return blur;
}
raico_blur_quality_t
raico_blur_get_quality (raico_blur_t* blur)
{
g_assert (blur != NULL);
return blur->priv->quality;
}
void
raico_blur_set_quality (raico_blur_t* blur,
raico_blur_quality_t quality)
{
if (!blur)
{
g_debug ("raico_blur_set_quality(): NULL blur-pointer passed");
return;
}
blur->priv->quality = quality;
}
guint
raico_blur_get_radius (raico_blur_t* blur)
{
g_assert (blur != NULL);
return blur->priv->radius;
}
void
raico_blur_set_radius (raico_blur_t* blur,
guint radius)
{
if (!blur)
{
g_debug ("raico_blur_set_radius(): NULL blur-pointer passed");
return;
}
blur->priv->radius = radius;
}
void
raico_blur_apply (raico_blur_t* blur,
cairo_surface_t* surface)
{
cairo_format_t format;
double x_scale;
double y_scale;
guint radius;
// sanity checks
if (!blur)
{
g_debug ("raico_blur_apply(): NULL blur-pointer passed");
return;
}
if (!surface)
{
g_debug ("raico_blur_apply(): NULL surface-pointer passed");
return;
}
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
g_debug ("raico_blur_apply(): invalid surface status");
return;
}
if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE)
{
g_debug ("raico_blur_apply(): non-image surface passed");
return;
}
format = cairo_image_surface_get_format (surface);
if (format != CAIRO_FORMAT_A8 &&
format != CAIRO_FORMAT_RGB24 &&
format != CAIRO_FORMAT_ARGB32)
{
g_debug ("raico_blur_apply(): unsupported image-format");
return;
}
// stupid, but you never know
if (blur->priv->radius == 0)
return;
/* adjust radius for device scale. We don't support blurring
* different amounts in x and y, so just use the mean value
* between cairo's respective device scales (in practice they
* should always be the same). */
cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
radius = blur->priv->radius * 0.5 * (x_scale + y_scale);
// now do the real work
switch (blur->priv->quality)
{
case RAICO_BLUR_QUALITY_LOW:
surface_exponential_blur (surface, radius);
break;
case RAICO_BLUR_QUALITY_MEDIUM:
//surface_stack_blur (surface, blur->priv->radius);
surface_gaussian_blur (surface, radius);
break;
case RAICO_BLUR_QUALITY_HIGH:
surface_gaussian_blur (surface, radius);
break;
}
}
void
raico_blur_destroy (raico_blur_t* blur)
{
if (!blur)
{
g_debug ("raico_blur_destroy(): invalid blur-pointer passed");
return;
}
g_free ((gpointer) blur->priv);
g_free ((gpointer) blur);
}
./src/stack.c 0000644 0000156 0000165 00000061547 12704153556 013162 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** stack.c - manages the stack/queue of incoming notifications
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** Contributor(s):
** Abhishek Mukherjee (append fixes, rev. 280)
** Aurélien Gâteau (0.10 spec, rev. 348)
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "dbus.h"
#include
#include
#include "stack.h"
#include "bubble.h"
#include "apport.h"
#include "dialog.h"
#include "dnd.h"
#include "log.h"
G_DEFINE_TYPE (Stack, stack, G_TYPE_OBJECT);
#define FORCED_SHUTDOWN_THRESHOLD 500
/* fwd declaration */
void close_handler (GObject* n, Stack* stack);
/*-- internal API ------------------------------------------------------------*/
static void
stack_dispose (GObject* gobject)
{
/* chain up to the parent class */
G_OBJECT_CLASS (stack_parent_class)->dispose (gobject);
}
static
void
disconnect_bubble (gpointer data,
gpointer user_data)
{
Bubble* bubble = BUBBLE(data);
Stack* stack = STACK(user_data);
g_signal_handlers_disconnect_by_func (G_OBJECT(bubble), G_CALLBACK (close_handler), stack);
}
static void
stack_finalize (GObject* gobject)
{
if (STACK(gobject)->list != NULL)
g_list_foreach (STACK(gobject)->list, disconnect_bubble, gobject);
if (STACK(gobject)->defaults != NULL)
g_object_unref (STACK(gobject)->defaults);
if (STACK(gobject)->observer != NULL)
g_object_unref (STACK(gobject)->observer);
/* chain up to the parent class */
G_OBJECT_CLASS (stack_parent_class)->finalize (gobject);
}
static void
stack_init (Stack* self)
{
/* If you need specific construction properties to complete
** initialization, delay initialization completion until the
** property is set. */
self->list = NULL;
}
static void
stack_get_property (GObject* gobject,
guint prop,
GValue* value,
GParamSpec* spec)
{
switch (prop)
{
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
#include "stack-glue.h"
static void
stack_class_init (StackClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = stack_dispose;
gobject_class->finalize = stack_finalize;
gobject_class->get_property = stack_get_property;
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
&dbus_glib_stack_object_info);
}
gint
compare_id (gconstpointer a,
gconstpointer b)
{
gint result;
guint id_1;
guint id_2;
if (!a || !b)
return -1;
if (!IS_BUBBLE (a))
return -1;
id_1 = bubble_get_id ((Bubble*) a);
id_2 = *((guint*) b);
if (id_1 < id_2)
result = -1;
if (id_1 == id_2)
result = 0;
if (id_1 > id_2)
result = 1;
return result;
}
static gint
compare_append (gconstpointer a,
gconstpointer b)
{
const gchar* str_1;
const gchar* str_2;
gint cmp;
if (!a || !b)
return -1;
if (!IS_BUBBLE (a))
return -1;
if (!IS_BUBBLE (b))
return 1;
if (!bubble_is_append_allowed((Bubble*) a))
return -1;
if (!bubble_is_append_allowed((Bubble*) b))
return 1;
str_1 = bubble_get_title ((Bubble*) a);
str_2 = bubble_get_title ((Bubble*) b);
cmp = g_strcmp0(str_1, str_2);
if (cmp < 0)
return -1;
if (cmp > 0)
return 1;
str_1 = bubble_get_sender ((Bubble*) a);
str_2 = bubble_get_sender ((Bubble*) b);
return g_strcmp0(str_1, str_2);
}
GList*
find_entry_by_id (Stack* self,
guint id)
{
GList* entry;
/* sanity check */
if (!self)
return NULL;
entry = g_list_find_custom (self->list,
(gconstpointer) &id,
compare_id);
if (!entry)
return NULL;
return entry;
}
static Bubble*
find_bubble_by_id (Stack* self,
guint id)
{
GList* entry;
/* sanity check */
if (!self)
return NULL;
entry = g_list_find_custom (self->list,
(gconstpointer) &id,
compare_id);
if (!entry)
return NULL;
return (Bubble*) entry->data;
}
static Bubble*
find_bubble_for_append(Stack* self,
Bubble *bubble)
{
GList* entry;
/* sanity check */
if (!self)
return NULL;
entry = g_list_find_custom(self->list,
(gconstpointer) bubble,
compare_append);
if (!entry)
return NULL;
return (Bubble*) entry->data;
}
static void
_weak_notify_cb (gpointer data,
GObject* former_object)
{
Stack* stack = STACK (data);
stack->list = g_list_remove (stack->list, former_object);
}
static void
_trigger_bubble_redraw (gpointer data,
gpointer user_data)
{
Bubble* bubble;
if (!data)
return;
bubble = BUBBLE (data);
if (!IS_BUBBLE (bubble))
return;
bubble_recalc_size (bubble);
bubble_refresh (bubble);
}
static Bubble *sync_bubble = NULL;
static void
value_changed_handler (Defaults* defaults,
Stack* stack)
{
if (stack->list != NULL)
g_list_foreach (stack->list, _trigger_bubble_redraw, NULL);
if (sync_bubble != NULL)
{
bubble_recalc_size (sync_bubble);
bubble_refresh (sync_bubble);
}
}
#include "display.c"
/*-- public API --------------------------------------------------------------*/
Stack*
stack_new (Defaults* defaults,
Observer* observer)
{
Stack* this;
if (!defaults || !observer)
return NULL;
this = g_object_new (STACK_TYPE, NULL);
if (!this)
return NULL;
this->defaults = defaults;
this->observer = observer;
this->list = NULL;
this->next_id = 1;
this->slots[SLOT_TOP] = NULL;
this->slots[SLOT_BOTTOM] = NULL;
/* hook up handler to act on changes of defaults/settings */
g_signal_connect (G_OBJECT (defaults),
"value-changed",
G_CALLBACK (value_changed_handler),
this);
return this;
}
void
stack_del (Stack* self)
{
if (!self)
return;
g_object_unref (self);
}
void
close_handler (GObject *n,
Stack* stack)
{
/* TODO: use weak-refs to dispose the bubble.
Meanwhile, do nothing here to avoid segfaults
and rely on the stack_purge_old_bubbles() call
later on in the thread.
*/
if (n != NULL)
{
if (IS_BUBBLE (n))
stack_free_slot (stack, BUBBLE (n));
if (IS_BUBBLE (n)
&& bubble_is_synchronous (BUBBLE (n)))
{
g_object_unref (n);
sync_bubble = NULL;
} if (IS_BUBBLE (n)) {
stack_pop_bubble_by_id (stack, bubble_get_id ((Bubble*) n));
/* Fix for a tricky race condition
where a bubble fades out in sync
with a synchronous bubble: the symc.
one is still considered visible while
the normal one has triggered this signal.
This ensures the display slot of the
sync. bubble is recycled, and no gap is
left on the screen */
sync_bubble = NULL;
} else {
/* Fix for a tricky race condition
where a bubble fades out in sync
with a synchronous bubble: the symc.
one is still considered visible while
the normal one has triggered this signal.
This ensures the display slot of the
sync. bubble is recycled, and no gap is
left on the screen */
sync_bubble = NULL;
}
stack_layout (stack);
}
return;
}
/* since notification-ids are unsigned integers the first id index is 1, 0 is
** used to indicate an error */
guint
stack_push_bubble (Stack* self,
Bubble* bubble)
{
guint notification_id = -1;
/* sanity check */
if (!self || !IS_BUBBLE (bubble))
return -1;
notification_id = bubble_get_id (bubble);
/* check if this is just an update */
if (find_bubble_by_id (self, notification_id))
{
bubble_start_timer (bubble, TRUE);
bubble_refresh (bubble);
/* resync the synchronous bubble if it's at the top */
if (sync_bubble != NULL
&& bubble_is_visible (sync_bubble))
if (stack_is_at_top_corner (self, sync_bubble))
bubble_sync_with (sync_bubble, bubble);
return notification_id;
}
/* add bubble/id to stack */
if (notification_id == 0)
{
do
{
notification_id = self->next_id++;
} while (find_bubble_by_id (self, notification_id));
}
// FIXME: migrate stack to use abstract notification object and don't
// keep heavy bubble objects around, at anyone time at max. only two
// bubble-objects will be in memory... this will also reduce leak-
// potential
bubble_set_id (bubble, notification_id);
self->list = g_list_append (self->list, (gpointer) bubble);
g_signal_connect (G_OBJECT (bubble),
"timed-out",
G_CALLBACK (close_handler),
self);
/* return current/new id to caller (usually our DBus-dispatcher) */
return notification_id;
}
void
stack_pop_bubble_by_id (Stack* self,
guint id)
{
Bubble* bubble;
/* sanity check */
if (!self)
return;
/* find bubble corresponding to id */
bubble = find_bubble_by_id (self, id);
if (!bubble)
return;
/* close/hide/fade-out bubble */
bubble_hide (bubble);
/* find entry in list corresponding to id and remove it */
self->list = g_list_delete_link (self->list,
find_entry_by_id (self, id));
g_object_unref (bubble);
/* immediately refresh the layout of the stack */
stack_layout (self);
}
static GdkPixbuf*
process_dbus_icon_data (GValue *data)
{
GType dbus_icon_t;
GArray *pixels;
int width, height, rowstride, bits_per_sample, n_channels, size;
gboolean has_alpha;
guchar *copy;
GdkPixbuf *pixbuf = NULL;
g_return_val_if_fail (data != NULL, NULL);
dbus_icon_t = dbus_g_type_get_struct ("GValueArray",
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_BOOLEAN,
G_TYPE_INT,
G_TYPE_INT,
dbus_g_type_get_collection ("GArray",
G_TYPE_UCHAR),
G_TYPE_INVALID);
if (G_VALUE_HOLDS (data, dbus_icon_t))
{
dbus_g_type_struct_get (data,
0, &width,
1, &height,
2, &rowstride,
3, &has_alpha,
4, &bits_per_sample,
5, &n_channels,
6, &pixels,
G_MAXUINT);
size = (height - 1) * rowstride + width *
((n_channels * bits_per_sample + 7) / 8);
copy = (guchar *) g_memdup (pixels->data, size);
pixbuf = gdk_pixbuf_new_from_data(copy, GDK_COLORSPACE_RGB,
has_alpha,
bits_per_sample,
width, height,
rowstride,
(GdkPixbufDestroyNotify)g_free,
NULL);
}
return pixbuf;
}
// control if there are non-default actions requested with this notification
static gboolean
dialog_check_actions_and_timeout (gchar** actions,
gint timeout)
{
int i = 0;
gboolean turn_into_dialog = FALSE;
if (actions != NULL)
{
for (i = 0; actions[i] != NULL; i += 2)
{
if (actions[i+1] == NULL)
{
g_debug ("incorrect action callback "
"with no label");
break;
}
turn_into_dialog = TRUE;
g_debug ("notification request turned into a dialog "
"box, because it contains at least one action "
"callback (%s: \"%s\")",
actions[i],
actions[i+1]);
}
if (timeout == 0)
{
turn_into_dialog = TRUE;
g_debug ("notification request turned into a dialog "
"box, because of its infinite timeout");
}
}
return turn_into_dialog;
}
// FIXME: a intnernal function used for the forcefully-shutdown work-around
// regarding mem-leaks
gboolean
_arm_forced_quit (gpointer data)
{
Stack* stack = NULL;
// sanity check, "disarming" this forced quit
if (!data)
return FALSE;
stack = STACK (data);
// only forcefully quit if the queue is empty
if (g_list_length (stack->list) == 0)
{
gtk_main_quit ();
// I don't think this is ever reached :)
return FALSE;
}
return TRUE;
}
gboolean
stack_notify_handler (Stack* self,
const gchar* app_name,
guint id,
const gchar* icon,
const gchar* summary,
const gchar* body,
gchar** actions,
GHashTable* hints,
gint timeout,
DBusGMethodInvocation* context)
{
Bubble* bubble = NULL;
Bubble* app_bubble = NULL;
GValue* data = NULL;
GValue* compat = NULL;
GdkPixbuf* pixbuf = NULL;
gboolean new_bubble = FALSE;
gboolean turn_into_dialog;
guint real_id;
gchar *sender;
// check max. allowed limit queue-size
if (g_list_length (self->list) > MAX_STACK_SIZE)
{
GError* error = NULL;
error = g_error_new (g_quark_from_string ("notify-osd"),
1,
"Reached stack-limit of %d",
MAX_STACK_SIZE);
dbus_g_method_return_error (context, error);
g_error_free (error);
error = NULL;
return TRUE;
}
// see if pathological actions or timeouts are used by an app issuing a
// notification
turn_into_dialog = dialog_check_actions_and_timeout (actions, timeout);
if (turn_into_dialog)
{
// TODO: apport_report (app_name, summary, actions, timeout);
gchar* sender = dbus_g_method_get_sender (context);
fallback_dialog_show (self->defaults,
sender,
app_name,
id,
summary,
body,
actions);
g_free (sender);
dbus_g_method_return (context, id);
return TRUE;
}
// check if a bubble exists with same id
bubble = find_bubble_by_id (self, id);
sender = dbus_g_method_get_sender (context);
if (bubble)
{
if (g_strcmp0 (bubble_get_sender (bubble), sender) != 0)
{
// Another sender is trying to replace a notification, let's block it!
id = 0;
bubble = NULL;
}
}
if (bubble == NULL)
{
new_bubble = TRUE;
bubble = bubble_new (self->defaults);
g_object_weak_ref (G_OBJECT (bubble),
_weak_notify_cb,
(gpointer) self);
bubble_set_sender (bubble, sender);
bubble_set_id (bubble, id);
}
g_free (sender);
if (new_bubble && hints)
{
data = (GValue*) g_hash_table_lookup (hints, "x-canonical-append");
compat = (GValue*) g_hash_table_lookup (hints, "append");
if ((data && G_VALUE_HOLDS_STRING (data)) ||
(compat && G_VALUE_HOLDS_STRING (compat)))
bubble_set_append (bubble, TRUE);
else
bubble_set_append (bubble, FALSE);
}
if (summary)
bubble_set_title (bubble, summary);
if (body)
bubble_set_message_body (bubble, body);
if (new_bubble && bubble_is_append_allowed(bubble)) {
app_bubble = find_bubble_for_append(self, bubble);
/* Appending to an old bubble */
if (app_bubble != NULL) {
g_object_unref(bubble);
bubble = app_bubble;
if (body) {
bubble_append_message_body (bubble, body);
}
}
}
real_id = bubble_get_id (bubble);
if (hints)
{
data = (GValue*) g_hash_table_lookup (hints, "x-canonical-private-synchronous");
compat = (GValue*) g_hash_table_lookup (hints, "synchronous");
if ((data && G_VALUE_HOLDS_STRING (data)) || (compat && G_VALUE_HOLDS_STRING (compat)))
{
if (sync_bubble != NULL
&& IS_BUBBLE (sync_bubble))
{
g_object_unref (bubble);
bubble = sync_bubble;
bubble_set_title (sync_bubble, summary ? summary : "");
bubble_set_message_body (sync_bubble, body ? body : "");
bubble_set_value (sync_bubble, -2);
bubble_determine_layout (sync_bubble);
}
if (data && G_VALUE_HOLDS_STRING (data))
bubble_set_synchronous (bubble, g_value_get_string (data));
if (compat && G_VALUE_HOLDS_STRING (compat))
bubble_set_synchronous (bubble, g_value_get_string (compat));
}
}
if (hints)
{
data = (GValue*) g_hash_table_lookup (hints, "value");
if (data && G_VALUE_HOLDS_INT (data))
bubble_set_value (bubble, g_value_get_int (data));
}
if (hints)
{
data = (GValue*) g_hash_table_lookup (hints, "urgency");
if (data && G_VALUE_HOLDS_UCHAR (data))
bubble_set_urgency (bubble,
g_value_get_uchar (data));
/* Note: urgency was defined as an enum: LOW, NORMAL, CRITICAL
So, 2 means CRITICAL
*/
}
if (hints)
{
data = (GValue*) g_hash_table_lookup (hints, "x-canonical-private-icon-only");
compat = (GValue*) g_hash_table_lookup (hints, "icon-only");
if ((data && G_VALUE_HOLDS_STRING (data)) || (compat && G_VALUE_HOLDS_STRING (compat)))
bubble_set_icon_only (bubble, TRUE);
else
bubble_set_icon_only (bubble, FALSE);
}
if (hints)
{
if ((data = (GValue*) g_hash_table_lookup (hints, "image_data")))
{
g_debug("Using image_data hint\n");
pixbuf = process_dbus_icon_data (data);
bubble_set_icon_from_pixbuf (bubble, pixbuf);
}
else if ((data = (GValue*) g_hash_table_lookup (hints, "image_path")))
{
g_debug("Using image_path hint\n");
if ((data && G_VALUE_HOLDS_STRING (data)))
bubble_set_icon (bubble, g_value_get_string(data));
else
g_warning ("image_path hint is not a string\n");
}
else if (icon && *icon != '\0')
{
g_debug("Using icon parameter\n");
bubble_set_icon (bubble, icon);
}
else if ((data = (GValue*) g_hash_table_lookup (hints, "icon_data")))
{
g_debug("Using deprecated icon_data hint\n");
pixbuf = process_dbus_icon_data (data);
bubble_set_icon_from_pixbuf (bubble, pixbuf);
}
}
log_bubble_debug (bubble, app_name,
(*icon == '\0' && data != NULL) ?
"..." : icon);
bubble_determine_layout (bubble);
bubble_recalc_size (bubble);
if (bubble_is_synchronous (bubble))
{
stack_display_sync_bubble (self, bubble);
} else {
real_id = stack_push_bubble (self, bubble);
if (! new_bubble && bubble_is_append_allowed (bubble))
log_bubble (bubble, app_name, "appended");
else if (! new_bubble)
log_bubble (bubble, app_name, "replaced");
else
log_bubble (bubble, app_name, "");
/* make sure the sync. bubble is positioned correctly
even for the append case
*/
// no longer needed since we have the two-slots mechanism now
//if (sync_bubble != NULL
// && bubble_is_visible (sync_bubble))
// stack_display_position_sync_bubble (self, sync_bubble);
/* update the layout of the stack;
* this will also open the new bubble */
if (!stack_layout (self))
bubble = NULL;
}
dbus_g_method_return (context, real_id);
// FIXME: this is a temporary work-around, I do not like at all, until
// the heavy memory leakage of notify-osd is fully fixed...
// after a threshold-value is reached, "arm" a forceful shutdown of
// notify-osd (still allowing notifications in the queue, and coming in,
// to be displayed), in order to get the leaked memory freed again, any
// new notifications, coming in after the shutdown, will instruct the
// session to restart notify-osd
if (bubble_get_id (bubble) == FORCED_SHUTDOWN_THRESHOLD)
g_timeout_add (defaults_get_on_screen_timeout (self->defaults),
_arm_forced_quit,
(gpointer) self);
return TRUE;
}
gboolean
stack_close_notification_handler (Stack* self,
guint id,
GError** error)
{
if (id == 0)
g_warning ("%s(): notification id == 0, likely wrong\n",
G_STRFUNC);
Bubble* bubble = find_bubble_by_id (self, id);
// exit but pretend it's ok, for applications
// that call us after an action button was clicked
if (bubble == NULL)
return TRUE;
dbus_send_close_signal (bubble_get_sender (bubble),
bubble_get_id (bubble),
3);
// do not trigger any closure of a notification-bubble here, as
// this kind of control from outside (DBus) does not comply with
// the notify-osd specification
//bubble_hide (bubble);
//g_object_unref (bubble);
//stack_layout (self);
return TRUE;
}
gboolean
stack_get_capabilities (Stack* self,
gchar*** out_caps)
{
*out_caps = g_malloc0 (13 * sizeof(char *));
(*out_caps)[0] = g_strdup ("body");
(*out_caps)[1] = g_strdup ("body-markup");
(*out_caps)[2] = g_strdup ("icon-static");
(*out_caps)[3] = g_strdup ("image/svg+xml");
(*out_caps)[4] = g_strdup ("x-canonical-private-synchronous");
(*out_caps)[5] = g_strdup ("x-canonical-append");
(*out_caps)[6] = g_strdup ("x-canonical-private-icon-only");
(*out_caps)[7] = g_strdup ("x-canonical-truncation");
/* a temp. compatibility-check for the transition time to allow apps a
** grace-period to catch up with the capability- and hint-name-changes
** introduced with notify-osd rev. 224 */
(*out_caps)[8] = g_strdup ("private-synchronous");
(*out_caps)[9] = g_strdup ("append");
(*out_caps)[10] = g_strdup ("private-icon-only");
(*out_caps)[11] = g_strdup ("truncation");
(*out_caps)[12] = NULL;
return TRUE;
}
gboolean
stack_get_server_information (Stack* self,
gchar** out_name,
gchar** out_vendor,
gchar** out_version,
gchar** out_spec_ver)
{
*out_name = g_strdup ("notify-osd");
*out_vendor = g_strdup ("Canonical Ltd");
*out_version = g_strdup ("1.0");
*out_spec_ver = g_strdup ("1.1");
return TRUE;
}
gboolean
stack_is_slot_vacant (Stack* self,
Slot slot)
{
// sanity checks
if (!self || !IS_STACK (self))
return FALSE;
if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
return FALSE;
return self->slots[slot] == NULL ? VACANT : OCCUPIED;
}
// return values of -1 for x and y indicate an error by the caller
void
stack_get_slot_position (Stack* self,
Slot slot,
gint bubble_height,
gint* x,
gint* y)
{
GdkScreen* screen = NULL;
gboolean is_composited = FALSE;
// sanity checks
if (!x && !y)
return;
if (!self || !IS_STACK (self))
{
*x = -1;
*y = -1;
return;
}
if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
{
*x = -1;
*y = -1;
return;
}
// initialize x and y
defaults_get_top_corner (self->defaults, &screen, x, y);
is_composited = gdk_screen_is_composited (screen);
// differentiate returned top-left corner for top and bottom slot
// depending on the placement
switch (defaults_get_gravity (self->defaults))
{
Defaults* d;
case GRAVITY_EAST:
d = self->defaults;
// the position for the sync./feedback bubble
if (slot == SLOT_TOP)
*y += defaults_get_desktop_height (d) / 2 -
EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
bubble_height +
EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d);
// the position for the async. bubble
else if (slot == SLOT_BOTTOM)
*y += defaults_get_desktop_height (d) / 2 +
EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d);
break;
case GRAVITY_NORTH_EAST:
d = self->defaults;
// there's nothing to do for slot == SLOT_TOP as we
// already have correct x and y from the call to
// defaults_get_top_corner() earlier
// this needs to look at the height of the bubble in the
// top slot
if (slot == SLOT_BOTTOM)
{
switch (defaults_get_slot_allocation (d))
{
case SLOT_ALLOCATION_FIXED:
*y += EM2PIXELS (defaults_get_icon_size (d), d) +
2 * EM2PIXELS (defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_bubble_vert_gap (d), d); /* +
2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d);*/
break;
case SLOT_ALLOCATION_DYNAMIC:
g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED);
*y += bubble_get_height (self->slots[SLOT_TOP]) +
EM2PIXELS (defaults_get_bubble_vert_gap (d), d) -
2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d);
break;
default:
break;
}
}
break;
default:
g_warning ("Unhandled placement!\n");
break;
}
}
// call this _before_ the fade-in animation of the bubble starts
gboolean
stack_allocate_slot (Stack* self,
Bubble* bubble,
Slot slot)
{
// sanity checks
if (!self || !IS_STACK (self))
return FALSE;
if (!bubble || !IS_BUBBLE (bubble))
return FALSE;
if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
return FALSE;
if (stack_is_slot_vacant (self, slot))
self->slots[slot] = BUBBLE (g_object_ref ((gpointer) bubble));
else
return FALSE;
return TRUE;
}
// call this _after_ the fade-out animation of the bubble is finished
gboolean
stack_free_slot (Stack* self,
Bubble* bubble)
{
// sanity checks
if (!self || !IS_STACK (self))
return FALSE;
if (!bubble || !IS_BUBBLE (bubble))
return FALSE;
// check top and bottom slots for bubble pointer equality
if (bubble == self->slots[SLOT_TOP])
{
g_object_unref (self->slots[SLOT_TOP]);
self->slots[SLOT_TOP] = NULL;
}
else if (bubble == self->slots[SLOT_BOTTOM])
{
g_object_unref (self->slots[SLOT_BOTTOM]);
self->slots[SLOT_BOTTOM] = NULL;
}
else
return FALSE;
return TRUE;
}
./src/dnd.c 0000644 0000156 0000165 00000012703 12704153542 012603 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** dnd.c - implements the "do not disturb"-mode, e.g. gsmgr, presentations
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "dbus.h"
static DBusGProxy *gsmgr = NULL;
static DBusGProxy *gscrsvr = NULL;
gboolean
dnd_is_xscreensaver_active ()
{
GdkDisplay *display = gdk_display_get_default ();
Atom XA_BLANK =
gdk_x11_get_xatom_by_name_for_display(display, "BLANK");
Atom XA_LOCK =
gdk_x11_get_xatom_by_name_for_display(display, "BLANK");
Atom XA_SCREENSAVER_STATUS =
gdk_x11_get_xatom_by_name_for_display(display,
"_SCREENSAVER_STATUS");
gboolean active = FALSE;
Atom type;
int format;
int status;
unsigned long nitems, bytesafter;
unsigned char* data = NULL;
Display *dpy = gdk_x11_get_default_xdisplay ();
Window win = gdk_x11_get_default_root_xwindow ();
gdk_error_trap_push ();
status = XGetWindowProperty (dpy, win,
XA_SCREENSAVER_STATUS,
0, 999, False, XA_INTEGER,
&type, &format, &nitems, &bytesafter,
(unsigned char **) &data);
gdk_flush ();
gdk_error_trap_pop_ignored ();
if (status == Success
&& type == XA_INTEGER
&& nitems >= 3
&& data != NULL)
{
CARD32* tmp_data = (CARD32*) data;
active = (tmp_data[0] == XA_BLANK || tmp_data[0] == XA_LOCK)
&& ((time_t)tmp_data[1] > (time_t)666000000L);
g_debug ("Screensaver is currently active");
}
if (data != NULL)
free (data);
return active;
}
static DBusGProxy*
get_gnomesession_proxy (void)
{
if (gsmgr == NULL)
{
DBusGConnection *connection = dbus_get_connection ();
gsmgr = dbus_g_proxy_new_for_name (connection,
"org.gnome.SessionManager",
"/org/gnome/SessionManager",
"org.gnome.SessionManager");
}
return gsmgr;
}
gboolean
dnd_is_idle_inhibited ()
{
GError *error = NULL;
gboolean inhibited = FALSE;
guint idle = 8; // 8: Inhibit the session being marked as idle
if (! get_gnomesession_proxy ())
return FALSE;
dbus_g_proxy_call_with_timeout (
gsmgr, "IsInhibited", 2000, &error,
G_TYPE_UINT, idle,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &inhibited,
G_TYPE_INVALID);
if (error)
{
g_warning ("dnd_is_idle_inhibited(): "
"got error \"%s\"\n",
error->message);
g_error_free (error);
error = NULL;
}
if (inhibited)
g_debug ("Session idleness has been inhibited");
return inhibited;
}
static DBusGProxy*
get_screensaver_proxy (void)
{
if (gscrsvr == NULL)
{
DBusGConnection *connection = dbus_get_connection ();
gscrsvr = dbus_g_proxy_new_for_name (connection,
"org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver");
}
return gscrsvr;
}
gboolean
dnd_is_screensaver_active ()
{
GError *error = NULL;
gboolean active = FALSE;;
if (! get_screensaver_proxy ())
return FALSE;
dbus_g_proxy_call_with_timeout (
gscrsvr, "GetActive", 2000, &error,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &active,
G_TYPE_INVALID);
if (error)
{
g_warning ("dnd_is_screensaver_active(): Got error \"%s\"\n",
error->message);
g_error_free (error);
error = NULL;
}
if (active)
g_debug ("Gnome screensaver is active");
return active;
}
static gboolean
dnd_is_online_presence_dnd ()
{
/* TODO: ask FUSA if we're in DND mode */
return FALSE;
}
static int
is_fullscreen_cb (WnckWindow *window, WnckWorkspace *workspace)
{
if (wnck_window_is_visible_on_workspace (window, workspace)
&& wnck_window_is_fullscreen (window))
{
return 0;
} else {
return 1;
}
}
gboolean
dnd_has_one_fullscreen_window (void)
{
gboolean result;
WnckScreen *screen = wnck_screen_get_default ();
wnck_screen_force_update (screen);
WnckWorkspace *workspace = wnck_screen_get_active_workspace (screen);
GList *list = wnck_screen_get_windows (screen);
GList *item = g_list_find_custom (list, workspace, (GCompareFunc) is_fullscreen_cb);
result = item != NULL;
#ifdef HAVE_WNCK_SHUTDOWN
wnck_shutdown ();
#endif
return result;
}
/* Tries to determine whether the user is in "do not disturb" mode */
gboolean
dnd_dont_disturb_user (void)
{
return (dnd_is_online_presence_dnd()
|| dnd_is_xscreensaver_active()
|| dnd_is_screensaver_active()
|| dnd_is_idle_inhibited()
|| dnd_has_one_fullscreen_window()
);
}
./src/stack-blur.h 0000644 0000156 0000165 00000002571 12704153542 014114 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// stack-blur.h - implements stack-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// based on stack-blur algorithm by Mario Klingemann
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _STACK_BLUR_H
#define _STACK_BLUR_H
#include
#include
void
surface_stack_blur (cairo_surface_t* surface,
guint radius);
#endif // _STACK_BLUR_H
./src/raico-blur.h 0000644 0000156 0000165 00000004114 12704153542 014077 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// raico-blur.h - implements public API for blurring cairo image-surfaces
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _RAICO_BLUR_H
#define _RAICO_BLUR_H
#include
#include
typedef enum _raico_blur_quality_t
{
RAICO_BLUR_QUALITY_LOW = 0, // low quality, but fast, maybe interactive
RAICO_BLUR_QUALITY_MEDIUM, // compromise between speed and quality
RAICO_BLUR_QUALITY_HIGH // quality before speed
} raico_blur_quality_t;
typedef struct _raico_blur_private_t raico_blur_private_t;
typedef struct _raico_blur_t
{
raico_blur_private_t* priv;
} raico_blur_t;
raico_blur_t*
raico_blur_create (raico_blur_quality_t quality);
raico_blur_quality_t
raico_blur_get_quality (raico_blur_t* blur);
void
raico_blur_set_quality (raico_blur_t* blur,
raico_blur_quality_t quality);
guint
raico_blur_get_radius (raico_blur_t* blur);
void
raico_blur_set_radius (raico_blur_t* blur,
guint radius);
void
raico_blur_apply (raico_blur_t* blur,
cairo_surface_t* surface);
void
raico_blur_destroy (raico_blur_t* blur);
#endif // _RAICO_BLUR_H
./src/display.c 0000644 0000156 0000165 00000024713 12704153542 013507 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** display.c - manages the display of notifications waiting in the stack/queue
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
/* This is actually part of stack.c, but moved here because it manages
the display of notifications. This is also in preparation for some
refactoring, where we'll create:
* - a distinct (non-graphical) notification.c module
* - a distinct display.c module that takes care of placing bubbles
* on the screen
*/
static Bubble*
stack_find_bubble_on_display (Stack *self)
{
GList* list = NULL;
Bubble* bubble = NULL;
g_assert (IS_STACK (self));
/* find the bubble on display */
for (list = g_list_first (self->list);
list != NULL;
list = g_list_next (list))
{
bubble = (Bubble*) list->data;
if (bubble_is_visible (bubble))
return bubble;
}
return NULL;
}
static gboolean
stack_is_at_top_corner (Stack *self, Bubble *bubble)
{
GdkScreen* screen;
gint x, y1, y2;
g_assert (IS_STACK (self));
g_assert (IS_BUBBLE (bubble));
defaults_get_top_corner (self->defaults, &screen, &x, &y1);
bubble_get_position (bubble, &x, &y2);
return y1 == y2;
}
static void
stack_display_position_sync_bubble (Stack *self, Bubble *bubble)
{
Defaults* d = self->defaults;
GdkScreen* screen;
gint y = 0;
gint x = 0;
defaults_get_top_corner (d, &screen, &x, &y);
// TODO: with multi-head, in focus follow mode, there may be enough
// space left on the top monitor
switch (defaults_get_slot_allocation (d))
{
case SLOT_ALLOCATION_FIXED:
if (stack_is_slot_vacant (self, SLOT_TOP))
{
stack_get_slot_position (self,
SLOT_TOP,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No slot-coords!\n",
G_STRFUNC);
else
stack_allocate_slot (self,
bubble,
SLOT_TOP);
}
else
{
g_warning ("%s(): Top slot taken!\n",
G_STRFUNC);
}
break;
case SLOT_ALLOCATION_DYNAMIC:
// see if we're call at the wrong moment, when both
// slots are occupied by bubbles
if (!stack_is_slot_vacant (self, SLOT_TOP) &&
!stack_is_slot_vacant (self, SLOT_BOTTOM))
{
g_warning ("%s(): Both slots taken!\n",
G_STRFUNC);
}
else
{
// first check if we can place the sync. bubble
// in the top slot and the bottom slot is still
// vacant, this is to avoid the "gap" between
// bottom slot and panel
if (stack_is_slot_vacant (self, SLOT_TOP) &&
stack_is_slot_vacant (self, SLOT_BOTTOM))
{
stack_get_slot_position (self,
SLOT_TOP,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
stack_allocate_slot (self,
bubble,
SLOT_TOP);
}
// next check if top is occupied and bottom is
// still vacant, then place sync. bubble in
// bottom slot
else if (!stack_is_slot_vacant (self,
SLOT_TOP) &&
stack_is_slot_vacant (self,
SLOT_BOTTOM))
{
stack_get_slot_position (self,
SLOT_BOTTOM,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
{
stack_allocate_slot (
self,
bubble,
SLOT_BOTTOM);
bubble_sync_with (
bubble,
self->slots[SLOT_TOP]);
}
}
// this case, top vacant, bottom occupied,
// should never happen for the old placement,
// we want to avoid the "gap" between the bottom
// bubble and the panel
else if (stack_is_slot_vacant (self,
SLOT_TOP) &&
!stack_is_slot_vacant (self,
SLOT_BOTTOM))
{
g_warning ("%s(): Gap, gap, gap!!!\n",
G_STRFUNC);
}
}
break;
default :
g_warning ("Unhandled slot-allocation!\n");
break;
}
bubble_move (bubble, x, y);
}
static void
stack_display_sync_bubble (Stack *self, Bubble *bubble)
{
g_return_if_fail (IS_STACK (self));
g_return_if_fail (IS_BUBBLE (bubble));
bubble_set_timeout (bubble, 2000);
Bubble *other = stack_find_bubble_on_display (self);
if (other != NULL)
{
/* synchronize the sync bubble with
the timeout of the bubble at the bottom */
if (stack_is_at_top_corner (self, bubble))
bubble_sync_with (bubble, other);
else
bubble_sync_with (bubble, other);
bubble_refresh (other);
}
/* is the notification reusing the current bubble? */
if (sync_bubble == bubble)
{
bubble_start_timer (bubble, TRUE);
bubble_refresh (bubble);
return;
}
stack_display_position_sync_bubble (self, bubble);
bubble_fade_in (bubble, 100);
sync_bubble = bubble;
g_signal_connect (G_OBJECT (bubble),
"timed-out",
G_CALLBACK (close_handler),
self);
}
static Bubble*
stack_select_next_to_display (Stack *self)
{
Bubble* next_to_display = NULL;
GList* list = NULL;
Bubble* bubble = NULL;
/* pickup the next bubble to display */
for (list = g_list_first (self->list);
list != NULL;
list = g_list_next (list))
{
bubble = (Bubble*) list->data;
/* sync. bubbles have already been taken care of */
if (bubble_is_synchronous (bubble))
{
g_critical ("synchronous notifications are managed separately");
continue;
}
/* if there is already one bubble on display
we don't have room for another one */
if (bubble_is_visible (bubble))
return NULL;
if (bubble_is_urgent (bubble))
{
/* pick-up the /first/ urgent bubble
in the queue (FIFO) */
return bubble;
}
if (next_to_display == NULL)
next_to_display = bubble;
/* loop, in case there are urgent bubbles waiting higher up
in the stack */
}
return next_to_display;
}
/* Returns true if the next bubble is shown */
static gboolean
stack_layout (Stack* self)
{
Bubble* bubble = NULL;
Defaults* d;
GdkScreen* screen;
gint y = 0;
gint x = 0;
g_return_if_fail (self != NULL);
bubble = stack_select_next_to_display (self);
if (bubble == NULL)
/* this actually happens when we're called for a synchronous
bubble or after a bubble timed out, but there where no other
notifications waiting in the queue */
return FALSE;
if (dnd_dont_disturb_user ()
&& (! bubble_is_urgent (bubble)))
{
guint id = bubble_get_id (bubble);
/* find entry in list corresponding to id and remove it */
self->list =
g_list_delete_link (self->list,
find_entry_by_id (self, id));
g_object_unref (bubble);
/* loop, in case there are other bubbles to discard */
stack_layout (self);
return FALSE;
}
bubble_set_timeout (bubble,
defaults_get_on_screen_timeout (self->defaults));
defaults_get_top_corner (self->defaults, &screen, &x, &y);
d = self->defaults;
switch (defaults_get_slot_allocation (d))
{
case SLOT_ALLOCATION_FIXED:
if (stack_is_slot_vacant (self, SLOT_TOP) &&
bubble_is_synchronous (bubble))
{
stack_get_slot_position (self,
SLOT_TOP,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
stack_allocate_slot (self,
bubble,
SLOT_TOP);
}
else if (stack_is_slot_vacant (self, SLOT_BOTTOM) &&
!bubble_is_synchronous (bubble))
{
stack_get_slot_position (self,
SLOT_BOTTOM,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
stack_allocate_slot (self,
bubble,
SLOT_BOTTOM);
}
else
{
g_warning ("%s(): Error while handling fixed "
"slot-allocation!\n",
G_STRFUNC);
}
break;
case SLOT_ALLOCATION_DYNAMIC:
if (stack_is_slot_vacant (self, SLOT_TOP) &&
stack_is_slot_vacant (self, SLOT_BOTTOM))
{
stack_get_slot_position (self,
SLOT_TOP,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
stack_allocate_slot (self,
bubble,
SLOT_TOP);
}
else if (!stack_is_slot_vacant (self, SLOT_TOP) &&
stack_is_slot_vacant (self, SLOT_BOTTOM))
{
stack_get_slot_position (self,
SLOT_BOTTOM,
bubble_get_height (bubble),
&x,
&y);
if (x == -1 || y == -1)
g_warning ("%s(): No coords!\n",
G_STRFUNC);
else
{
stack_allocate_slot (self,
bubble,
SLOT_BOTTOM);
if (sync_bubble != NULL &&
bubble_is_visible (sync_bubble))
{
// synchronize the sync bubble with the timeout
// of the bubble at the bottom
bubble_sync_with (self->slots[SLOT_TOP],
self->slots[SLOT_BOTTOM]);
}
}
}
else
{
g_warning ("%s(): Error while handling dynamic "
"slot-allocation!\n",
G_STRFUNC);
}
break;
default :
g_warning ("%s(): Unhandled slot-allocation scheme!\n",
G_STRFUNC);
break;
}
bubble_move (bubble, x, y);
/* TODO: adjust timings for bubbles that appear in a serie of bubbles */
if (bubble_is_urgent (bubble))
bubble_fade_in (bubble, 100);
else
bubble_fade_in (bubble, 200);
return TRUE;
}
./src/gaussian-blur.c 0000644 0000156 0000165 00000010644 12704153542 014614 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// raico-blur
//
// gaussian-blur.c - implements gaussian-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// based on filters in libpixman
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include
#include "gaussian-blur.h"
pixman_fixed_t*
create_gaussian_blur_kernel (gint radius,
gdouble sigma,
gint* length)
{
const gdouble scale2 = 2.0f * sigma * sigma;
const gdouble scale1 = 1.0f / (G_PI * scale2);
const gint size = 2 * radius + 1;
const gint n_params = size * size;
pixman_fixed_t* params;
gdouble* tmp;
gdouble sum;
gint x;
gint y;
gint i;
tmp = g_newa (double, n_params);
// caluclate gaussian kernel in floating point format
for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
for (y = -radius; y <= radius; ++y, ++i) {
const gdouble u = x * x;
const gdouble v = y * y;
tmp[i] = scale1 * exp (-(u+v)/scale2);
sum += tmp[i];
}
}
// normalize gaussian kernel and convert to fixed point format
params = g_new (pixman_fixed_t, n_params + 2);
params[0] = pixman_int_to_fixed (size);
params[1] = pixman_int_to_fixed (size);
for (i = 0; i < n_params; ++i)
params[2 + i] = pixman_double_to_fixed (tmp[i] / sum);
if (length)
*length = n_params + 2;
return params;
}
void
_blur_image_surface (cairo_surface_t* surface,
gint radius,
gdouble sigma /* pass 0.0f for auto-calculation */)
{
pixman_fixed_t* params = NULL;
gint n_params;
pixman_image_t* src;
gint w;
gint h;
gint s;
gpointer p;
gdouble radiusf;
radiusf = fabs (radius) + 1.0f;
if (sigma == 0.0f)
sigma = sqrt (-(radiusf * radiusf) / (2.0f * log (1.0f / 255.0f)));
w = cairo_image_surface_get_width (surface);
h = cairo_image_surface_get_height (surface);
s = cairo_image_surface_get_stride (surface);
// create pixman image for cairo image surface
p = cairo_image_surface_get_data (surface);
src = pixman_image_create_bits (PIXMAN_a8r8g8b8, w, h, p, s);
// attach gaussian kernel to pixman image
params = create_gaussian_blur_kernel (radius, sigma, &n_params);
pixman_image_set_filter (src,
PIXMAN_FILTER_CONVOLUTION,
params,
n_params);
g_free (params);
// render blured image to new pixman image
pixman_image_composite (PIXMAN_OP_SRC,
src,
NULL,
src,
0,
0,
0,
0,
0,
0,
w,
h);
pixman_image_unref (src);
}
void
surface_gaussian_blur (cairo_surface_t* surface,
guint radius)
{
cairo_format_t format;
// sanity checks are done in raico-blur.c
// before we mess with the surface execute any pending drawing
cairo_surface_flush (surface);
format = cairo_image_surface_get_format (surface);
switch (format)
{
case CAIRO_FORMAT_ARGB32:
_blur_image_surface (surface, radius, 0.0f);
break;
case CAIRO_FORMAT_RGB24:
// do nothing, for now
break;
case CAIRO_FORMAT_A8:
// do nothing, for now
break;
default :
// do nothing
break;
}
// inform cairo we altered the surfaces contents
cairo_surface_mark_dirty (surface);
}
./src/main.c 0000644 0000156 0000165 00000005104 12704153542 012757 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** main.c - pulling it all together
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#include "defaults.h"
#include "stack.h"
#include "observer.h"
#include "dbus.h"
#include "log.h"
#define ICONS_DIR (DATADIR G_DIR_SEPARATOR_S "notify-osd" G_DIR_SEPARATOR_S "icons")
int
main (int argc,
char** argv)
{
Defaults* defaults = NULL;
Stack* stack = NULL;
Observer* observer = NULL;
DBusGConnection* connection = NULL;
dbus_g_thread_init ();
log_init ();
gtk_init (&argc, &argv);
/* Init some theme/icon stuff */
gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(),
ICONS_DIR);
defaults = defaults_new ();
observer = observer_new ();
stack = stack_new (defaults, observer);
connection = dbus_create_service_instance (DBUS_NAME);
if (connection == NULL)
{
g_warning ("Could not register instance");
stack_del (stack);
return 0;
}
DBusGProxy* proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
dbus_g_proxy_add_signal (proxy, "NameLost", G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (proxy,
"NameLost",
gtk_main_quit,
NULL,
NULL);
dbus_g_connection_register_g_object (connection,
DBUS_PATH,
G_OBJECT (stack));
gtk_main ();
stack_del (stack);
g_object_unref (proxy);
return 0;
}
./src/bubble-window-accessible.c 0000644 0000156 0000165 00000030267 12704153542 016676 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window-accessible.c - implements an accessible bubble window
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include "bubble-window-accessible.h"
#include "bubble.h"
#include
static void bubble_window_accessible_init (BubbleWindowAccessible* object);
static void bubble_window_accessible_finalize (GObject* object);
static void bubble_window_accessible_class_init (BubbleWindowAccessibleClass* klass);
static const char* bubble_window_accessible_get_name (AtkObject* obj);
static const char* bubble_window_accessible_get_description (AtkObject* obj);
static void bubble_window_real_initialize (AtkObject* obj,
gpointer data);
static void atk_value_interface_init (AtkValueIface* iface);
static void atk_text_interface_init (AtkTextIface* iface);
static void bubble_window_get_current_value (AtkValue* obj,
GValue* value);
static void bubble_window_get_maximum_value (AtkValue* obj,
GValue* value);
static void bubble_window_get_minimum_value (AtkValue* obj,
GValue* value);
static void bubble_value_changed_event (Bubble* bubble,
gint value,
AtkObject *obj);
static void bubble_message_body_deleted_event (Bubble* bubble,
const gchar* text,
AtkObject* obj);
static void bubble_message_body_inserted_event (Bubble* bubble,
const gchar* text,
AtkObject* obj);
static gchar* bubble_window_get_text (AtkText *obj,
gint start_offset,
gint end_offset);
static gint bubble_window_get_character_count (AtkText *obj);
static gunichar bubble_window_get_character_at_offset (AtkText *obj,
gint offset);
static void* bubble_window_accessible_parent_class;
G_DEFINE_TYPE_WITH_CODE (BubbleWindowAccessible, bubble_window_accessible, GTK_TYPE_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init))
static void
atk_value_interface_init (AtkValueIface* iface)
{
g_return_if_fail (iface != NULL);
iface->get_current_value = bubble_window_get_current_value;
iface->get_maximum_value = bubble_window_get_maximum_value;
iface->get_minimum_value = bubble_window_get_minimum_value;
}
static void
atk_text_interface_init (AtkTextIface* iface)
{
g_return_if_fail (iface != NULL);
iface->get_text = bubble_window_get_text;
iface->get_character_count = bubble_window_get_character_count;
iface->get_character_at_offset = bubble_window_get_character_at_offset;
}
static void
bubble_window_accessible_init (BubbleWindowAccessible *object)
{
/* TODO: Add initialization code here */
}
static void
bubble_window_accessible_finalize (GObject *object)
{
/* TODO: Add deinitalization code here */
G_OBJECT_CLASS (bubble_window_accessible_parent_class)->finalize (object);
}
static void
bubble_window_accessible_class_init (BubbleWindowAccessibleClass *klass)
{
GObjectClass* object_class = G_OBJECT_CLASS (klass);
AtkObjectClass* class = ATK_OBJECT_CLASS (klass);
bubble_window_accessible_parent_class = g_type_class_peek_parent (klass);
class->get_name = bubble_window_accessible_get_name;
class->get_description = bubble_window_accessible_get_description;
class->initialize = bubble_window_real_initialize;
object_class->finalize = bubble_window_accessible_finalize;
}
static void
bubble_window_real_initialize (AtkObject* obj,
gpointer data)
{
GtkWidget* widget = GTK_WIDGET (data);
Bubble* bubble;
ATK_OBJECT_CLASS (bubble_window_accessible_parent_class)->initialize (obj, data);
bubble = g_object_get_data (G_OBJECT(widget), "bubble");
g_signal_connect (bubble,
"value-changed",
G_CALLBACK (bubble_value_changed_event),
obj);
g_signal_connect (bubble,
"message-body-deleted",
G_CALLBACK (bubble_message_body_deleted_event),
obj);
g_signal_connect (bubble,
"message-body-inserted",
G_CALLBACK (bubble_message_body_inserted_event),
obj);
atk_object_set_role (obj, ATK_ROLE_NOTIFICATION);
}
AtkObject*
bubble_window_accessible_new (GtkWidget *widget)
{
GObject *object;
AtkObject *aobj;
object = g_object_new (BUBBLE_WINDOW_TYPE_ACCESSIBLE, NULL);
aobj = ATK_OBJECT (object);
gtk_accessible_set_widget (GTK_ACCESSIBLE (aobj), widget);
atk_object_initialize (aobj, widget);
return aobj;
}
static const char*
bubble_window_accessible_get_name (AtkObject* obj)
{
GtkWidget* widget;
Bubble* bubble;
const gchar* title;
g_return_val_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj), "");
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return "";
bubble = g_object_get_data (G_OBJECT (widget), "bubble");
g_return_val_if_fail (IS_BUBBLE (bubble), "");
title = bubble_get_title(bubble);
if (g_strcmp0(title, " ") == 0)
{
/* HACK: Titles should never be empty. This solution is extremely wrong.
https://bugs.launchpad.net/notify-osd/+bug/334292 */
const gchar* synch_str;
synch_str = bubble_get_synchronous(bubble);
if (synch_str != NULL)
return synch_str;
else
return "";
}
return title;
}
static const char*
bubble_window_accessible_get_description (AtkObject* obj)
{
GtkWidget *widget;
Bubble *bubble;
g_return_val_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj), "");
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return "";
bubble = g_object_get_data (G_OBJECT (widget), "bubble");
g_return_val_if_fail (IS_BUBBLE (bubble), "");
return bubble_get_message_body(bubble);
}
static void
bubble_window_get_current_value (AtkValue* obj,
GValue* value)
{
gdouble current_value;
GtkWidget* widget;
Bubble* bubble;
g_return_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj));
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return;
bubble = g_object_get_data (G_OBJECT (widget), "bubble");
current_value = (gdouble) bubble_get_value(bubble);
memset (value, 0, sizeof (GValue));
g_value_init (value, G_TYPE_DOUBLE);
g_value_set_double (value,current_value);
}
static void
bubble_window_get_maximum_value (AtkValue* obj,
GValue* value)
{
memset (value, 0, sizeof (GValue));
g_value_init (value, G_TYPE_DOUBLE);
g_value_set_double (value, 100.0);
}
static void
bubble_window_get_minimum_value (AtkValue* obj,
GValue* value)
{
memset (value, 0, sizeof (GValue));
g_value_init (value, G_TYPE_DOUBLE);
g_value_set_double (value, 0.0);
}
static void
bubble_value_changed_event (Bubble* bubble,
gint value,
AtkObject* obj)
{
g_object_notify (G_OBJECT (obj), "accessible-value");
}
static void
bubble_message_body_deleted_event (Bubble* bubble,
const gchar* text,
AtkObject* obj)
{
/* Not getting very fancy here, delete is always complete */
g_signal_emit_by_name (
obj, "text_changed::delete", 0, g_utf8_strlen (text, -1));
}
static void
bubble_message_body_inserted_event (Bubble* bubble,
const gchar* text,
AtkObject* obj)
{
const gchar* message_body;
message_body = bubble_get_message_body (bubble);
g_signal_emit_by_name (
obj, "text_changed::insert",
g_utf8_strlen (message_body, -1) - g_utf8_strlen (text, -1),
g_utf8_strlen (message_body, -1));
}
static gchar*
bubble_window_get_text (AtkText *obj,
gint start_offset,
gint end_offset)
{
GtkWidget* widget;
Bubble* bubble;
const gchar* body_text;
gsize char_length;
glong body_strlen;
g_return_val_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj), g_strdup(""));
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
g_return_val_if_fail (GTK_IS_WINDOW (widget), g_strdup(""));
bubble = g_object_get_data (G_OBJECT(widget), "bubble");
if (end_offset <= start_offset)
return g_strdup("");
body_text = bubble_get_message_body (bubble);
body_strlen = g_utf8_strlen(body_text, -1);
if (start_offset > body_strlen)
start_offset = body_strlen;
if (end_offset > body_strlen || end_offset == -1)
end_offset = body_strlen;
char_length = g_utf8_offset_to_pointer (body_text, end_offset) -
g_utf8_offset_to_pointer (body_text, start_offset);
return g_strndup (g_utf8_offset_to_pointer(body_text, start_offset),
char_length);
}
static gint
bubble_window_get_character_count (AtkText *obj)
{
GtkWidget* widget;
Bubble* bubble;
g_return_val_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj), 0);
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return 0;
bubble = g_object_get_data (G_OBJECT (widget), "bubble");
return g_utf8_strlen(bubble_get_message_body (bubble), -1);
}
static gunichar
bubble_window_get_character_at_offset (AtkText *obj,
gint offset)
{
GtkWidget* widget;
Bubble* bubble;
const gchar* body_text;
g_return_val_if_fail (BUBBLE_WINDOW_IS_ACCESSIBLE (obj), 0);
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
return 0;
bubble = g_object_get_data (G_OBJECT (widget), "bubble");
body_text = bubble_get_message_body (bubble);
return g_utf8_get_char (g_utf8_offset_to_pointer (body_text, offset));
}
./src/Makefile.am 0000644 0000156 0000165 00000004603 12704153542 013726 0 ustar jenkins jenkins NULL =
transform = s/_/-/g
INCLUDES = \
-I. \
-I$(srcdir) \
-I$(top_srcdir) \
$(NULL)
notify_osddir = $(libexecdir)
notify_osd_PROGRAMS = \
notify-osd \
$(NULL)
notify_osd_sources = \
bubble.c \
defaults.c \
dialog.c \
notification.c \
main.c \
observer.c \
stack.c \
dbus.c \
dnd.c \
apport.c \
log.c \
util.c \
timings.c \
stack-blur.c \
exponential-blur.c \
gaussian-blur.c \
raico-blur.c \
tile.c \
bubble-window.c \
bubble-window-accessible.c \
bubble-window-accessible-factory.c \
$(top_srcdir)/egg/egg-fixed.c \
$(top_srcdir)/egg/egg-units.c \
$(top_srcdir)/egg/egg-timeline.c \
$(top_srcdir)/egg/egg-timeout-pool.c \
$(top_srcdir)/egg/egg-alpha.c \
$(top_srcdir)/egg/egg-hack.c \
$(NULL)
notify_osd_headers = \
bubble.h \
defaults.h \
dialog.h \
notification.h \
observer.h \
stack.h \
stack-glue.h \
dbus.h \
dnd.h \
log.h \
apport.h \
util.h \
timings.h \
stack-blur.h \
exponential-blur.h \
gaussian-blur.h \
raico-blur.h \
tile.h \
bubble-window.h \
bubble-window-accessible.h \
bubble-window-accessible-factory.h \
$(top_srcdir)/egg/egg-fixed.h \
$(top_srcdir)/egg/egg-units.h \
$(top_srcdir)/egg/egg-timeline.h \
$(top_srcdir)/egg/egg-timeout-pool.h \
$(top_srcdir)/egg/egg-alpha.h \
$(top_srcdir)/egg/egg-debug.h \
$(top_srcdir)/egg/egg-hack.h \
$(NULL)
notify_osd_SOURCES = \
$(notify_osd_sources) \
$(notify_osd_headers) \
$(NULL)
notify_osd_LDADD = \
$(LIBM) \
$(X_LIBS) \
$(GLIB_LIBS) \
$(GTK_LIBS) \
$(NOTIFY_OSD_LIBS) \
$(DBUS_LIBS) \
$(WNCK_LIBS) \
-lm \
$(NULL)
notify_osd_CFLAGS = \
-DDATADIR=\""$(datadir)"\" \
$(GTK_CFLAGS) \
$(NOTIFY_OSD_CFLAGS) \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
$(WNCK_CFLAGS) \
$(INCLUDES) \
$(NULL)
notify_osd_LDFLAGS = \
-Xlinker -lm -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions \
$(NULL)
# this comes from distutils.sysconfig.get_config_var('LINKFORSHARED')
stack-glue.h: notify-osd.xml Makefile
$(LIBTOOL) --mode=execute $(DBUS_GLIB_BIN)/dbus-binding-tool --prefix=stack --mode=glib-server --output=$@ $<
BUILT_SOURCES = \
stack-glue.h
EXTRA_DIST = \
notify-osd.xml \
dialog.c \
display.c \
$(NULL)
dist-hook:
cd $(distdir) ; rm -f $(CLEANFILES)
DISTCLEANFILES = $(BUILT_SOURCES)
./src/log.c 0000644 0000156 0000165 00000007065 12704153542 012624 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** log.h - log utils
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** Contributor(s):
** Sense "qense" Hofstede (fix LP: #465801, rev. 415)
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include "config.h"
#include
#include
#include
#include
#include "bubble.h"
static FILE *logfile = NULL;
static void
log_logger_null(const char *domain,
GLogLevelFlags log_level,
const char *message,
gpointer user_data)
{
return;
}
void
log_init (void)
{
if (! g_getenv ("LOG"))
return;
const char *homedir = g_getenv ("HOME");
if (!homedir)
homedir = g_get_home_dir ();
g_return_if_fail (homedir != NULL);
// Make sure the cache directory is there, if at all possible
const gchar *dirname = g_get_user_cache_dir ();
g_mkdir_with_parents (dirname, 0700);
char *filename = g_build_filename (dirname, "notify-osd.log", NULL);
logfile = fopen (filename, "w");
if (logfile == NULL)
g_warning ("could not open/append to %s; logging disabled",
filename);
g_free (filename);
/* discard all debug messages unless DEBUG is set */
if (! g_getenv ("DEBUG"))
g_log_set_handler (NULL,
G_LOG_LEVEL_MESSAGE
| G_LOG_FLAG_FATAL
| G_LOG_FLAG_RECURSION,
log_logger_null, NULL);
g_message ("DEBUG mode enabled");
}
char*
log_create_timestamp (void)
{
struct timeval tv;
struct tm *tm;
/* FIXME: deal with tz offsets */
gettimeofday (&tv, NULL);
tm = localtime (&tv.tv_sec);
return g_strdup_printf ("%.4d-%.2d-%.2dT%.2d:%.2d:%.2d%.1s%.2d:%.2d",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
"-", 0, 0);
}
void
log_bubble (Bubble *bubble, const char *app_name, const char *option)
{
g_return_if_fail (IS_BUBBLE (bubble));
if (logfile == NULL)
return;
char *ts = log_create_timestamp ();
if (option)
fprintf (logfile, "[%s, %s %s] %s\n",
ts, app_name, option,
bubble_get_title (bubble));
else
fprintf (logfile, "[%s, %s] %s\n",
ts, app_name,
bubble_get_title (bubble));
fprintf (logfile, "%s\n\n",
bubble_get_message_body (bubble));
fflush (logfile);
g_free (ts);
}
void
log_bubble_debug (Bubble *bubble, const char *app_name, const char *icon)
{
g_return_if_fail (bubble != NULL && IS_BUBBLE (bubble));
char *ts = log_create_timestamp ();
g_debug ("[%s, %s, id:%d, icon:%s%s] %s\n%s\n",
ts, app_name, bubble_get_id (bubble), icon,
bubble_is_synchronous (bubble) ? " (synchronous)" : "",
bubble_get_title (bubble),
bubble_get_message_body (bubble));
g_free (ts);
}
./src/exponential-blur.c 0000644 0000156 0000165 00000014227 12704153542 015331 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// raico-blur
//
// exponential-blur.c - implements exponential-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
// Jason Smith
//
// Notes:
// based on exponential-blur algorithm by Jani Huhtanen
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
// FIXME: not working yet, unfinished
#include
#include "exponential-blur.h"
static inline void
_blurinner (guchar* pixel,
gint *zR,
gint *zG,
gint *zB,
gint *zA,
gint alpha,
gint aprec,
gint zprec);
static inline void
_blurrow (guchar* pixels,
gint width,
gint height,
gint channels,
gint line,
gint alpha,
gint aprec,
gint zprec);
static inline void
_blurcol (guchar* pixels,
gint width,
gint height,
gint channels,
gint col,
gint alpha,
gint aprec,
gint zprec);
void
_expblur (guchar* pixels,
gint width,
gint height,
gint channels,
gint radius,
gint aprec,
gint zprec);
void
surface_exponential_blur (cairo_surface_t* surface,
guint radius)
{
guchar* pixels;
guint width;
guint height;
cairo_format_t format;
// sanity checks are done in raico-blur.c
// before we mess with the surface execute any pending drawing
cairo_surface_flush (surface);
pixels = cairo_image_surface_get_data (surface);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
format = cairo_image_surface_get_format (surface);
switch (format)
{
case CAIRO_FORMAT_ARGB32:
_expblur (pixels, width, height, 4, radius, 16, 7);
break;
case CAIRO_FORMAT_RGB24:
_expblur (pixels, width, height, 3, radius, 16, 7);
break;
case CAIRO_FORMAT_A8:
_expblur (pixels, width, height, 1, radius, 16, 7);
break;
default :
// do nothing
break;
}
// inform cairo we altered the surfaces contents
cairo_surface_mark_dirty (surface);
}
//
// pixels image-data
// width image-width
// height image-height
// channels image-channels
//
// in-place blur of image 'img' with kernel of approximate radius 'radius'
//
// blurs with two sided exponential impulse response
//
// aprec = precision of alpha parameter in fixed-point format 0.aprec
//
// zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
//
void
_expblur (guchar* pixels,
gint width,
gint height,
gint channels,
gint radius,
gint aprec,
gint zprec)
{
gint alpha;
gint row = 0;
gint col = 0;
if (radius < 1)
return;
// calculate the alpha such that 90% of
// the kernel is within the radius.
// (Kernel extends to infinity)
alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
for (; row < height; row++)
_blurrow (pixels,
width,
height,
channels,
row,
alpha,
aprec,
zprec);
for(; col < width; col++)
_blurcol (pixels,
width,
height,
channels,
col,
alpha,
aprec,
zprec);
return;
}
static inline void
_blurinner (guchar* pixel,
gint *zR,
gint *zG,
gint *zB,
gint *zA,
gint alpha,
gint aprec,
gint zprec)
{
gint R;
gint G;
gint B;
guchar A;
R = *pixel;
G = *(pixel + 1);
B = *(pixel + 2);
A = *(pixel + 3);
*zR += (alpha * ((R << zprec) - *zR)) >> aprec;
*zG += (alpha * ((G << zprec) - *zG)) >> aprec;
*zB += (alpha * ((B << zprec) - *zB)) >> aprec;
*zA += (alpha * ((A << zprec) - *zA)) >> aprec;
*pixel = *zR >> zprec;
*(pixel + 1) = *zG >> zprec;
*(pixel + 2) = *zB >> zprec;
*(pixel + 3) = *zA >> zprec;
}
static inline void
_blurrow (guchar* pixels,
gint width,
gint height,
gint channels,
gint line,
gint alpha,
gint aprec,
gint zprec)
{
gint zR;
gint zG;
gint zB;
gint zA;
gint index;
guchar* scanline;
scanline = &(pixels[line * width * channels]);
zR = *scanline << zprec;
zG = *(scanline + 1) << zprec;
zB = *(scanline + 2) << zprec;
zA = *(scanline + 3) << zprec;
for (index = 0; index < width; index ++)
_blurinner (&scanline[index * channels],
&zR,
&zG,
&zB,
&zA,
alpha,
aprec,
zprec);
for (index = width - 2; index >= 0; index--)
_blurinner (&scanline[index * channels],
&zR,
&zG,
&zB,
&zA,
alpha,
aprec,
zprec);
}
static inline void
_blurcol (guchar* pixels,
gint width,
gint height,
gint channels,
gint x,
gint alpha,
gint aprec,
gint zprec)
{
gint zR;
gint zG;
gint zB;
gint zA;
gint index;
guchar* ptr;
ptr = pixels;
ptr += x * channels;
zR = *((guchar*) ptr ) << zprec;
zG = *((guchar*) ptr + 1) << zprec;
zB = *((guchar*) ptr + 2) << zprec;
zA = *((guchar*) ptr + 3) << zprec;
for (index = width; index < (height - 1) * width; index += width)
_blurinner ((guchar*) &ptr[index * channels],
&zR,
&zG,
&zB,
&zA,
alpha,
aprec,
zprec);
for (index = (height - 2) * width; index >= 0; index -= width)
_blurinner ((guchar*) &ptr[index * channels],
&zR,
&zG,
&zB,
&zA,
alpha,
aprec,
zprec);
}
./src/timings.c 0000644 0000156 0000165 00000026455 12704153542 013521 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// timings.c - timings object handling duration and max. on-screen time
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include "timings.h"
G_DEFINE_TYPE (Timings, timings, G_TYPE_OBJECT);
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), TIMINGS_TYPE, TimingsPrivate))
struct _TimingsPrivate {
GTimer* on_screen_timer;
GTimer* duration_timer;
GTimer* paused_timer;
guint timeout_id;
guint max_timeout_id;
guint scheduled_duration; // value interpreted as milliseconds
guint max_duration; // value interpreted as milliseconds
gboolean is_started;
gboolean is_paused;
};
enum
{
COMPLETED,
LIMIT_REACHED,
LAST_SIGNAL
};
//-- private functions ---------------------------------------------------------
static guint g_timings_signals[LAST_SIGNAL] = { 0 };
guint
_ms_elapsed (GTimer* timer)
{
gulong microseconds;
gulong milliseconds;
gdouble duration;
gdouble seconds;
// sanity check
g_assert (timer != NULL);
// get elapsed time
duration = g_timer_elapsed (timer, µseconds);
// convert result to milliseconds ...
milliseconds = microseconds / 1000;
modf (duration, &seconds);
// ... and return it
return seconds * 1000 + milliseconds;
}
gboolean
_emit_completed (gpointer data)
{
Timings* t;
if (!data)
return TRUE;
t = (Timings*) data;
if (!t || !IS_TIMINGS (t))
return TRUE;
g_signal_emit (t, g_timings_signals[COMPLETED], 0);
return FALSE;
}
gboolean
_emit_limit_reached (gpointer data)
{
Timings* t;
if (!data)
return TRUE;
t = (Timings*) data;
if (!t || !IS_TIMINGS (t))
return TRUE;
g_signal_emit (t, g_timings_signals[LIMIT_REACHED], 0);
return FALSE;
}
void
_debug_output (TimingsPrivate* priv)
{
if (g_getenv ("DEBUG"))
{
g_print ("\non-screen time: %d seconds, %d ms.\n",
_ms_elapsed (priv->on_screen_timer) / 1000,
_ms_elapsed (priv->on_screen_timer) % 1000);
g_print ("paused time : %d seconds, %d ms.\n",
_ms_elapsed (priv->paused_timer) / 1000,
_ms_elapsed (priv->paused_timer) % 1000);
g_print ("unpaused time : %d seconds, %d ms.\n",
_ms_elapsed (priv->duration_timer) / 1000,
_ms_elapsed (priv->duration_timer) % 1000);
g_print ("scheduled time: %d seconds, %d ms.\n",
priv->scheduled_duration / 1000,
priv->scheduled_duration % 1000);
}
}
//-- internal functions --------------------------------------------------------
// this is what gets called if one does g_object_unref(bla)
static void
timings_dispose (GObject* gobject)
{
Timings* t;
TimingsPrivate* priv;
// sanity checks
g_assert (gobject);
t = TIMINGS (gobject);
g_assert (t);
g_assert (IS_TIMINGS (t));
priv = GET_PRIVATE (t);
g_assert (priv);
// free any allocated resources
if (priv->on_screen_timer)
{
g_timer_destroy (priv->on_screen_timer);
priv->on_screen_timer = NULL;
}
if (priv->duration_timer)
{
g_timer_destroy (priv->duration_timer);
priv->duration_timer = NULL;
}
if (priv->paused_timer)
{
g_timer_destroy (priv->paused_timer);
priv->paused_timer = NULL;
}
if (priv->timeout_id != 0)
{
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
}
if (priv->max_timeout_id != 0)
{
g_source_remove (priv->max_timeout_id);
priv->max_timeout_id = 0;
}
// chain up to the parent class
G_OBJECT_CLASS (timings_parent_class)->dispose (gobject);
}
static void
timings_finalize (GObject* gobject)
{
// chain up to the parent class
G_OBJECT_CLASS (timings_parent_class)->finalize (gobject);
}
static void
timings_init (Timings* self)
{
// If you need specific construction properties to complete
// initialization, delay initialization completion until the
// property is set.
}
static void
timings_get_property (GObject* gobject,
guint prop,
GValue* value,
GParamSpec* spec)
{
switch (prop)
{
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
timings_class_init (TimingsClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (TimingsPrivate));
gobject_class->dispose = timings_dispose;
gobject_class->finalize = timings_finalize;
gobject_class->get_property = timings_get_property;
g_timings_signals[COMPLETED] = g_signal_new (
"completed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (TimingsClass, completed),
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
g_timings_signals[LIMIT_REACHED] = g_signal_new (
"limit-reached",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (TimingsClass, limit_reached),
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
}
//-- public functions ----------------------------------------------------------
Timings*
timings_new (guint scheduled_duration,
guint max_duration)
{
Timings* this;
TimingsPrivate* priv;
// verify the caller is not stupid
if (scheduled_duration > max_duration)
return NULL;
this = g_object_new (TIMINGS_TYPE, NULL);
if (!this)
return NULL;
priv = GET_PRIVATE (this);
priv->on_screen_timer = g_timer_new ();
g_timer_stop (priv->on_screen_timer);
priv->duration_timer = g_timer_new ();
g_timer_stop (priv->duration_timer);
priv->paused_timer = g_timer_new ();
g_timer_stop (priv->paused_timer);
priv->scheduled_duration = scheduled_duration;
priv->max_duration = max_duration;
priv->is_started = FALSE;
priv->is_paused = FALSE;
return this;
}
gboolean
timings_start (Timings* t)
{
TimingsPrivate* priv;
// sanity checks
if (!t)
return FALSE;
priv = GET_PRIVATE (t);
if (!priv)
return FALSE;
// if we have been started already return early
if (priv->is_started)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Already started!\n");
return FALSE;
}
// install and start the two timeout-handlers
priv->timeout_id = g_timeout_add (priv->scheduled_duration,
_emit_completed,
(gpointer) t);
priv->max_timeout_id = g_timeout_add (priv->max_duration,
_emit_limit_reached,
(gpointer) t);
// let the on-screen- and duration-timers tick
g_timer_continue (priv->on_screen_timer);
g_timer_continue (priv->duration_timer);
// indicate that we started
priv->is_started = TRUE;
return TRUE;
}
gboolean
timings_stop (Timings* t)
{
TimingsPrivate* priv;
// sanity checks
if (!t)
return FALSE;
priv = GET_PRIVATE (t);
if (!priv)
return FALSE;
// if we have not been started, return early
if (!priv->is_started)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Can't stop something, which "
"is not started yet!\n");
return FALSE;
}
// get rid of timeouts
if (!priv->is_paused)
{
// remove timeout for normal scheduled duration
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
}
// remove timeout enforcing max. time-limit
g_source_remove (priv->max_timeout_id);
priv->max_timeout_id = 0;
// halt all timers
if (priv->is_paused)
g_timer_stop (priv->paused_timer);
else
{
g_timer_stop (priv->on_screen_timer);
g_timer_stop (priv->duration_timer);
}
// indicate that we stopped (means also not paused)
priv->is_started = FALSE;
priv->is_paused = FALSE;
// spit out some debugging information
_debug_output (priv);
return TRUE;
}
gboolean
timings_pause (Timings* t)
{
TimingsPrivate* priv;
// sanity checks
if (!t)
return FALSE;
priv = GET_PRIVATE (t);
if (!priv)
return FALSE;
// only if we have been started it makes sense pause
if (!priv->is_started)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Can't pause something, which "
" is not started yet!\n");
return FALSE;
}
// don't halt if we are already paused
if (priv->is_paused)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Already paused!\n");
return FALSE;
}
// make paused-timer tick again, hold duration-timer and update flag
g_timer_continue (priv->paused_timer);
g_timer_stop (priv->duration_timer);
priv->is_paused = TRUE;
// get rid of old timeout
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
return TRUE;
}
gboolean
timings_continue (Timings* t)
{
TimingsPrivate* priv;
guint extension;
// sanity checks
if (!t)
return FALSE;
priv = GET_PRIVATE (t);
if (!priv)
return FALSE;
// only if we have been started it makes sense to move on
if (!priv->is_started)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Can't continue something, "
"which is not started yet!\n");
return FALSE;
}
// don't continue if we are not paused
if (!priv->is_paused)
{
if (g_getenv ("DEBUG"))
g_print ("\n*** WARNING: Already running!\n");
return FALSE;
}
// make duration-timer tick again, hold paused-timer and update flag
g_timer_continue (priv->duration_timer);
g_timer_stop (priv->paused_timer);
priv->is_paused = FALSE;
// put new timeout in place
extension = priv->scheduled_duration -
_ms_elapsed (priv->duration_timer);
priv->timeout_id = g_timeout_add (extension,
_emit_completed,
(gpointer) t);
g_assert (priv->timeout_id != 0);
return TRUE;
}
gboolean
timings_extend (Timings* t,
guint extension)
{
TimingsPrivate* priv;
guint on_screen_time; // value interpreted as milliseconds
// sanity checks
if (!t)
return FALSE;
priv = GET_PRIVATE (t);
if (!priv)
return FALSE;
// you never know how stupid the caller may be
if (extension == 0)
return FALSE;
// only if we have been started we can extend
if (!priv->is_started)
return FALSE;
// if paused only update scheduled duration and return
if (priv->is_paused)
{
if (priv->scheduled_duration + extension >
priv->max_duration)
priv->scheduled_duration = priv->max_duration;
else
priv->scheduled_duration += extension;
return TRUE;
}
// get rid of old timeout
g_source_remove (priv->timeout_id);
// ensure we don't overshoot limit with the on-screen time
on_screen_time = _ms_elapsed (priv->duration_timer);
if (priv->scheduled_duration + extension > priv->max_duration)
{
extension = priv->max_duration - on_screen_time;
priv->scheduled_duration = priv->max_duration;
}
else
{
priv->scheduled_duration += extension;
extension = priv->scheduled_duration - on_screen_time;
}
// add new timeout
priv->timeout_id = g_timeout_add (extension,
_emit_completed,
(gpointer) t);
return TRUE;
}
./src/dbus.c 0000644 0000156 0000165 00000007617 12704153542 013003 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** dbus.c - dbus boiler-plate code for talking with libnotify
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include "dbus.h"
static DBusGConnection* connection = NULL;
DBusGConnection*
dbus_get_connection (void)
{
/* usefull mostly for unit tests */
if (connection == NULL)
connection = dbus_create_service_instance (DBUS_NAME);
return connection;
}
DBusGConnection*
dbus_create_service_instance (const char *service_name)
{
DBusGProxy* proxy = NULL;
guint request_name_result;
GError* error = NULL;
error = NULL;
connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
if (error)
{
g_warning ("dbus_create_service_instance(): "
"Got error \"%s\"\n",
error->message);
g_error_free (error);
return NULL;
}
proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
error = NULL;
if (!dbus_g_proxy_call (proxy,
"RequestName",
&error,
G_TYPE_STRING, service_name,
G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID))
{
g_warning ("dbus_create_service_instance(): "
"Got error \"%s\"\n",
error->message);
g_error_free (error);
g_object_unref (proxy);
return NULL;
}
g_object_unref (proxy);
if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
g_warning ("Another instance has already registered %s", service_name);
return NULL;
}
return connection;
}
void
dbus_send_close_signal (gchar *dest,
guint id,
guint reason)
{
DBusMessage *msg;
msg = dbus_message_new_signal ("/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"NotificationClosed");
dbus_message_set_destination (msg, dest);
dbus_message_append_args (msg, DBUS_TYPE_UINT32, &id,
DBUS_TYPE_INVALID);
dbus_message_append_args (msg, DBUS_TYPE_UINT32, &reason,
DBUS_TYPE_INVALID);
dbus_connection_send (dbus_g_connection_get_connection (connection),
msg,
NULL);
dbus_message_unref (msg);
}
void
dbus_send_action_signal (gchar *dest,
guint id,
const char *action_key)
{
DBusMessage *msg;
msg = dbus_message_new_signal ("/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"ActionInvoked");
dbus_message_set_destination (msg, dest);
dbus_message_append_args (msg, DBUS_TYPE_UINT32, &id,
DBUS_TYPE_INVALID);
dbus_message_append_args (msg, DBUS_TYPE_STRING, &action_key,
DBUS_TYPE_INVALID);
dbus_connection_send (dbus_g_connection_get_connection (connection),
msg,
NULL);
dbus_message_unref (msg);
}
./src/tile.h 0000644 0000156 0000165 00000003602 12704153542 012776 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// tile.h - implements public API surface/blur cache
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _TILE_H
#define _TILE_H
#include
#include
typedef struct _tile_private_t tile_private_t;
typedef struct _tile_t
{
tile_private_t* priv;
} tile_t;
tile_t*
tile_new (cairo_surface_t* source,
guint blur_radius);
tile_t*
tile_new_for_padding (cairo_surface_t* normal,
cairo_surface_t* blurred,
gint width,
gint height);
void
tile_destroy (tile_t* tile);
void
tile_paint (tile_t* tile,
cairo_t* cr,
gdouble x,
gdouble y,
gdouble normal_alpha,
gdouble blurred_alpha);
void
tile_paint_with_padding (tile_t* tile,
cairo_t* cr,
gdouble x,
gdouble y,
gdouble width,
gdouble height,
gdouble normal_alpha,
gdouble blurred_alpha);
#endif // _TILE_H
./src/notify-osd.xml 0000644 0000156 0000165 00000003252 12704153542 014506 0 ustar jenkins jenkins
./src/apport.h 0000644 0000156 0000165 00000002671 12704153542 013353 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** apport.h - apport hooks for triggering bug-reports on non-spec notifications
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
/* this module should send a report via apport when an application
is trying to use elements of the spec we don't support anymore
*/
void
apport_report (const gchar* app_name,
const gchar* summary,
gchar** actions,
gint timeout);
./src/observer.c 0000644 0000156 0000165 00000010702 12704153542 013662 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** observer.c - meant to be a singelton watching for mouse-over-bubble cases
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include "observer.h"
G_DEFINE_TYPE (Observer, observer, G_TYPE_OBJECT);
enum
{
PROP_DUMMY = 0,
PROP_X,
PROP_Y
};
/*-- internal API ------------------------------------------------------------*/
static void
observer_dispose (GObject* gobject)
{
/* chain up to the parent class */
G_OBJECT_CLASS (observer_parent_class)->dispose (gobject);
}
static void
observer_finalize (GObject* gobject)
{
/* chain up to the parent class */
G_OBJECT_CLASS (observer_parent_class)->finalize (gobject);
}
static void
observer_init (Observer* self)
{
/* this should not be here, but I don't know yet how do deal with
** the distinction between class-members and instance-members
** also I do not know if an instance can have properties too or
** only a class */
self->window = NULL;
self->timeout_frequency = 0;
self->timeout_id = 0;
self->pointer_x = 0;
self->pointer_y = 0;
/* If you need specific construction properties to complete
** initialization, delay initialization completion until the
** property is set. */
}
static void
observer_get_property (GObject* gobject,
guint prop,
GValue* value,
GParamSpec* spec)
{
Observer* observer;
observer = OBSERVER (gobject);
switch (prop)
{
case PROP_X:
g_value_set_int (value, observer->pointer_x);
break;
case PROP_Y:
g_value_set_int (value, observer->pointer_y);
break;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
observer_set_property (GObject* gobject,
guint prop,
const GValue* value,
GParamSpec* spec)
{
Observer* observer;
observer = OBSERVER (gobject);
switch (prop)
{
case PROP_X:
observer->pointer_x = g_value_get_int (value);
break;
case PROP_Y:
observer->pointer_y = g_value_get_int (value);
break;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
observer_class_init (ObserverClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
GParamSpec* property_x;
GParamSpec* property_y;
gobject_class->dispose = observer_dispose;
gobject_class->finalize = observer_finalize;
gobject_class->get_property = observer_get_property;
gobject_class->set_property = observer_set_property;
property_x = g_param_spec_int (
"pointer-x",
"pointer-x",
"X-coord. of mouse pointer",
0,
4096,
0,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_X,
property_x);
property_y = g_param_spec_int (
"pointer-y",
"pointer-y",
"Y-coord. of mouse pointer",
0,
4096,
0,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_Y,
property_y);
}
/*-- public API --------------------------------------------------------------*/
Observer*
observer_new (void)
{
Observer* this = g_object_new (OBSERVER_TYPE, NULL);
return this;
}
void
observer_del (Observer* self)
{
g_object_unref (self);
}
gint
observer_get_x (Observer* self)
{
gint x;
g_object_get (self, "pointer-x", &x, NULL);
return x;
}
gint
observer_get_y (Observer* self)
{
gint y;
g_object_get (self, "pointer-y", &y, NULL);
return y;
}
./src/timings.h 0000644 0000156 0000165 00000004663 12704153542 013523 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// timings.h - timings object handling duration and max. on-screen time
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef __TIMINGS_H
#define __TIMINGS_H
#include
G_BEGIN_DECLS
#define TIMINGS_TYPE (timings_get_type ())
#define TIMINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIMINGS_TYPE, Timings))
#define TIMINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIMINGS_TYPE, TimingsClass))
#define IS_TIMINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIMINGS_TYPE))
#define IS_TIMINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIMINGS_TYPE))
#define TIMINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIMINGS_TYPE, TimingsClass))
typedef struct _Timings Timings;
typedef struct _TimingsClass TimingsClass;
typedef struct _TimingsPrivate TimingsPrivate;
// instance structure
struct _Timings
{
GObject parent;
//< private >
TimingsPrivate* priv;
};
// class structure
struct _TimingsClass
{
GObjectClass parent;
//< signals >
void (*completed) (Timings* timings);
void (*limit_reached) (Timings* timings);
};
GType timings_get_type (void);
Timings*
timings_new (guint scheduled_duration,
guint max_duration);
gboolean
timings_start (Timings* t);
gboolean
timings_stop (Timings* t);
gboolean
timings_pause (Timings* t);
gboolean
timings_continue (Timings* t);
gboolean
timings_extend (Timings* t,
guint extension);
G_END_DECLS
#endif // __TIMINGS_H
./src/log.h 0000644 0000156 0000165 00000002673 12704153542 012631 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** log.h - log utils
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __NOTIFY_OSD_LOG_H
#define __NOTIFY_OSD_LOG_H
G_BEGIN_DECLS
void
log_init (void);
void
log_bubble (Bubble *bubble, const char *app_name, const char *option);
char*
log_create_timestamp (void);
void
log_bubble_debug (Bubble *bubble, const char *app_name, const char *icon);
G_END_DECLS
#endif /* __NOTIFY_OSD_LOG_H */
./src/util.h 0000644 0000156 0000165 00000003146 12704153542 013021 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** util.h - all sorts of helper functions
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Cody Russell
** Mirco "MacSlow" Mueller
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#define WM_NAME_COMPIZ "compiz"
#define WM_NAME_METACITY "Metacity"
#define WM_NAME_XFCE "Xfwm4"
#define WM_NAME_KWIN "KWin"
#define WM_NAME_XMONAD "xmonad"
gchar*
filter_text (const gchar* text);
gchar*
newline_to_space (const gchar* text);
cairo_surface_t*
copy_surface (cairo_surface_t* orig);
gchar*
get_wm_name (Display* dpy);
GString*
extract_font_face (const gchar* string);
./src/defaults.c 0000644 0000156 0000165 00000136563 12704153542 013660 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** defaults.c - a singelton providing all default values for sizes, colors etc.
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** Contributor(s):
** Chow Loong Jin (fix for LP: #401809, rev. 349)
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include "defaults.h"
#include "util.h"
G_DEFINE_TYPE (Defaults, defaults, G_TYPE_OBJECT);
enum
{
PROP_DUMMY = 0,
PROP_DESKTOP_BOTTOM_GAP,
PROP_STACK_HEIGHT,
PROP_BUBBLE_VERT_GAP,
PROP_BUBBLE_HORZ_GAP,
PROP_BUBBLE_WIDTH,
PROP_BUBBLE_MIN_HEIGHT,
PROP_BUBBLE_MAX_HEIGHT,
PROP_BUBBLE_SHADOW_SIZE,
PROP_BUBBLE_SHADOW_COLOR,
PROP_BUBBLE_BG_COLOR,
PROP_BUBBLE_BG_OPACITY,
PROP_BUBBLE_HOVER_OPACITY,
PROP_BUBBLE_CORNER_RADIUS,
PROP_CONTENT_SHADOW_SIZE,
PROP_CONTENT_SHADOW_COLOR,
PROP_MARGIN_SIZE,
PROP_ICON_SIZE,
PROP_GAUGE_SIZE,
PROP_GAUGE_OUTLINE_WIDTH,
PROP_FADE_IN_TIMEOUT,
PROP_FADE_OUT_TIMEOUT,
PROP_ON_SCREEN_TIMEOUT,
PROP_TEXT_FONT_FACE,
PROP_TEXT_TITLE_COLOR,
PROP_TEXT_TITLE_WEIGHT,
PROP_TEXT_TITLE_SIZE,
PROP_TEXT_BODY_COLOR,
PROP_TEXT_BODY_WEIGHT,
PROP_TEXT_BODY_SIZE,
PROP_PIXELS_PER_EM,
PROP_SYSTEM_FONT_SIZE,
PROP_SCREEN_DPI,
PROP_GRAVITY
};
enum
{
VALUE_CHANGED,
GRAVITY_CHANGED,
LAST_SIGNAL
};
enum
{
R = 0,
G,
B
};
/* taking hints from Pango here, Qt looks a bit different*/
enum
{
TEXT_WEIGHT_LIGHT = 300, /* QFont::Light 25 */
TEXT_WEIGHT_NORMAL = 400, /* QFont::Normal 50 */
TEXT_WEIGHT_BOLD = 700 /* QFont::Bold 75 */
};
/* these values are interpreted as em-measurements and do comply to the
* visual guide for jaunty-notifications */
#define DEFAULT_DESKTOP_BOTTOM_GAP 6.0f
#define DEFAULT_BUBBLE_WIDTH 24.0f
#define DEFAULT_BUBBLE_MIN_HEIGHT 5.0f
#define DEFAULT_BUBBLE_MAX_HEIGHT 12.2f
#define DEFAULT_BUBBLE_VERT_GAP 0.5f
#define DEFAULT_BUBBLE_HORZ_GAP 0.5f
#define DEFAULT_BUBBLE_SHADOW_SIZE 0.7f
#define DEFAULT_BUBBLE_SHADOW_COLOR "#000000"
#define DEFAULT_BUBBLE_BG_COLOR "#131313"
#define DEFAULT_BUBBLE_BG_OPACITY "#cc"
#define DEFAULT_BUBBLE_HOVER_OPACITY "#66"
#define DEFAULT_BUBBLE_CORNER_RADIUS 0.375f
#define DEFAULT_CONTENT_SHADOW_SIZE 0.125f
#define DEFAULT_CONTENT_SHADOW_COLOR "#000000"
#define DEFAULT_MARGIN_SIZE 1.0f
#define DEFAULT_ICON_SIZE 3.0f
#define DEFAULT_GAUGE_SIZE 0.625f
#define DEFAULT_GAUGE_OUTLINE_WIDTH 0.125f
#define DEFAULT_TEXT_FONT_FACE "Sans"
#define DEFAULT_TEXT_TITLE_COLOR "#ffffff"
#define DEFAULT_TEXT_TITLE_WEIGHT TEXT_WEIGHT_BOLD
#define DEFAULT_TEXT_TITLE_SIZE 1.0f
#define DEFAULT_TEXT_BODY_COLOR "#eaeaea"
#define DEFAULT_TEXT_BODY_WEIGHT TEXT_WEIGHT_NORMAL
#define DEFAULT_TEXT_BODY_SIZE 0.9f
#define DEFAULT_PIXELS_PER_EM 10.0f
#define DEFAULT_SYSTEM_FONT_SIZE 10.0f
#define DEFAULT_SCREEN_DPI 96.0f
#define DEFAULT_GRAVITY GRAVITY_NORTH_EAST
/* these values are interpreted as milliseconds-measurements and do comply to
* the visual guide for jaunty-notifications */
#define DEFAULT_FADE_IN_TIMEOUT 250
#define DEFAULT_FADE_OUT_TIMEOUT 1000
#define DEFAULT_ON_SCREEN_TIMEOUT 10000
/* notify-osd settings */
#define NOTIFY_OSD_SCHEMA "com.canonical.notify-osd"
#define GSETTINGS_GRAVITY_KEY "gravity"
#define GSETTINGS_MULTIHEAD_MODE_KEY "multihead-mode"
/* gnome settings */
#define GNOME_DESKTOP_SCHEMA "org.gnome.desktop.interface"
#define GSETTINGS_FONT_KEY "font-name"
/* unity settings */
#define UNITY_SCHEMA "com.canonical.Unity"
#define GSETTINGS_AVG_BG_COL_KEY "average-bg-color"
static guint g_defaults_signals[LAST_SIGNAL] = { 0 };
/*-- internal API ------------------------------------------------------------*/
static void
_get_font_size_dpi (Defaults* self)
{
GString* string = NULL;
gdouble points = 0.0f;
GString* font_face = NULL;
gdouble dpi = 0.0f;
gdouble pixels_per_em = 0;
gchar* font_name = NULL;
PangoFontDescription* desc = NULL;
GtkSettings* gtk_settings = NULL;
gint value = 0;
if (!IS_DEFAULTS (self))
return;
/* determine current system font-name/size */
font_name = g_settings_get_string (self->gnome_settings, GSETTINGS_FONT_KEY);
string = g_string_new (font_name);
// extract text point-size
desc = pango_font_description_from_string (font_name);
if (pango_font_description_get_size_is_absolute (desc))
points = (gdouble) pango_font_description_get_size (desc);
else
points = (gdouble) pango_font_description_get_size (desc) /
(gdouble) PANGO_SCALE;
pango_font_description_free (desc);
g_free ((gpointer) font_name);
// extract font-face-name/style
font_face = extract_font_face (string->str);
if (string != NULL)
g_string_free (string, TRUE);
/* update stored font-face name and clean up */
if (font_face != NULL)
{
g_object_set (self, "text-font-face", font_face->str, NULL);
g_string_free (font_face, TRUE);
}
/* update stored system-font size (in pt!) */
g_object_set (self, "system-font-size", (gdouble) points, NULL);
/* determine current system DPI-setting */
gtk_settings = gtk_settings_get_default (); // not ref'ed
g_object_get (gtk_settings, "gtk-xft-dpi", &value, NULL);
dpi = (float) value / (float) 1024;
/* update stored DPI-value */
pixels_per_em = points * dpi / 72.0f;
g_object_set (self, "pixels-per-em", pixels_per_em, NULL);
g_object_set (self, "screen-dpi", dpi, NULL);
if (g_getenv ("DEBUG"))
g_print ("font-size: %fpt\ndpi: %3.1f\npixels/EM: %2.2f\nwidth: %d px\ntitle-height: %2.2f pt\nbody-height: %2.2f pt\n\n",
points,
defaults_get_screen_dpi (self),
pixels_per_em,
(gint) (pixels_per_em * DEFAULT_BUBBLE_WIDTH),
defaults_get_system_font_size (self) *
defaults_get_text_title_size (self),
defaults_get_system_font_size (self) *
defaults_get_text_body_size (self));
}
static void
_get_gravity (Defaults* self)
{
Gravity gravity = DEFAULT_GRAVITY;
if (!IS_DEFAULTS (self))
return;
// grab current gravity-setting for notify-osd from GSettings
gravity = g_settings_get_int (self->nosd_settings, GSETTINGS_GRAVITY_KEY);
// protect against out-of-bounds values for gravity
if (gravity != GRAVITY_EAST && gravity != GRAVITY_NORTH_EAST)
gravity = DEFAULT_GRAVITY;
// update stored DPI-value
g_object_set (self, "gravity", gravity, NULL);
}
static void
_font_changed (GSettings* settings,
gchar* key,
gpointer data)
{
Defaults* defaults;
if (!data)
return;
defaults = (Defaults*) data;
if (!IS_DEFAULTS (defaults))
return;
/* grab system-wide font-face/size and DPI */
_get_font_size_dpi (defaults);
g_signal_emit (defaults, g_defaults_signals[VALUE_CHANGED], 0);
}
static void
_gravity_changed (GSettings* settings,
gchar* key,
gpointer data)
{
Defaults* defaults;
if (!data)
return;
defaults = (Defaults*) data;
if (!IS_DEFAULTS (defaults))
return;
// grab gravity setting for notify-osd from gconf
_get_gravity (defaults);
g_signal_emit (defaults, g_defaults_signals[GRAVITY_CHANGED], 0);
}
void
defaults_refresh_bg_color_property (Defaults *self)
{
Atom real_type;
gint result;
gint real_format;
gulong items_read;
gulong items_left;
gchar* colors;
Atom representative_colors_atom;
Display* display;
g_return_if_fail ((self != NULL) && IS_DEFAULTS (self));
representative_colors_atom = gdk_x11_get_xatom_by_name ("_GNOME_BACKGROUND_REPRESENTATIVE_COLORS");
display = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
gdk_error_trap_push ();
result = XGetWindowProperty (display,
GDK_ROOT_WINDOW (),
representative_colors_atom,
0L,
G_MAXLONG,
False,
XA_STRING,
&real_type,
&real_format,
&items_read,
&items_left,
(guchar **) &colors);
gdk_flush ();
gdk_error_trap_pop_ignored ();
if (result == Success && items_read)
{
/* by treating the result as a nul-terminated string, we
* select the first colour in the list.
*/
g_object_set (self,
"bubble-bg-color",
colors,
NULL);
XFree (colors);
}
}
static void
defaults_constructed (GObject* gobject)
{
Defaults* self;
gdouble margin_size;
gdouble icon_size;
gdouble bubble_height;
gdouble new_bubble_height;
GdkScreen* screen;
gint x;
gint y;
self = DEFAULTS (gobject);
defaults_get_top_corner (self, &screen, &x, &y);
defaults_refresh_bg_color_property (self);
/* grab system-wide font-face/size and DPI */
_get_font_size_dpi (self);
_get_gravity (self);
/* correct the default min. bubble-height, according to the icon-size */
g_object_get (self,
"margin-size",
&margin_size,
NULL);
g_object_get (self,
"icon-size",
&icon_size,
NULL);
g_object_get (self,
"bubble-min-height",
&bubble_height,
NULL);
#if 0
/* try to register the non-standard size for the gtk_icon_theme_lookup
calls to work */
gtk_icon_size_register ("52x52",
pixels_per_em * icon_size,
pixels_per_em * icon_size);
#endif
new_bubble_height = 2.0f * margin_size + icon_size;
if (new_bubble_height > bubble_height)
{
g_object_set (self,
"bubble-min-height",
new_bubble_height,
NULL);
}
/* FIXME: calling this here causes a segfault */
/* chain up to the parent class */
/*G_OBJECT_CLASS (defaults_parent_class)->constructed (gobject);*/
}
static void
defaults_dispose (GObject* gobject)
{
Defaults* defaults;
defaults = DEFAULTS (gobject);
g_object_unref (defaults->nosd_settings);
g_object_unref (defaults->gnome_settings);
if (defaults->bubble_shadow_color)
{
g_string_free (defaults->bubble_shadow_color, TRUE);
defaults->bubble_shadow_color = NULL;
}
if (defaults->bubble_bg_color)
{
g_string_free (defaults->bubble_bg_color, TRUE);
defaults->bubble_bg_color = NULL;
}
if (defaults->bubble_bg_opacity)
{
g_string_free (defaults->bubble_bg_opacity, TRUE);
defaults->bubble_bg_opacity = NULL;
}
if (defaults->bubble_hover_opacity)
{
g_string_free (defaults->bubble_hover_opacity, TRUE);
defaults->bubble_hover_opacity = NULL;
}
if (defaults->content_shadow_color)
{
g_string_free (defaults->content_shadow_color, TRUE);
defaults->content_shadow_color = NULL;
}
if (defaults->text_font_face)
{
g_string_free (defaults->text_font_face, TRUE);
defaults->text_font_face = NULL;
}
if (defaults->text_title_color)
{
g_string_free (defaults->text_title_color, TRUE);
defaults->text_title_color = NULL;
}
if (defaults->text_body_color)
{
g_string_free (defaults->text_body_color, TRUE);
defaults->text_body_color = NULL;
}
// chain up to the parent class
G_OBJECT_CLASS (defaults_parent_class)->dispose (gobject);
}
static void
defaults_finalize (GObject* gobject)
{
// chain up to the parent class
G_OBJECT_CLASS (defaults_parent_class)->finalize (gobject);
}
static void
defaults_init (Defaults* self)
{
/* "connect" to the required GSettings schemas */
self->nosd_settings = g_settings_new (NOTIFY_OSD_SCHEMA);
self->gnome_settings = g_settings_new (GNOME_DESKTOP_SCHEMA);
g_signal_connect (self->gnome_settings,
"changed",
G_CALLBACK (_font_changed),
self);
g_signal_connect (gtk_settings_get_default (),
"notify::gtk-xft-dpi",
G_CALLBACK (_font_changed),
self);
g_signal_connect (self->nosd_settings,
"changed",
G_CALLBACK (_gravity_changed),
self);
// use fixed slot-allocation for async. and sync. bubbles
self->slot_allocation = SLOT_ALLOCATION_FIXED;
}
static void
defaults_get_property (GObject* gobject,
guint prop,
GValue* value,
GParamSpec* spec)
{
Defaults* defaults;
defaults = DEFAULTS (gobject);
switch (prop)
{
case PROP_DESKTOP_BOTTOM_GAP:
g_value_set_double (value, defaults->desktop_bottom_gap);
break;
case PROP_STACK_HEIGHT:
g_value_set_double (value, defaults->stack_height);
break;
case PROP_BUBBLE_VERT_GAP:
g_value_set_double (value, defaults->bubble_vert_gap);
break;
case PROP_BUBBLE_HORZ_GAP:
g_value_set_double (value, defaults->bubble_horz_gap);
break;
case PROP_BUBBLE_WIDTH:
g_value_set_double (value, defaults->bubble_width);
break;
case PROP_BUBBLE_MIN_HEIGHT:
g_value_set_double (value, defaults->bubble_min_height);
break;
case PROP_BUBBLE_MAX_HEIGHT:
g_value_set_double (value, defaults->bubble_max_height);
break;
case PROP_BUBBLE_SHADOW_SIZE:
g_value_set_double (value, defaults->bubble_shadow_size);
break;
case PROP_BUBBLE_SHADOW_COLOR:
g_value_set_string (value,
defaults->bubble_shadow_color->str);
break;
case PROP_BUBBLE_BG_COLOR:
g_value_set_string (value,
defaults->bubble_bg_color->str);
break;
case PROP_BUBBLE_BG_OPACITY:
g_value_set_string (value,
defaults->bubble_bg_opacity->str);
break;
case PROP_BUBBLE_HOVER_OPACITY:
g_value_set_string (value,
defaults->bubble_hover_opacity->str);
break;
case PROP_BUBBLE_CORNER_RADIUS:
g_value_set_double (value, defaults->bubble_corner_radius);
break;
case PROP_CONTENT_SHADOW_SIZE:
g_value_set_double (value, defaults->content_shadow_size);
break;
case PROP_CONTENT_SHADOW_COLOR:
g_value_set_string (value,
defaults->content_shadow_color->str);
break;
case PROP_MARGIN_SIZE:
g_value_set_double (value, defaults->margin_size);
break;
case PROP_ICON_SIZE:
g_value_set_double (value, defaults->icon_size);
break;
case PROP_GAUGE_SIZE:
g_value_set_double (value, defaults->gauge_size);
break;
case PROP_GAUGE_OUTLINE_WIDTH:
g_value_set_double (value, defaults->gauge_outline_width);
break;
case PROP_FADE_IN_TIMEOUT:
g_value_set_int (value, defaults->fade_in_timeout);
break;
case PROP_FADE_OUT_TIMEOUT:
g_value_set_int (value, defaults->fade_out_timeout);
break;
case PROP_ON_SCREEN_TIMEOUT:
g_value_set_int (value, defaults->on_screen_timeout);
break;
case PROP_TEXT_FONT_FACE:
g_value_set_string (value,
defaults->text_font_face->str);
break;
case PROP_TEXT_TITLE_COLOR:
g_value_set_string (value,
defaults->text_title_color->str);
break;
case PROP_TEXT_TITLE_WEIGHT:
g_value_set_int (value, defaults->text_title_weight);
break;
case PROP_TEXT_TITLE_SIZE:
g_value_set_double (value, defaults->text_title_size);
break;
case PROP_TEXT_BODY_COLOR:
g_value_set_string (value,
defaults->text_body_color->str);
break;
case PROP_TEXT_BODY_WEIGHT:
g_value_set_int (value, defaults->text_body_weight);
break;
case PROP_TEXT_BODY_SIZE:
g_value_set_double (value, defaults->text_body_size);
break;
case PROP_PIXELS_PER_EM:
g_value_set_double (value, defaults->pixels_per_em);
break;
case PROP_SYSTEM_FONT_SIZE:
g_value_set_double (value, defaults->system_font_size);
break;
case PROP_SCREEN_DPI:
g_value_set_double (value, defaults->screen_dpi);
break;
case PROP_GRAVITY:
g_value_set_int (value, defaults->gravity);
break;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
defaults_set_property (GObject* gobject,
guint prop,
const GValue* value,
GParamSpec* spec)
{
Defaults* defaults;
defaults = DEFAULTS (gobject);
switch (prop)
{
case PROP_DESKTOP_BOTTOM_GAP:
defaults->desktop_bottom_gap = g_value_get_double (value);
break;
case PROP_STACK_HEIGHT:
defaults->stack_height = g_value_get_double (value);
break;
case PROP_BUBBLE_WIDTH:
defaults->bubble_width = g_value_get_double (value);
break;
case PROP_BUBBLE_VERT_GAP:
defaults->bubble_vert_gap = g_value_get_double (value);
break;
case PROP_BUBBLE_HORZ_GAP:
defaults->bubble_horz_gap = g_value_get_double (value);
break;
case PROP_BUBBLE_MIN_HEIGHT:
defaults->bubble_min_height = g_value_get_double (value);
break;
case PROP_BUBBLE_MAX_HEIGHT:
defaults->bubble_max_height = g_value_get_double (value);
break;
case PROP_BUBBLE_SHADOW_SIZE:
defaults->bubble_shadow_size = g_value_get_double (value);
break;
case PROP_BUBBLE_SHADOW_COLOR:
if (defaults->bubble_shadow_color != NULL)
{
g_string_free (defaults->bubble_shadow_color,
TRUE);
}
defaults->bubble_shadow_color = g_string_new (
g_value_get_string (value));
break;
case PROP_BUBBLE_BG_COLOR:
if (defaults->bubble_bg_color != NULL)
{
g_string_free (defaults->bubble_bg_color, TRUE);
}
defaults->bubble_bg_color = g_string_new (
g_value_get_string (value));
break;
case PROP_BUBBLE_BG_OPACITY:
if (defaults->bubble_bg_opacity != NULL)
{
g_string_free (defaults->bubble_bg_opacity,
TRUE);
}
defaults->bubble_bg_opacity = g_string_new (
g_value_get_string (value));
break;
case PROP_BUBBLE_HOVER_OPACITY:
if (defaults->bubble_hover_opacity != NULL)
{
g_string_free (defaults->bubble_hover_opacity,
TRUE);
}
defaults->bubble_hover_opacity = g_string_new (
g_value_get_string (value));
break;
case PROP_BUBBLE_CORNER_RADIUS:
defaults->bubble_corner_radius = g_value_get_double (value);
break;
case PROP_CONTENT_SHADOW_SIZE:
defaults->content_shadow_size = g_value_get_double (value);
break;
case PROP_CONTENT_SHADOW_COLOR:
if (defaults->content_shadow_color != NULL)
{
g_string_free (defaults->content_shadow_color,
TRUE);
}
defaults->content_shadow_color = g_string_new (
g_value_get_string (value));
break;
case PROP_MARGIN_SIZE:
defaults->margin_size = g_value_get_double (value);
break;
case PROP_ICON_SIZE:
defaults->icon_size = g_value_get_double (value);
break;
case PROP_GAUGE_SIZE:
defaults->gauge_size = g_value_get_double (value);
break;
case PROP_GAUGE_OUTLINE_WIDTH:
defaults->gauge_outline_width = g_value_get_double (value);
break;
case PROP_FADE_IN_TIMEOUT:
defaults->fade_in_timeout = g_value_get_int (value);
break;
case PROP_FADE_OUT_TIMEOUT:
defaults->fade_out_timeout = g_value_get_int (value);
break;
case PROP_ON_SCREEN_TIMEOUT:
defaults->on_screen_timeout = g_value_get_int (value);
break;
case PROP_TEXT_FONT_FACE:
if (defaults->text_font_face != NULL)
{
g_string_free (defaults->text_font_face,
TRUE);
}
defaults->text_font_face = g_string_new (
g_value_get_string (value));
break;
case PROP_TEXT_TITLE_COLOR:
if (defaults->text_title_color != NULL)
{
g_string_free (defaults->text_title_color,
TRUE);
}
defaults->text_title_color = g_string_new (
g_value_get_string (value));
break;
case PROP_TEXT_TITLE_WEIGHT:
defaults->text_title_weight = g_value_get_int (value);
break;
case PROP_TEXT_TITLE_SIZE:
defaults->text_title_size = g_value_get_double (value);
break;
case PROP_TEXT_BODY_COLOR:
if (defaults->text_body_color != NULL)
{
g_string_free (defaults->text_body_color, TRUE);
}
defaults->text_body_color = g_string_new (
g_value_get_string (value));
break;
case PROP_TEXT_BODY_WEIGHT:
defaults->text_body_weight = g_value_get_int (value);
break;
case PROP_TEXT_BODY_SIZE:
defaults->text_body_size = g_value_get_double (value);
break;
case PROP_PIXELS_PER_EM:
defaults->pixels_per_em = g_value_get_double (value);
break;
case PROP_SYSTEM_FONT_SIZE:
defaults->system_font_size = g_value_get_double (value);
break;
case PROP_SCREEN_DPI:
defaults->screen_dpi = g_value_get_double (value);
break;
case PROP_GRAVITY:
defaults->gravity = g_value_get_int (value);
break;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
defaults_class_init (DefaultsClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
GParamSpec* property_desktop_bottom_gap;
GParamSpec* property_stack_height;
GParamSpec* property_bubble_vert_gap;
GParamSpec* property_bubble_horz_gap;
GParamSpec* property_bubble_width;
GParamSpec* property_bubble_min_height;
GParamSpec* property_bubble_max_height;
GParamSpec* property_bubble_shadow_size;
GParamSpec* property_bubble_shadow_color;
GParamSpec* property_bubble_bg_color;
GParamSpec* property_bubble_bg_opacity;
GParamSpec* property_bubble_hover_opacity;
GParamSpec* property_bubble_corner_radius;
GParamSpec* property_content_shadow_size;
GParamSpec* property_content_shadow_color;
GParamSpec* property_margin_size;
GParamSpec* property_icon_size;
GParamSpec* property_gauge_size;
GParamSpec* property_gauge_outline_width;
GParamSpec* property_fade_in_timeout;
GParamSpec* property_fade_out_timeout;
GParamSpec* property_on_screen_timeout;
GParamSpec* property_text_font_face;
GParamSpec* property_text_title_color;
GParamSpec* property_text_title_weight;
GParamSpec* property_text_title_size;
GParamSpec* property_text_body_color;
GParamSpec* property_text_body_weight;
GParamSpec* property_text_body_size;
GParamSpec* property_pixels_per_em;
GParamSpec* property_system_font_size;
GParamSpec* property_screen_dpi;
GParamSpec* property_gravity;
gobject_class->constructed = defaults_constructed;
gobject_class->dispose = defaults_dispose;
gobject_class->finalize = defaults_finalize;
gobject_class->get_property = defaults_get_property;
gobject_class->set_property = defaults_set_property;
g_defaults_signals[VALUE_CHANGED] = g_signal_new (
"value-changed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (DefaultsClass, value_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
g_defaults_signals[GRAVITY_CHANGED] = g_signal_new (
"gravity-changed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (DefaultsClass, gravity_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
property_desktop_bottom_gap = g_param_spec_double (
"desktop-bottom-gap",
"desktop-bottom-gap",
"Bottom gap on the desktop in em",
0.0f,
16.0f,
DEFAULT_DESKTOP_BOTTOM_GAP,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_DESKTOP_BOTTOM_GAP,
property_desktop_bottom_gap);
property_stack_height = g_param_spec_double (
"stack-height",
"stack-height",
"Maximum allowed height of stack (in em)",
0.0f,
256.0f,
50.0f,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_STACK_HEIGHT,
property_stack_height);
property_bubble_vert_gap = g_param_spec_double (
"bubble-vert-gap",
"bubble-vert-gap",
"Vert. gap between bubble and workarea edge (in em)",
0.0f,
10.0f,
DEFAULT_BUBBLE_VERT_GAP,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_VERT_GAP,
property_bubble_vert_gap);
property_bubble_horz_gap = g_param_spec_double (
"bubble-horz-gap",
"bubble-horz-gap",
"Horz. gap between bubble and workarea edge (in em)",
0.0f,
10.0f,
DEFAULT_BUBBLE_HORZ_GAP,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_HORZ_GAP,
property_bubble_horz_gap);
property_bubble_width = g_param_spec_double (
"bubble-width",
"bubble-width",
"Width of bubble (in em)",
0.0f,
256.0f,
DEFAULT_BUBBLE_WIDTH,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_WIDTH,
property_bubble_width);
property_bubble_min_height = g_param_spec_double (
"bubble-min-height",
"bubble-min-height",
"Min. height of bubble (in em)",
0.0f,
256.0f,
DEFAULT_BUBBLE_MIN_HEIGHT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_MIN_HEIGHT,
property_bubble_min_height);
property_bubble_max_height = g_param_spec_double (
"bubble-max-height",
"bubble-max-height",
"Max. height of bubble (in em)",
0.0f,
256.0f,
DEFAULT_BUBBLE_MAX_HEIGHT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_MAX_HEIGHT,
property_bubble_max_height);
property_bubble_shadow_size = g_param_spec_double (
"bubble-shadow-size",
"bubble-shadow-size",
"Size (in em) of bubble drop-shadow",
0.0f,
32.0f,
DEFAULT_BUBBLE_SHADOW_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_SHADOW_SIZE,
property_bubble_shadow_size);
property_bubble_shadow_color = g_param_spec_string (
"bubble-shadow-color",
"bubble-shadow-color",
"Color of bubble drop-shadow",
DEFAULT_BUBBLE_SHADOW_COLOR,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_SHADOW_COLOR,
property_bubble_shadow_color);
property_bubble_bg_color = g_param_spec_string (
"bubble-bg-color",
"bubble-bg-color",
"Color of bubble-background",
DEFAULT_BUBBLE_BG_COLOR,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_BG_COLOR,
property_bubble_bg_color);
property_bubble_bg_opacity = g_param_spec_string (
"bubble-bg-opacity",
"bubble-bg-opacity",
"Opacity of bubble-background",
DEFAULT_BUBBLE_BG_OPACITY,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_BG_OPACITY,
property_bubble_bg_opacity);
property_bubble_hover_opacity = g_param_spec_string (
"bubble-hover-opacity",
"bubble-hover-opacity",
"Opacity of bubble in mouse-over case",
DEFAULT_BUBBLE_HOVER_OPACITY,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_HOVER_OPACITY,
property_bubble_hover_opacity);
property_bubble_corner_radius = g_param_spec_double (
"bubble-corner-radius",
"bubble-corner-radius",
"Corner-radius of bubble (in em)",
0.0f,
16.0f,
DEFAULT_BUBBLE_CORNER_RADIUS,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_BUBBLE_CORNER_RADIUS,
property_bubble_corner_radius);
property_content_shadow_size = g_param_spec_double (
"content-shadow-size",
"content-shadow-size",
"Size (in em) of icon/text drop-shadow",
0.0f,
8.0f,
DEFAULT_CONTENT_SHADOW_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_CONTENT_SHADOW_SIZE,
property_content_shadow_size);
property_content_shadow_color = g_param_spec_string (
"content-shadow-color",
"content-shadow-color",
"Color of icon/text drop-shadow",
DEFAULT_CONTENT_SHADOW_COLOR,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_CONTENT_SHADOW_COLOR,
property_content_shadow_color);
property_margin_size = g_param_spec_double (
"margin-size",
"margin-size",
"Size (in em) of margin",
0.0f,
32.0f,
DEFAULT_MARGIN_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_MARGIN_SIZE,
property_margin_size);
property_icon_size = g_param_spec_double (
"icon-size",
"icon-size",
"Size (in em) of icon/avatar",
0.0f,
64.0f,
DEFAULT_ICON_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_ICON_SIZE,
property_icon_size);
property_gauge_size = g_param_spec_double (
"gauge-size",
"gauge-size",
"Size/height (in em) of gauge/indicator",
0.5f,
1.0f,
DEFAULT_GAUGE_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_GAUGE_SIZE,
property_gauge_size);
property_gauge_outline_width = g_param_spec_double (
"gauge-outline-width",
"gauge-outline-width",
"Width/thickness (in em) of gauge-outline",
0.1f,
0.2f,
DEFAULT_GAUGE_OUTLINE_WIDTH,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_GAUGE_OUTLINE_WIDTH,
property_gauge_outline_width);
property_fade_in_timeout = g_param_spec_int (
"fade-in-timeout",
"fade-in-timeout",
"Timeout for bubble fade-in in milliseconds",
0,
10000,
DEFAULT_FADE_IN_TIMEOUT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_FADE_IN_TIMEOUT,
property_fade_in_timeout);
property_fade_out_timeout = g_param_spec_int (
"fade-out-timeout",
"fade-out-timeout",
"Timeout for bubble fade-out in milliseconds",
0,
10000,
DEFAULT_FADE_OUT_TIMEOUT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_FADE_OUT_TIMEOUT,
property_fade_out_timeout);
property_on_screen_timeout = g_param_spec_int (
"on-screen-timeout",
"on-screen-timeout",
"Timeout for bubble on screen in milliseconds",
0,
10000,
DEFAULT_ON_SCREEN_TIMEOUT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_ON_SCREEN_TIMEOUT,
property_on_screen_timeout);
property_text_font_face = g_param_spec_string (
"text-font-face",
"text-font-face",
"Font-face to use of any rendered text",
DEFAULT_TEXT_FONT_FACE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_FONT_FACE,
property_text_font_face);
property_text_title_color = g_param_spec_string (
"text-title-color",
"text-title-color",
"Color to use for content title-text",
DEFAULT_TEXT_TITLE_COLOR,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_TITLE_COLOR,
property_text_title_color);
property_text_title_weight = g_param_spec_int (
"text-title-weight",
"text-title-weight",
"Weight to use for content title-text",
0,
1000,
DEFAULT_TEXT_TITLE_WEIGHT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_TITLE_WEIGHT,
property_text_title_weight);
property_text_title_size = g_param_spec_double (
"text-title-size",
"text-title-size",
"Size (in em) of font to use for content title-text",
0.0f,
32.0f,
DEFAULT_TEXT_TITLE_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_TITLE_SIZE,
property_text_title_size);
property_text_body_color = g_param_spec_string (
"text-body-color",
"text-body-color",
"Color to use for content body-text",
DEFAULT_TEXT_BODY_COLOR,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_BODY_COLOR,
property_text_body_color);
property_text_body_weight = g_param_spec_int (
"text-body-weight",
"text-body-weight",
"Weight to use for content body-text",
0,
1000,
DEFAULT_TEXT_BODY_WEIGHT,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_BODY_WEIGHT,
property_text_body_weight);
property_text_body_size = g_param_spec_double (
"text-body-size",
"text-body-size",
"Size (in em) of font to use for content body-text",
0.0f,
32.0f,
DEFAULT_TEXT_BODY_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_TEXT_BODY_SIZE,
property_text_body_size);
property_pixels_per_em = g_param_spec_double (
"pixels-per-em",
"pixels-per-em",
"Number of pixels for one em-unit",
1.0f,
100.0f,
DEFAULT_PIXELS_PER_EM,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_PIXELS_PER_EM,
property_pixels_per_em);
property_system_font_size = g_param_spec_double (
"system-font-size",
"system-font-size",
"System font-size in pt",
1.0f,
100.0f,
DEFAULT_SYSTEM_FONT_SIZE,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_SYSTEM_FONT_SIZE,
property_system_font_size);
property_screen_dpi = g_param_spec_double (
"screen-dpi",
"screen-dpi",
"Screen DPI value",
10.0f,
600.0f,
DEFAULT_SCREEN_DPI,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_SCREEN_DPI,
property_screen_dpi);
property_gravity = g_param_spec_int (
"gravity",
"gravity",
"Positional hint for placing bubbles",
0,
2,
DEFAULT_GRAVITY,
G_PARAM_CONSTRUCT |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_property (gobject_class,
PROP_GRAVITY,
property_gravity);
}
/*-- public API --------------------------------------------------------------*/
Defaults*
defaults_new (void)
{
Defaults* this = g_object_new (DEFAULTS_TYPE, NULL);
return this;
}
gint
defaults_get_desktop_width (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return 0;
return self->desktop_width;
}
gint
defaults_get_desktop_height (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return 0;
return self->desktop_height;
}
gdouble
defaults_get_desktop_bottom_gap (Defaults* self)
{
gdouble bottom_gap;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "desktop-bottom-gap", &bottom_gap, NULL);
return bottom_gap;
}
gdouble
defaults_get_stack_height (Defaults* self)
{
gdouble stack_height;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "stack-height", &stack_height, NULL);
return stack_height;
}
gdouble
defaults_get_bubble_gap (Defaults* self)
{
gdouble gap;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-gap", &gap, NULL);
return gap;
}
gdouble
defaults_get_bubble_width (Defaults* self)
{
gdouble width;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-width", &width, NULL);
return width;
}
gdouble
defaults_get_bubble_min_height (Defaults* self)
{
gdouble bubble_min_height;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-min-height", &bubble_min_height, NULL);
return bubble_min_height;
}
gdouble
defaults_get_bubble_max_height (Defaults* self)
{
gdouble bubble_max_height;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-max-height", &bubble_max_height, NULL);
return bubble_max_height;
}
gdouble
defaults_get_bubble_vert_gap (Defaults* self)
{
gdouble bubble_vert_gap;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-vert-gap", &bubble_vert_gap, NULL);
return bubble_vert_gap;
}
gdouble
defaults_get_bubble_horz_gap (Defaults* self)
{
gdouble bubble_horz_gap;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-horz-gap", &bubble_horz_gap, NULL);
return bubble_horz_gap;
}
gdouble
defaults_get_bubble_height (Defaults* self)
{
gdouble height;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "bubble-height", &height, NULL);
return height;
}
gdouble
defaults_get_bubble_shadow_size (Defaults* self, gboolean is_composited)
{
gdouble bubble_shadow_size;
if (!self || !IS_DEFAULTS (self) || !is_composited)
return 0.0f;
g_object_get (self, "bubble-shadow-size", &bubble_shadow_size, NULL);
return bubble_shadow_size;
}
gchar*
defaults_get_bubble_shadow_color (Defaults* self)
{
gchar* bubble_shadow_color = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self,
"bubble-shadow-color",
&bubble_shadow_color,
NULL);
return bubble_shadow_color;
}
gchar*
defaults_get_bubble_bg_color (Defaults* self)
{
gchar* bubble_bg_color = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
defaults_refresh_bg_color_property (self);
g_object_get (self,
"bubble-bg-color",
&bubble_bg_color,
NULL);
return bubble_bg_color;
}
gchar*
defaults_get_bubble_bg_opacity (Defaults* self)
{
gchar* bubble_bg_opacity = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self,
"bubble-bg-opacity",
&bubble_bg_opacity,
NULL);
return bubble_bg_opacity;
}
gchar*
defaults_get_bubble_hover_opacity (Defaults* self)
{
gchar* bubble_hover_opacity = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self,
"bubble-hover-opacity",
&bubble_hover_opacity,
NULL);
return bubble_hover_opacity;
}
gdouble
defaults_get_bubble_corner_radius (Defaults* self, gboolean is_composited)
{
gdouble bubble_corner_radius;
if (!self || !IS_DEFAULTS (self) || !is_composited)
return 0.0f;
g_object_get (self,
"bubble-corner-radius",
&bubble_corner_radius,
NULL);
return bubble_corner_radius;
}
gdouble
defaults_get_content_shadow_size (Defaults* self)
{
gdouble content_shadow_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "content-shadow-size", &content_shadow_size, NULL);
return content_shadow_size;
}
gchar*
defaults_get_content_shadow_color (Defaults* self)
{
gchar* content_shadow_color = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self,
"content-shadow-color",
&content_shadow_color,
NULL);
return content_shadow_color;
}
gdouble
defaults_get_margin_size (Defaults* self)
{
gdouble margin_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "margin-size", &margin_size, NULL);
return margin_size;
}
gdouble
defaults_get_icon_size (Defaults* self)
{
gdouble icon_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "icon-size", &icon_size, NULL);
return icon_size;
}
gdouble
defaults_get_gauge_size (Defaults* self)
{
gdouble gauge_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "gauge-size", &gauge_size, NULL);
return gauge_size;
}
gdouble
defaults_get_gauge_outline_width (Defaults* self)
{
gdouble gauge_outline_width;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "gauge-outline-width", &gauge_outline_width, NULL);
return gauge_outline_width;
}
gint
defaults_get_fade_in_timeout (Defaults* self)
{
gint fade_in_timeout;
if (!self || !IS_DEFAULTS (self))
return 0;
g_object_get (self, "fade-in-timeout", &fade_in_timeout, NULL);
return fade_in_timeout;
}
gint
defaults_get_fade_out_timeout (Defaults* self)
{
gint fade_out_timeout;
if (!self || !IS_DEFAULTS (self))
return 0;
g_object_get (self, "fade-out-timeout", &fade_out_timeout, NULL);
return fade_out_timeout;
}
gint
defaults_get_on_screen_timeout (Defaults* self)
{
gint on_screen_timeout;
if (!self || !IS_DEFAULTS (self))
return 0;
g_object_get (self, "on-screen-timeout", &on_screen_timeout, NULL);
return on_screen_timeout;
}
gchar*
defaults_get_text_font_face (Defaults* self)
{
gchar* text_font_face = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self, "text-font-face", &text_font_face, NULL);
return text_font_face;
}
gchar*
defaults_get_text_title_color (Defaults* self)
{
gchar* text_title_color = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self, "text-title-color", &text_title_color, NULL);
return text_title_color;
}
gint
defaults_get_text_title_weight (Defaults* self)
{
gint text_title_weight;
if (!self || !IS_DEFAULTS (self))
return 0;
g_object_get (self, "text-title-weight", &text_title_weight, NULL);
return text_title_weight;
}
gdouble
defaults_get_text_title_size (Defaults* self)
{
gdouble text_title_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "text-title-size", &text_title_size, NULL);
return text_title_size;
}
gchar*
defaults_get_text_body_color (Defaults* self)
{
gchar* text_body_color = NULL;
if (!self || !IS_DEFAULTS (self))
return NULL;
g_object_get (self, "text-body-color", &text_body_color, NULL);
return text_body_color;
}
gint
defaults_get_text_body_weight (Defaults* self)
{
gint text_body_weight;
if (!self || !IS_DEFAULTS (self))
return 0;
g_object_get (self, "text-body-weight", &text_body_weight, NULL);
return text_body_weight;
}
gdouble
defaults_get_text_body_size (Defaults* self)
{
gdouble text_body_size;
if (!self || !IS_DEFAULTS (self))
return 0.0f;
g_object_get (self, "text-body-size", &text_body_size, NULL);
return text_body_size;
}
/* we use the normal font-height in pixels ("pixels-per-em") as the measurement
* for 1 em, thus it should _not_ be called before defaults_constructed() */
gdouble
defaults_get_pixel_per_em (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return 0.0f;
gdouble pixels_per_em;
g_object_get (self, "pixels-per-em", &pixels_per_em, NULL);
return pixels_per_em;
}
gdouble
defaults_get_system_font_size (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return 0.0f;
gdouble system_font_size;
g_object_get (self, "system-font-size", &system_font_size, NULL);
return system_font_size;
}
gdouble
defaults_get_screen_dpi (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return 0.0f;
gdouble screen_dpi;
g_object_get (self, "screen-dpi", &screen_dpi, NULL);
return screen_dpi;
}
static gboolean
defaults_multihead_does_focus_follow (Defaults *self)
{
gboolean mode = FALSE;
g_return_val_if_fail (self != NULL && IS_DEFAULTS (self), FALSE);
gchar* mode_str = g_settings_get_string (self->nosd_settings,
GSETTINGS_MULTIHEAD_MODE_KEY);
if (mode_str != NULL)
{
if (! g_strcmp0 (mode_str, "focus-follow"))
mode = TRUE;
g_free ((gpointer) mode_str);
}
return mode;
}
void
defaults_get_top_corner (Defaults *self, GdkScreen **screen, gint *x, gint *y)
{
GdkRectangle rect;
GdkWindow* active_window = NULL;
GdkDeviceManager* device_manager;
GdkDevice* device;
gint mx;
gint my;
gint monitor = 0;
gint aw_monitor;
gboolean follow_focus = defaults_multihead_does_focus_follow (self);
gboolean is_composited = FALSE;
gint primary_monitor;
g_return_if_fail (self != NULL && IS_DEFAULTS (self));
device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
device = gdk_device_manager_get_client_pointer (device_manager);
gdk_device_get_position (device, screen, &mx, &my);
is_composited = gdk_screen_is_composited (*screen);
if (follow_focus)
{
g_debug ("multi_head_focus_follow mode");
monitor = gdk_screen_get_monitor_at_point (*screen, mx, my);
active_window = gdk_screen_get_active_window (*screen);
if (active_window != NULL)
{
aw_monitor = gdk_screen_get_monitor_at_window (
*screen,
active_window);
if (monitor != aw_monitor)
{
g_debug ("choosing the monitor with the active"
" window, not the one with the mouse"
" cursor");
}
monitor = aw_monitor;
g_object_unref (active_window);
}
}
/* _NET_WORKAREA is always a rectangle spanning all monitors of
* a screen. As such, it can't properly deal with monitor setups
* that aren't aligned or have different resolutions.
* gdk_screen_get_monitor_workarea() works around this by only
* returning the workarea for the primary screen and the full
* geometry for all other monitors.
*
* This leads to the sync bubbles sometimes overlapping the
* panel on secondary monitors. To work around this, we get the
* panel's height on the primary monitor and use that for all
* other monitors as well.
*/
primary_monitor = gdk_screen_get_primary_monitor (*screen);
if (monitor == primary_monitor)
{
gdk_screen_get_monitor_workarea (*screen, primary_monitor, &rect);
}
else
{
GdkRectangle workarea;
GdkRectangle primary_geom;
gint panel_height;
gdk_screen_get_monitor_workarea (*screen, primary_monitor, &workarea);
gdk_screen_get_monitor_geometry (*screen, primary_monitor, &primary_geom);
panel_height = workarea.y - primary_geom.y;
gdk_screen_get_monitor_geometry (*screen, monitor, &rect);
rect.y += panel_height;
rect.height -= panel_height;
}
g_debug ("selecting monitor %d at (%d,%d) - %dx%d",
monitor,
rect.x,
rect.y,
rect.width,
rect.height);
self->desktop_width = rect.width;
self->desktop_height = rect.height;
*y = rect.y;
*y += EM2PIXELS (defaults_get_bubble_vert_gap (self), self)
- EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self);
if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR)
{
*x = rect.x + rect.width;
*x -= EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self)
+ EM2PIXELS (defaults_get_bubble_horz_gap (self), self)
+ EM2PIXELS (defaults_get_bubble_width (self), self);
} else {
*x = rect.x
- EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self)
+ EM2PIXELS (defaults_get_bubble_horz_gap (self), self);
}
g_debug ("top corner at: %d, %d", *x, *y);
}
Gravity
defaults_get_gravity (Defaults* self)
{
if (!self || !IS_DEFAULTS (self))
return GRAVITY_NONE;
Gravity gravity;
g_object_get (self, "gravity", &gravity, NULL);
return gravity;
}
SlotAllocation
defaults_get_slot_allocation (Defaults *self)
{
if (!self || !IS_DEFAULTS (self))
return SLOT_ALLOCATION_NONE;
return self->slot_allocation;
}
./src/notification.h 0000644 0000156 0000165 00000010160 12704153542 014524 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// notification.h - notification object storing attributes like title- and body-
// text, value, icon, id, sender-pid etc.
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef __NOTIFICATION_H
#define __NOTIFICATION_H
#include
#include
G_BEGIN_DECLS
#define NOTIFICATION_TYPE (notification_get_type ())
#define NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NOTIFICATION_TYPE, Notification))
#define NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NOTIFICATION_TYPE, NotificationClass))
#define IS_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NOTIFICATION_TYPE))
#define IS_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NOTIFICATION_TYPE))
#define NOTIFICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NOTIFICATION_TYPE, NotificationClass))
#define NOTIFICATION_VALUE_MIN_ALLOWED -1
#define NOTIFICATION_VALUE_MAX_ALLOWED 101
typedef struct _Notification Notification;
typedef struct _NotificationClass NotificationClass;
typedef struct _NotificationPrivate NotificationPrivate;
typedef enum
{
URGENCY_LOW = 0,
URGENCY_NORMAL,
URGENCY_HIGH,
URGENCY_NONE
} Urgency;
// instance structure
struct _Notification
{
GObject parent;
//< private >
NotificationPrivate* priv;
};
// class structure
struct _NotificationClass
{
GObjectClass parent;
//< signals >
};
GType Notification_get_type (void);
Notification*
notification_new ();
gint
notification_get_id (Notification* n);
void
notification_set_id (Notification* n,
const gint id);
gchar*
notification_get_title (Notification* n);
void
notification_set_title (Notification* n,
const gchar* title);
gchar*
notification_get_body (Notification* n);
void
notification_set_body (Notification* n,
const gchar* body);
gint
notification_get_value (Notification* n);
void
notification_set_value (Notification* n,
const gint value);
gchar*
notification_get_icon_themename (Notification* n);
void
notification_set_icon_themename (Notification* n,
const gchar* icon_themename);
gchar*
notification_get_icon_filename (Notification* n);
void
notification_set_icon_filename (Notification* n,
const gchar* icon_filename);
GdkPixbuf*
notification_get_icon_pixbuf (Notification* n);
void
notification_set_icon_pixbuf (Notification* n,
const GdkPixbuf* icon_pixbuf);
gint
notification_get_onscreen_time (Notification* n);
void
notification_set_onscreen_time (Notification* n,
const gint onscreen_time);
gchar*
notification_get_sender_name (Notification* n);
void
notification_set_sender_name (Notification* n,
const gchar* sender_name);
gint
notification_get_sender_pid (Notification* n);
void
notification_set_sender_pid (Notification* n,
const gint sender_pid);
GTimeVal*
notification_get_timestamp (Notification* n);
void
notification_set_timestamp (Notification* n,
const GTimeVal* timestamp);
gint
notification_get_urgency (Notification* n);
void
notification_set_urgency (Notification* n,
const Urgency urgency);
G_END_DECLS
#endif // __NOTIFICATION_H
./src/exponential-blur.h 0000644 0000156 0000165 00000002610 12704153542 015327 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// raico-blur
//
// exponential-blur.h - implements exponential-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// based on exponential-blur algorithm by Jani Huhtanen
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _EXPONENTIAL_BLUR_H
#define _EXPONENTIAL_BLUR_H
#include
#include
void
surface_exponential_blur (cairo_surface_t* surface,
guint radius);
#endif // _EXPONENTIAL_BLUR_H
./src/bubble-window.c 0000644 0000156 0000165 00000007426 12704153542 014604 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window.c - implements bubble window
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include "bubble-window.h"
#include "bubble.h"
#include "bubble-window-accessible-factory.h"
G_DEFINE_TYPE (BubbleWindow, bubble_window, GTK_TYPE_WINDOW);
static AtkObject* bubble_window_get_accessible (GtkWidget *widget);
static void
bubble_window_init (BubbleWindow *object)
{
/* TODO: Add initialization code here */
}
static void
bubble_window_finalize (GObject *object)
{
/* TODO: Add deinitalization code here */
G_OBJECT_CLASS (bubble_window_parent_class)->finalize (object);
}
static void
bubble_window_class_init (BubbleWindowClass *klass)
{
GObjectClass* object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
widget_class->get_accessible = bubble_window_get_accessible;
object_class->finalize = bubble_window_finalize;
}
GtkWidget *
bubble_window_new (void)
{
GtkWidget *bubble_window;
bubble_window = g_object_new (BUBBLE_TYPE_WINDOW,
"type", GTK_WINDOW_POPUP, NULL);
return bubble_window;
}
static AtkObject *
bubble_window_get_accessible (GtkWidget *widget)
{
static gboolean first_time = TRUE;
static GQuark quark_accessible_object;
if (first_time)
{
AtkObjectFactory *factory = NULL;
AtkRegistry *registry = NULL;
GType derived_type = NULL;
GType derived_atk_type = NULL;
/*
* Figure out whether accessibility is enabled by looking at the
* type of the accessible object which would be created for
* the parent type WnckPager.
*/
derived_type = g_type_parent (BUBBLE_TYPE_WINDOW);
registry = atk_get_default_registry ();
factory = atk_registry_get_factory (registry,
derived_type);
derived_atk_type = atk_object_factory_get_accessible_type (factory);
atk_registry_set_factory_type (registry,
BUBBLE_TYPE_WINDOW,
BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY);
quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object");
first_time = FALSE;
}
AtkRegistry *default_registry = atk_get_default_registry ();
AtkObjectFactory *factory = NULL;
AtkObject *accessible = g_object_get_qdata (G_OBJECT (widget),
quark_accessible_object);
if (accessible)
return accessible;
factory = atk_registry_get_factory (default_registry,
G_TYPE_FROM_INSTANCE (widget));
accessible = atk_object_factory_create_accessible (factory,
G_OBJECT (widget));
g_object_set_qdata (G_OBJECT (widget), quark_accessible_object,
accessible);
return accessible;
}
./src/util.c 0000644 0000156 0000165 00000015323 12704153542 013014 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** util.c - all sorts of helper functions
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Cody Russell
** Mirco "MacSlow" Mueller
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#define CHARACTER_LT_REGEX "&(lt;|#60;|#x3c;)"
#define CHARACTER_GT_REGEX "&(gt;|#62;|#x3e;)"
#define CHARACTER_AMP_REGEX "&(amp;|#38;|#x26;)"
#define CHARACTER_APOS_REGEX "'"
#define CHARACTER_QUOT_REGEX """
#define CHARACTER_NEWLINE_REGEX " *((
]*/?>|\r|\n)+ *)+"
#define TAG_MATCH_REGEX "<(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)\\b[^>]*>(.*?)\\1>|<(img|span|a)[^>]/>|<(img)[^>]*>"
#define TAG_REPLACE_REGEX "<(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)\\b[^>]*>|(b|i|u|big|a|img|span|s|sub|small|tt|html|qt)>"
struct _ReplaceMarkupData
{
gchar* regex;
gchar* replacement;
};
typedef struct _ReplaceMarkupData ReplaceMarkupData;
static gchar*
strip_html (const gchar *text, const gchar *match_regex, const gchar* replace_regex)
{
GRegex *regex;
gchar *ret;
gboolean match = FALSE;
GMatchInfo *info = NULL;
regex = g_regex_new (match_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
match = g_regex_match (regex, text, 0, &info);
g_regex_unref (regex);
if (match) {
regex = g_regex_new (replace_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
ret = g_regex_replace (regex, text, -1, 0, "", 0, NULL);
g_regex_unref (regex);
} else {
ret = g_strdup (text);
}
if (info)
g_match_info_free (info);
return ret;
}
static gchar*
replace_markup (const gchar *text, const gchar *match_regex, const gchar *replace_text)
{
GRegex *regex;
gchar *ret;
regex = g_regex_new (match_regex, G_REGEX_DOTALL | G_REGEX_OPTIMIZE, 0, NULL);
ret = g_regex_replace (regex, text, -1, 0, replace_text, 0, NULL);
g_regex_unref (regex);
return ret;
}
gchar*
filter_text (const gchar *text)
{
gchar *text1;
text1 = strip_html (text, TAG_MATCH_REGEX, TAG_REPLACE_REGEX);
static ReplaceMarkupData data[] = {
{ CHARACTER_AMP_REGEX, "&" },
{ CHARACTER_LT_REGEX, "<" },
{ CHARACTER_GT_REGEX, ">" },
{ CHARACTER_APOS_REGEX, "'" },
{ CHARACTER_QUOT_REGEX, "\"" },
{ CHARACTER_NEWLINE_REGEX, "\n" }
};
ReplaceMarkupData* ptr = data;
ReplaceMarkupData* end = data + sizeof(data) / sizeof(ReplaceMarkupData);
for (; ptr != end; ++ptr) {
gchar* tmp = replace_markup (text1, ptr->regex, ptr->replacement);
g_free (text1);
text1 = tmp;
}
return text1;
}
gchar*
newline_to_space (const gchar *text)
{
gchar *text1;
text1 = strip_html (text, TAG_MATCH_REGEX, TAG_REPLACE_REGEX);
static ReplaceMarkupData data[] = {
{ CHARACTER_NEWLINE_REGEX, " " }
};
ReplaceMarkupData* ptr = data;
ReplaceMarkupData* end = data + sizeof(data) / sizeof(ReplaceMarkupData);
for (; ptr != end; ++ptr) {
gchar* tmp = replace_markup (text1, ptr->regex, ptr->replacement);
g_free (text1);
text1 = tmp;
}
return text1;
}
cairo_surface_t*
copy_surface (cairo_surface_t* orig)
{
cairo_surface_t* copy = NULL;
cairo_format_t format;
gint width;
gint height;
cairo_t* cr;
double x_scale;
double y_scale;
width = cairo_image_surface_get_width (orig);
height = cairo_image_surface_get_height (orig);
format = cairo_image_surface_get_format (orig);
cairo_surface_get_device_scale (orig, &x_scale, &y_scale);
copy = cairo_surface_create_similar_image (orig, format, width, height);
cairo_surface_set_device_scale (copy, x_scale, y_scale);
cr = cairo_create (copy);
cairo_set_source_surface (cr, orig, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
return copy;
}
// code of get_wm_name() based in large chunks on www.amsn-project.net
gchar*
get_wm_name (Display* dpy)
{
int screen;
Atom type;
int format;
unsigned long bytes_returned;
unsigned long n_returned;
unsigned char* buffer;
Window* child;
Window root;
Atom supwmcheck;
Atom wmname;
if (!dpy)
return NULL;
screen = DefaultScreen (dpy);
root = RootWindow (dpy, screen);
supwmcheck = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", False);
wmname = XInternAtom (dpy, "_NET_WM_NAME", False);
XGetWindowProperty (dpy,
root,
supwmcheck,
0,
8,
False,
AnyPropertyType,
&type,
&format,
&n_returned,
&bytes_returned,
&buffer);
child = (Window*) buffer;
if (n_returned != 1)
return NULL;
XGetWindowProperty (dpy,
*child,
wmname,
0,
128,
False,
AnyPropertyType,
&type,
&format,
&n_returned,
&bytes_returned,
&buffer);
if (n_returned == 0)
return NULL;
XFree (child);
// example wm-names as reported by get_wm_name()
//
// compiz
// Metacity
// Xfwm4
// KWin
// xmonad
return (gchar*) buffer;
}
GString*
extract_font_face (const gchar* string)
{
GRegex* regex = NULL;
GMatchInfo* match_info = NULL;
GString* font_face = NULL;
// sanity check
if (!string)
return NULL;
// extract font-face-name/style
font_face = g_string_new ("");
if (!font_face)
return NULL;
// setup regular expression to extract leading text before trailing int
regex = g_regex_new ("([A-Z a-z])+", 0, 0, NULL);
// walk the string
g_regex_match (regex, string, 0, &match_info);
while (g_match_info_matches (match_info))
{
gchar* word = NULL;
word = g_match_info_fetch (match_info, 0);
if (word)
{
g_string_append (font_face, word);
g_free (word);
}
g_match_info_next (match_info, NULL);
}
// clean up
g_match_info_free (match_info);
g_regex_unref (regex);
return font_face;
}
./src/stack-blur.c 0000644 0000156 0000165 00000015516 12704153542 014112 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// raico-blur
//
// stack-blur.c - implements stack-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// Notes:
// based on stack-blur algorithm by Mario Klingemann
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
// FIXME: not working yet, unfinished
#include
#include
#include "stack-blur.h"
void
surface_stack_blur (cairo_surface_t* surface,
guint radius)
{
guchar* pixels;
guint width;
guint height;
cairo_format_t format;
// sanity checks are done in raico-blur.c
// before we mess with the surface execute any pending drawing
cairo_surface_flush (surface);
pixels = cairo_image_surface_get_data (surface);
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
format = cairo_image_surface_get_format (surface);
switch (format)
{
case CAIRO_FORMAT_ARGB32:{
gint w = width;
gint h = height;
gint wm = w - 1;
gint hm = h - 1;
gint wh = w * h;
gint div = radius + radius + 1;
if (radius < 1)
break;
gint* r = (gint*) g_malloc0 (wh);
gint* g = (gint*) g_malloc0 (wh);
gint* b = (gint*) g_malloc0 (wh);
gint* a = (gint*) g_malloc0 (wh);
gint rsum;
gint gsum;
gint bsum;
gint asum;
gint x;
gint y;
gint i;
gint yp;
gint yi;
gint yw;
gint* dv = NULL;
gint* vmin = (gint*) g_malloc0 (MAX (w, h));
gint divsum = (div + 1) >> 1;
divsum *= divsum;
dv = (gint*) g_malloc0 (256 * divsum);
g_assert (dv != NULL);
for (i = 0; i < 256 * divsum; ++i)
dv[i] = (i / divsum);
yw = yi = 0;
gint** stack = (gint**) g_malloc0 (div);
for (i = 0; i < div; ++i)
stack[i] = (gint*) g_malloc0 (4);
gint stackpointer;
gint stackstart;
gint* sir;
gint rbs;
gint r1 = radius + 1;
gint routsum;
gint goutsum;
gint boutsum;
gint aoutsum;
gint rinsum;
gint ginsum;
gint binsum;
gint ainsum;
for (y = 0; y < h; ++y)
{
rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
for(i =- radius; i <= radius; ++i)
{
sir = stack[i + radius];
sir[0] = pixels[yi + MIN (wm, MAX (i, 0)) + 0];
sir[1] = pixels[yi + MIN (wm, MAX (i, 0)) + 1];
sir[2] = pixels[yi + MIN (wm, MAX (i, 0)) + 2];
sir[3] = pixels[yi + MIN (wm, MAX (i, 0)) + 3];
rbs = r1 - abs (i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
asum += sir[3] * rbs;
if (i > 0)
{
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
}
else
{
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
}
}
stackpointer = radius;
for (x = 0; x < w; ++x)
{
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
a[yi] = dv[asum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
asum -= aoutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
aoutsum -= sir[3];
if (y == 0)
vmin[x] = MIN (x + radius + 1, wm);
sir[0] = pixels[yw + vmin[x] + 0];
sir[1] = pixels[yw + vmin[x] + 1];
sir[2] = pixels[yw + vmin[x] + 2];
sir[3] = pixels[yw + vmin[x] + 3];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
asum += ainsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
ainsum -= sir[3];
++yi;
}
yw += w;
}
for (x = 0; x < w; ++x)
{
rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0;
yp =- radius * w;
for (i =- radius; i <= radius; ++i)
{
yi = MAX (0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
sir[3] = a[yi];
rbs = r1 - abs (i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
asum += a[yi] * rbs;
if (i > 0)
{
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
}
else
{
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
}
if (i < hm)
yp += w;
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; ++y)
{
pixels[yi + 0] = dv[rsum];
pixels[yi + 1] = dv[gsum];
pixels[yi + 2] = dv[bsum];
pixels[yi + 3] = dv[asum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
asum -= aoutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
aoutsum -= sir[3];
if (x == 0)
vmin[y] = MIN (y + r1, hm) * w;
gint pixel = x + vmin[y];
sir[0] = r[pixel];
sir[1] = g[pixel];
sir[2] = b[pixel];
sir[3] = a[pixel];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
ainsum += sir[3];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
asum += ainsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
aoutsum += sir[3];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
ainsum -= sir[3];
yi += w;
}
}
g_free ((gpointer) r);
g_free ((gpointer) g);
g_free ((gpointer) b);
g_free ((gpointer) a);
g_free ((gpointer) vmin);
g_free ((gpointer) dv);
for (i = 0; i < div; ++i)
g_free ((gpointer) stack[i]);
g_free ((gpointer) stack);
}
break;
case CAIRO_FORMAT_RGB24:
// do nothing, for the moment
break;
case CAIRO_FORMAT_A8:
// do nothing, for the moment
break;
default :
// really do nothing
break;
}
// inform cairo we altered the surfaces contents
cairo_surface_mark_dirty (surface);
}
./src/apport.c 0000644 0000156 0000165 00000002645 12704153542 013347 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** apport.c - apport hooks for triggering bug-reports on non-spec notifications
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#include
void
apport_report (const gchar* app_name,
const gchar* summary,
gchar** actions,
gint timeout)
{
/* call /usr/share/apport/notification_hook
passing all the arguments in the request
*/
}
./src/dnd.h 0000644 0000156 0000165 00000003034 12704153542 012605 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** dnd.h - implements the "do not disturb"-mode, e.g. screensaver, presentations
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __DND_H
#define __DNS_H
G_BEGIN_DECLS
/* Tries to determine whether the user is in "do not disturb" mode */
gboolean
dnd_dont_disturb_user (void);
gboolean
dnd_is_xscreensaver_active (void);
gboolean
dnd_is_idle_inhibited (void);
gboolean
dnd_is_screensaver_active (void);
gboolean
dnd_has_one_fullscreen_window (void);
G_END_DECLS
#endif /* __DND_H */
./src/stack.h 0000644 0000156 0000165 00000007351 12704153542 013153 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** stack.h - implements singelton handling all the internal queue-logic
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __STACK_H
#define __STACK_H
#include
#include
#include
#include "defaults.h"
#include "bubble.h"
#include "observer.h"
G_BEGIN_DECLS
#define STACK_TYPE (stack_get_type ())
#define STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STACK_TYPE, Stack))
#define STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STACK_TYPE, StackClass))
#define IS_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STACK_TYPE))
#define IS_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STACK_TYPE))
#define STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STACK_TYPE, StackClass))
#define MAX_STACK_SIZE 50
#define VACANT TRUE
#define OCCUPIED FALSE
typedef struct _Stack Stack;
typedef struct _StackClass StackClass;
typedef enum
{
SLOT_TOP = 0,
SLOT_BOTTOM
} Slot;
/* instance structure */
struct _Stack
{
GObject parent;
/* private */
Defaults* defaults;
Observer* observer;
GList* list;
guint next_id;
Bubble* slots[2]; // NULL: vacant, non-NULL: occupied
};
/* class structure */
struct _StackClass
{
GObjectClass parent;
};
GType stack_get_type (void);
Stack*
stack_new (Defaults* defaults,
Observer* observer);
void
stack_del (Stack* self);
guint
stack_push_bubble (Stack* self,
Bubble* bubble);
void
stack_pop_bubble_by_id (Stack* self,
guint id);
gboolean
stack_notify_handler (Stack* self,
const gchar* app_name,
guint id,
const gchar* icon,
const gchar* summary,
const gchar* body,
gchar** actions,
GHashTable* hints,
gint timeout,
DBusGMethodInvocation* context);
gboolean
stack_close_notification_handler (Stack* self,
guint id,
GError** error);
gboolean
stack_get_capabilities (Stack* self,
gchar*** out_caps);
gboolean
stack_get_server_information (Stack* self,
gchar** out_name,
gchar** out_vendor,
gchar** out_version,
gchar** out_spec_ver);
gboolean
stack_is_slot_vacant (Stack* self,
Slot slot);
void
stack_get_slot_position (Stack* self,
Slot slot,
gint bubble_height,
gint* x,
gint* y);
gboolean
stack_allocate_slot (Stack* self,
Bubble* bubble,
Slot slot);
gboolean
stack_free_slot (Stack* self,
Bubble* bubble);
G_END_DECLS
#endif /* __STACK_H */
./src/bubble.c 0000644 0000156 0000165 00000274242 12704153556 013306 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// bubble.c - implements all the rendering of a notification bubble
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
// David Barth
//
// Contributor(s):
// Frederic "fredp" Peters (icon-only fix, rev. 204)
// Eitan Isaacson (ATK interface for a11y, rev. 351)
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include "bubble.h"
#include "defaults.h"
#include "stack.h"
#include "dbus.h"
#include "util.h"
#include "bubble-window.h"
#include "raico-blur.h"
#include "tile.h"
struct _BubblePrivate {
BubbleLayout layout;
GtkWidget* widget;
gboolean visible;
guint timer_id;
gboolean mouse_over;
gfloat distance;
gchar* synchronous;
gboolean composited;
EggAlpha* alpha;
EggTimeline* timeline;
guint draw_handler_id;
guint pointer_update_id;
tile_t* tile_background_part;
tile_t* tile_background;
tile_t* tile_icon;
tile_t* tile_title;
tile_t* tile_body;
tile_t* tile_indicator;
gint title_width;
gint title_height;
gint body_width;
gint body_height;
gboolean append;
gboolean icon_only;
gint future_height;
gboolean prevent_fade;
// these will be replaced by class Notification later on
GString* title;
GString* message_body;
gboolean title_needs_refresh;
gboolean message_body_needs_refresh;
guint id;
GdkPixbuf* icon_pixbuf;
gint value; // "empty": -2, valid range: -1..101, -1/101 trigger "over/undershoot"-effect
gchar* sender;
guint timeout;
guint urgency;
//notification_t* notification;
// used to prevent unneeded updates of the tile-cache, for append-,
// update or replace-cases, needs to move into class Notification
gchar * old_icon_filename;
};
G_DEFINE_TYPE_WITH_PRIVATE (Bubble, bubble, G_TYPE_OBJECT);
enum
{
TIMED_OUT,
VALUE_CHANGED,
MESSAGE_BODY_DELETED,
MESSAGE_BODY_INSERTED,
LAST_SIGNAL
};
enum
{
R = 0,
G,
B,
A
};
typedef struct _NotifyHSVColor NotifyHSVColor;
struct _NotifyHSVColor {
gdouble hue;
gdouble saturation;
gdouble value;
};
// FIXME: this is in class Defaults already, but not yet hooked up so for the
// moment we use the macros here, these values reflect the visual-guideline
// for jaunty notifications
#define TEXT_TITLE_COLOR_R 1.0f
#define TEXT_TITLE_COLOR_G 1.0f
#define TEXT_TITLE_COLOR_B 1.0f
#define TEXT_TITLE_COLOR_A 1.0f
#define TEXT_BODY_COLOR_R 0.91f
#define TEXT_BODY_COLOR_G 0.91f
#define TEXT_BODY_COLOR_B 0.91f
#define TEXT_BODY_COLOR_A 1.0f
#define TEXT_SHADOW_COLOR_R 0.0f
#define TEXT_SHADOW_COLOR_G 0.0f
#define TEXT_SHADOW_COLOR_B 0.0f
#define TEXT_SHADOW_COLOR_A 1.0f
#define BUBBLE_BG_COLOR_R 0.15f
#define BUBBLE_BG_COLOR_G 0.15f
#define BUBBLE_BG_COLOR_B 0.15f
#define BUBBLE_BG_COLOR_A 0.9f
#define INDICATOR_UNLIT_R 1.0f
#define INDICATOR_UNLIT_G 1.0f
#define INDICATOR_UNLIT_B 1.0f
#define INDICATOR_UNLIT_A 0.3f
#define INDICATOR_LIT_R 1.0f
#define INDICATOR_LIT_G 1.0f
#define INDICATOR_LIT_B 1.0f
#define INDICATOR_LIT_A 1.0f
#define FPS 60
#define PROXIMITY_THRESHOLD 40
#define WINDOW_MIN_OPACITY 0.4f
#define WINDOW_MAX_OPACITY 1.0f
// text drop-shadow should _never_ be bigger than content blur-radius!!!
#define BUBBLE_CONTENT_BLUR_RADIUS 4
#define TEXT_DROP_SHADOW_SIZE 2
//-- private functions ---------------------------------------------------------
static guint g_bubble_signals[LAST_SIGNAL] = { 0 };
gint g_pointer[2];
static cairo_surface_t *
bubble_create_image_surface (Bubble* self,
cairo_format_t format,
gint width,
gint height)
{
cairo_surface_t *surface;
gint scale;
scale = gtk_widget_get_scale_factor (self->priv->widget);
surface = cairo_image_surface_create (format, scale * width, scale * height);
cairo_surface_set_device_scale (surface, scale, scale);
return surface;
}
static void
draw_round_rect (cairo_t* cr,
gdouble aspect, // aspect-ratio
gdouble x, // top-left corner
gdouble y, // top-left corner
gdouble corner_radius, // "size" of the corners
gdouble width, // width of the rectangle
gdouble height) // height of the rectangle
{
gdouble radius = corner_radius / aspect;
// top-left, right of the corner
cairo_move_to (cr, x + radius, y);
// top-right, left of the corner
cairo_line_to (cr,
x + width - radius,
y);
// top-right, below the corner
cairo_arc (cr,
x + width - radius,
y + radius,
radius,
-90.0f * G_PI / 180.0f,
0.0f * G_PI / 180.0f);
// bottom-right, above the corner
cairo_line_to (cr,
x + width,
y + height - radius);
// bottom-right, left of the corner
cairo_arc (cr,
x + width - radius,
y + height - radius,
radius,
0.0f * G_PI / 180.0f,
90.0f * G_PI / 180.0f);
// bottom-left, right of the corner
cairo_line_to (cr,
x + radius,
y + height);
// bottom-left, above the corner
cairo_arc (cr,
x + radius,
y + height - radius,
radius,
90.0f * G_PI / 180.0f,
180.0f * G_PI / 180.0f);
// top-left, below the corner
cairo_line_to (cr,
x,
y + radius);
// top-left, right of the corner
cairo_arc (cr,
x + radius,
y + radius,
radius,
180.0f * G_PI / 180.0f,
270.0f * G_PI / 180.0f);
}
// color-, alpha-, radius-, width-, height- and gradient-values were determined
// by very close obvervation of a SVG-mockup from the design-team
static void
_draw_value_indicator (cairo_t* cr,
gint value, // value to render: 0 - 100
gint start_x, // top of surrounding rect
gint start_y, // left of surrounding rect
gint width, // width of surrounding rect
gint height, // height of surrounding rect
gint outline_thickness) // outline-thickness
{
gdouble outline_radius;
gdouble outline_width;
gdouble outline_height;
gdouble bar_radius;
gdouble bar_width;
//gdouble bar_height;
cairo_pattern_t* gradient;
outline_radius = outline_thickness;
outline_width = width;
outline_height = height;
// draw bar-background
cairo_set_line_width (cr, outline_thickness);
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 0.5f);
draw_round_rect (cr,
1.0f,
start_x,
start_y,
outline_radius,
outline_width,
outline_height);
cairo_fill (cr);
gradient = cairo_pattern_create_linear (0.0f,
start_y + outline_thickness,
0.0f,
start_y +
outline_height -
2 * outline_thickness);
cairo_pattern_add_color_stop_rgba (gradient,
0.0f,
0.866f,
0.866f,
0.866f,
0.3f);
cairo_pattern_add_color_stop_rgba (gradient,
0.2f,
0.827f,
0.827f,
0.827f,
0.3f);
cairo_pattern_add_color_stop_rgba (gradient,
0.3f,
0.772f,
0.772f,
0.772f,
0.3f);
cairo_pattern_add_color_stop_rgba (gradient,
1.0f,
0.623f,
0.623f,
0.623f,
0.3f);
cairo_set_source (cr, gradient);
draw_round_rect (cr,
1.0f,
start_x + outline_thickness,
start_y + outline_thickness,
outline_radius,
outline_width - 2 * outline_thickness,
outline_height - 2 * outline_thickness);
cairo_fill (cr);
cairo_pattern_destroy (gradient);
bar_radius = outline_radius;
bar_width = outline_width - 2 * outline_radius;
//bar_height = outline_height - outline_radius;
// draw value-bar
if (value > 0)
{
gint corrected_value = value;
if (corrected_value > 100)
corrected_value = 100;
draw_round_rect (cr,
1.0f,
start_x + outline_thickness,
start_y + outline_thickness,
bar_radius,
bar_width / 100.0f * (gdouble) corrected_value,
outline_height - 2 * outline_thickness);
gradient = cairo_pattern_create_linear (0.0f,
start_y +
outline_thickness,
0.0f,
start_y +
outline_height -
2 * outline_thickness);
cairo_pattern_add_color_stop_rgba (gradient,
0.0f,
0.9f,
0.9f,
0.9f,
1.0f);
cairo_pattern_add_color_stop_rgba (gradient,
0.75f,
0.5f,
0.5f,
0.5f,
1.0f);
cairo_pattern_add_color_stop_rgba (gradient,
1.0f,
0.4f,
0.4f,
0.4f,
1.0f);
cairo_set_source (cr, gradient);
cairo_fill (cr);
cairo_pattern_destroy (gradient);
}
}
void
_draw_shadow (Bubble* self,
cairo_t* cr,
gdouble width,
gdouble height,
gint shadow_radius,
gint corner_radius)
{
cairo_surface_t* tmp_surface = NULL;
cairo_surface_t* new_surface = NULL;
cairo_pattern_t* pattern = NULL;
cairo_t* cr_surf = NULL;
cairo_matrix_t matrix;
raico_blur_t* blur = NULL;
double x_scale;
double y_scale;
tmp_surface = bubble_create_image_surface (self,
CAIRO_FORMAT_ARGB32,
4 * shadow_radius,
4 * shadow_radius);
if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS) {
if (tmp_surface)
cairo_surface_destroy (tmp_surface);
return;
}
cr_surf = cairo_create (tmp_surface);
if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
if (cr_surf)
cairo_destroy (cr_surf);
return;
}
cairo_scale (cr_surf, 1.0f, 1.0f);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr_surf);
cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 1.0f);
cairo_arc (cr_surf,
2 * shadow_radius,
2 * shadow_radius,
1.75f * corner_radius,
0.0f,
360.0f * (G_PI / 180.f));
cairo_fill (cr_surf);
cairo_destroy (cr_surf);
// create and setup blur
blur = raico_blur_create (RAICO_BLUR_QUALITY_HIGH);
raico_blur_set_radius (blur, shadow_radius);
// now blur it
raico_blur_apply (blur, tmp_surface);
// blur no longer needed
raico_blur_destroy (blur);
new_surface = cairo_image_surface_create_for_data (
cairo_image_surface_get_data (tmp_surface),
cairo_image_surface_get_format (tmp_surface),
cairo_image_surface_get_width (tmp_surface) / 2,
cairo_image_surface_get_height (tmp_surface) / 2,
cairo_image_surface_get_stride (tmp_surface));
cairo_surface_get_device_scale (tmp_surface, &x_scale, &y_scale);
cairo_surface_set_device_scale (new_surface, x_scale, y_scale);
pattern = cairo_pattern_create_for_surface (new_surface);
if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
if (pattern)
cairo_pattern_destroy (pattern);
return;
}
// top left
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_set_source (cr, pattern);
cairo_rectangle (cr,
0.0f,
0.0f,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// bottom left
cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
cairo_matrix_translate (&matrix, 0.0f, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
0.0f,
2 * shadow_radius,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// top right
cairo_matrix_init_scale (&matrix, -1.0f, 1.0f);
cairo_matrix_translate (&matrix, -width, 0.0f);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
width - 2 * shadow_radius,
0.0f,
2 * shadow_radius,
height - 2 * shadow_radius);
cairo_fill (cr);
// bottom right
cairo_matrix_init_scale (&matrix, -1.0f, -1.0f);
cairo_matrix_translate (&matrix, -width, -height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
2 * shadow_radius,
height - 2 * shadow_radius,
width - 2 * shadow_radius,
2 * shadow_radius);
cairo_fill (cr);
// clean up
cairo_pattern_destroy (pattern);
cairo_surface_destroy (tmp_surface);
cairo_surface_destroy (new_surface);
}
static gdouble
get_shadow_size (Bubble *bubble)
{
BubblePrivate* priv = bubble->priv;
Defaults* d = bubble->defaults;
return defaults_get_bubble_shadow_size (d, priv->composited);
}
static gdouble
get_corner_radius (Bubble *bubble)
{
BubblePrivate* priv = bubble->priv;
Defaults* d = bubble->defaults;
return defaults_get_bubble_corner_radius (d, priv->composited);
}
static void
_draw_layout_grid (cairo_t* cr,
Bubble* bubble)
{
Defaults* d = bubble->defaults;
if (!cr)
return;
cairo_set_line_width (cr, 1.0f);
cairo_set_source_rgba (cr, 1.0f, 0.5f, 0.25f, 1.0f);
// all vertical grid lines
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (2 * defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (2 * defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d) -
EM2PIXELS (defaults_get_margin_size (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d) -
EM2PIXELS (defaults_get_margin_size (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
// all horizontal grid lines
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_margin_size (d), d) +
EM2PIXELS (defaults_get_icon_size (d), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d) -
EM2PIXELS (defaults_get_margin_size (d), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d) -
EM2PIXELS (defaults_get_margin_size (d), d));
cairo_move_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_line_to (cr,
0.5f + EM2PIXELS (get_shadow_size (bubble), d) +
EM2PIXELS (defaults_get_bubble_width (d), d),
0.5f + (gdouble) bubble_get_height (bubble) -
EM2PIXELS (get_shadow_size (bubble), d));
cairo_stroke (cr);
}
void
_refresh_background (Bubble* self)
{
BubblePrivate* priv = self->priv;
Defaults* d = self->defaults;
cairo_t* cr = NULL;
cairo_surface_t* scratch = NULL;
cairo_surface_t* clone = NULL;
cairo_surface_t* normal = NULL;
cairo_surface_t* blurred = NULL;
raico_blur_t* blur = NULL;
gint width;
gint height;
gint scratch_shadow_size;
bubble_get_size (self, &width, &height);
// create temp. scratch surface for top-left shadow/background part
if (priv->composited)
{
scratch_shadow_size = EM2PIXELS (get_shadow_size (self), d);
scratch = bubble_create_image_surface (
self,
CAIRO_FORMAT_ARGB32,
3 * scratch_shadow_size,
3 * scratch_shadow_size);
}
else
{
// We must have at least some width to this scratch surface.
scratch_shadow_size = 1;
scratch = bubble_create_image_surface (
self,
CAIRO_FORMAT_RGB24,
3 * scratch_shadow_size,
3 * scratch_shadow_size);
}
g_return_if_fail (scratch);
if (cairo_surface_status (scratch) != CAIRO_STATUS_SUCCESS)
{
if (scratch)
cairo_surface_destroy (scratch);
return;
}
// create drawing context for that temp. scratch surface
cr = cairo_create (scratch);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (scratch);
if (cr)
cairo_destroy (cr);
return;
}
// clear, render top-left part of shadow/background in scratch-surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
GdkRGBA color;
gchar* color_string = NULL;
color_string = defaults_get_bubble_bg_color (d);
gdk_rgba_parse (&color, color_string);
g_free (color_string);
// Apply color tweaks
NotifyHSVColor hsv_color;
gtk_rgb_to_hsv (color.red, color.green, color.blue,
&hsv_color.hue, &hsv_color.saturation, &hsv_color.value);
hsv_color.saturation *= (2.0f - hsv_color.saturation);
hsv_color.value = MIN (hsv_color.value, 0.4f);
gtk_hsv_to_rgb (hsv_color.hue, hsv_color.saturation, hsv_color.value,
&color.red, &color.green, &color.blue);
if (priv->composited)
{
_draw_shadow (
self,
cr,
width,
height,
EM2PIXELS (get_shadow_size (self), d),
EM2PIXELS (get_corner_radius (self), d));
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
draw_round_rect (
cr,
1.0f,
EM2PIXELS (get_shadow_size (self), d),
EM2PIXELS (get_shadow_size (self), d),
EM2PIXELS (get_corner_radius (self), d),
EM2PIXELS (defaults_get_bubble_width (d), d),
(gdouble) bubble_get_height (self) -
2.0f * EM2PIXELS (get_shadow_size (self), d));
cairo_fill (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr,
color.red,
color.green,
color.blue,
BUBBLE_BG_COLOR_A);
}
else
cairo_set_source_rgb (cr,
color.red,
color.green,
color.blue);
draw_round_rect (
cr,
1.0f,
EM2PIXELS (get_shadow_size (self), d),
EM2PIXELS (get_shadow_size (self), d),
EM2PIXELS (get_corner_radius (self), d),
EM2PIXELS (defaults_get_bubble_width (d), d),
(gdouble) bubble_get_height (self) -
2.0f * EM2PIXELS (get_shadow_size (self), d));
cairo_fill (cr);
cairo_destroy (cr);
// create temp. clone of scratch surface
clone = copy_surface (scratch);
// create normal surface from that surface-clone
normal = copy_surface (clone);
// now blur the surface-clone
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, BUBBLE_CONTENT_BLUR_RADIUS);
raico_blur_apply (blur, clone);
raico_blur_destroy (blur);
// create blurred version from that blurred surface-clone
blurred = copy_surface (clone);
cairo_surface_destroy (clone);
// finally create tile with top-left shadow/background part
if (priv->tile_background_part)
tile_destroy (priv->tile_background_part);
priv->tile_background_part = tile_new_for_padding (normal, blurred,
3 * scratch_shadow_size,
3 * scratch_shadow_size);
cairo_surface_destroy (normal);
cairo_surface_destroy (blurred);
// create surface(s) for full shadow/background tile
if (priv->composited)
{
// we need two RGBA-surfaces
normal = bubble_create_image_surface (self,
CAIRO_FORMAT_ARGB32,
width,
height);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (scratch);
if (normal)
cairo_surface_destroy (normal);
return;
}
blurred = bubble_create_image_surface (self,
CAIRO_FORMAT_ARGB32,
width,
height);
if (cairo_surface_status (blurred) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
cairo_surface_destroy (scratch);
if (blurred)
cairo_surface_destroy (blurred);
return;
}
}
else
{
// we need only one RGB-surface
normal = bubble_create_image_surface (self,
CAIRO_FORMAT_RGB24,
width,
height);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (scratch);
if (normal)
cairo_surface_destroy (normal);
return;
}
}
// use tile for top-left background-part to fill the full bg-surface
if (priv->composited)
{
// create context for blurred surface
cr = cairo_create (blurred);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
cairo_surface_destroy (blurred);
cairo_surface_destroy (scratch);
if (cr)
cairo_destroy (cr);
return;
}
// clear blurred surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
// fill with blurred state of background-part tile
tile_paint_with_padding (priv->tile_background_part,
cr,
0.0f,
0.0f,
width,
height,
0.0f,
1.0f);
// get rid of context for blurred surface
cairo_destroy (cr);
}
// create context for normal surface
cr = cairo_create (normal);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
cairo_surface_destroy (scratch);
if (priv->composited)
cairo_surface_destroy (blurred);
return;
}
// clear normal surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
// fill with normal state of background-part tile
tile_paint_with_padding (priv->tile_background_part,
cr,
0.0f,
0.0f,
width,
height,
1.0f,
0.0f);
// get rid of context for normal surface
cairo_destroy (cr);
// finally create tile for full background
if (priv->tile_background)
tile_destroy (priv->tile_background);
if (priv->composited)
priv->tile_background = tile_new_for_padding (normal, blurred, width, height);
else
priv->tile_background = tile_new_for_padding (normal, normal, width, height);
// clean up
if (priv->composited)
cairo_surface_destroy (blurred);
cairo_surface_destroy (normal);
cairo_surface_destroy (scratch);
}
void
_refresh_icon (Bubble* self)
{
BubblePrivate* priv = self->priv;
Defaults* d = self->defaults;
cairo_surface_t* normal = NULL;
cairo_surface_t* icon_surface = NULL;
cairo_t* cr = NULL;
if (!priv->icon_pixbuf)
return;
// create temp. scratch surface
normal = bubble_create_image_surface (
self,
CAIRO_FORMAT_ARGB32,
EM2PIXELS (defaults_get_icon_size (d), d) +
2 * BUBBLE_CONTENT_BLUR_RADIUS,
EM2PIXELS (defaults_get_icon_size (d), d) +
2 * BUBBLE_CONTENT_BLUR_RADIUS);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
return;
// create context for normal surface
cr = cairo_create (normal);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
return;
}
// clear normal surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
// render icon into normal surface
icon_surface = gdk_cairo_surface_create_from_pixbuf (priv->icon_pixbuf, 0,
gtk_widget_get_window (priv->widget));
cairo_set_source_surface (cr,
icon_surface,
BUBBLE_CONTENT_BLUR_RADIUS,
BUBBLE_CONTENT_BLUR_RADIUS);
cairo_paint (cr);
// create the surface/blur-cache from the normal surface
if (priv->tile_icon)
tile_destroy (priv->tile_icon);
priv->tile_icon = tile_new (normal, BUBBLE_CONTENT_BLUR_RADIUS/2);
// clean up
cairo_destroy (cr);
cairo_surface_destroy (icon_surface);
cairo_surface_destroy (normal);
}
void
_refresh_title (Bubble* self)
{
BubblePrivate* priv = self->priv;
Defaults* d = self->defaults;
cairo_surface_t* normal = NULL;
cairo_t* cr = NULL;
PangoFontDescription* desc = NULL;
PangoLayout* layout = NULL;
raico_blur_t* blur = NULL;
gchar* text_font_face = NULL;
// create temp. scratch surface
normal = bubble_create_image_surface (
self,
CAIRO_FORMAT_ARGB32,
priv->title_width + 2 * BUBBLE_CONTENT_BLUR_RADIUS,
priv->title_height + 2 * BUBBLE_CONTENT_BLUR_RADIUS);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
return;
// create context for normal surface
cr = cairo_create (normal);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
return;
}
// clear normal surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
// create pango desc/layout
layout = pango_cairo_create_layout (cr);
text_font_face = defaults_get_text_font_face (d);
desc = pango_font_description_from_string (text_font_face);
g_free ((gpointer) text_font_face);
pango_font_description_set_size (desc,
defaults_get_system_font_size (d) *
defaults_get_text_title_size (d) *
PANGO_SCALE);
pango_font_description_set_weight (desc,
defaults_get_text_title_weight (d));
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
pango_layout_set_width (layout, priv->title_width * PANGO_SCALE);
pango_layout_set_height (layout, priv->title_height * PANGO_SCALE);
// print and layout string (pango-wise)
pango_layout_set_text (layout, priv->title->str, priv->title->len);
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (
pango_layout_get_context (layout),
gdk_screen_get_font_options (
gtk_widget_get_screen (priv->widget)));
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
defaults_get_screen_dpi (d));
pango_layout_context_changed (layout);
// draw text for drop-shadow and ...
cairo_move_to (cr,
BUBBLE_CONTENT_BLUR_RADIUS,
BUBBLE_CONTENT_BLUR_RADIUS);
cairo_set_source_rgba (cr,
TEXT_SHADOW_COLOR_R,
TEXT_SHADOW_COLOR_G,
TEXT_SHADOW_COLOR_B,
TEXT_SHADOW_COLOR_A);
pango_cairo_show_layout (cr, layout);
// ... blur it
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, TEXT_DROP_SHADOW_SIZE);
raico_blur_apply (blur, normal);
raico_blur_destroy (blur);
// now draw normal (non-blurred) text over drop-shadow
cairo_set_source_rgba (cr,
TEXT_TITLE_COLOR_R,
TEXT_TITLE_COLOR_G,
TEXT_TITLE_COLOR_B,
TEXT_TITLE_COLOR_A);
pango_cairo_show_layout (cr, layout);
g_object_unref (layout);
// create the surface/blur-cache from the normal surface
if (priv->tile_title)
tile_destroy (priv->tile_title);
priv->tile_title = tile_new (normal, BUBBLE_CONTENT_BLUR_RADIUS);
// clean up
cairo_destroy (cr);
cairo_surface_destroy (normal);
// reset refresh-flag
priv->title_needs_refresh = FALSE;
}
void
_refresh_body (Bubble* self)
{
BubblePrivate* priv = self->priv;
Defaults* d = self->defaults;
cairo_surface_t* normal = NULL;
cairo_t* cr = NULL;
PangoFontDescription* desc = NULL;
PangoLayout* layout = NULL;
raico_blur_t* blur = NULL;
gchar* text_font_face = NULL;
// create temp. scratch surface
normal = bubble_create_image_surface (
self,
CAIRO_FORMAT_ARGB32,
priv->body_width + 2 * BUBBLE_CONTENT_BLUR_RADIUS,
priv->body_height + 2 * BUBBLE_CONTENT_BLUR_RADIUS);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
return;
// create context for normal surface
cr = cairo_create (normal);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
return;
}
// clear normal surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
// create pango desc/layout
layout = pango_cairo_create_layout (cr);
text_font_face = defaults_get_text_font_face (d);
desc = pango_font_description_from_string (text_font_face);
g_free ((gpointer) text_font_face);
pango_font_description_set_size (desc,
defaults_get_system_font_size (d) *
defaults_get_text_body_size (d) *
PANGO_SCALE);
pango_font_description_set_weight (desc,
defaults_get_text_body_weight (d));
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
pango_layout_set_width (layout, priv->body_width * PANGO_SCALE);
pango_layout_set_height (layout, priv->body_height * PANGO_SCALE);
// print and layout string (pango-wise)
pango_layout_set_text (layout,
priv->message_body->str,
priv->message_body->len);
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (
pango_layout_get_context (layout),
gdk_screen_get_font_options (
gtk_widget_get_screen (priv->widget)));
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
defaults_get_screen_dpi (d));
pango_layout_context_changed (layout);
// draw text for drop-shadow and ...
cairo_move_to (cr,
BUBBLE_CONTENT_BLUR_RADIUS,
BUBBLE_CONTENT_BLUR_RADIUS);
cairo_set_source_rgba (cr,
TEXT_SHADOW_COLOR_R,
TEXT_SHADOW_COLOR_G,
TEXT_SHADOW_COLOR_B,
TEXT_SHADOW_COLOR_A);
pango_cairo_show_layout (cr, layout);
// ... blur it
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, TEXT_DROP_SHADOW_SIZE);
raico_blur_apply (blur, normal);
raico_blur_destroy (blur);
// now draw normal (non-blurred) text over drop-shadow
cairo_set_source_rgba (cr,
TEXT_BODY_COLOR_R,
TEXT_BODY_COLOR_G,
TEXT_BODY_COLOR_B,
TEXT_BODY_COLOR_A);
pango_cairo_show_layout (cr, layout);
g_object_unref (layout);
// create the surface/blur-cache from the normal surface
if (priv->tile_body)
tile_destroy (priv->tile_body);
priv->tile_body = tile_new (normal, BUBBLE_CONTENT_BLUR_RADIUS);
// clean up
cairo_destroy (cr);
cairo_surface_destroy (normal);
// reset refresh-flag
priv->message_body_needs_refresh = FALSE;
}
void
_refresh_indicator (Bubble* self)
{
BubblePrivate* priv = self->priv;
Defaults* d = self->defaults;
cairo_surface_t* normal = NULL;
cairo_t* cr = NULL;
// create temp. scratch surface
normal = bubble_create_image_surface (
self,
CAIRO_FORMAT_ARGB32,
EM2PIXELS (defaults_get_bubble_width (d), d) -
3 * EM2PIXELS (defaults_get_margin_size (d), d) -
EM2PIXELS (defaults_get_icon_size (d), d)
+ 2 * BUBBLE_CONTENT_BLUR_RADIUS,
EM2PIXELS (defaults_get_icon_size (d), d) / 5.0f
+ 2 * BUBBLE_CONTENT_BLUR_RADIUS);
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS)
return;
// create context for normal surface
cr = cairo_create (normal);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (normal);
return;
}
// clear normal surface
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
_draw_value_indicator (
cr,
priv->value,
BUBBLE_CONTENT_BLUR_RADIUS,
BUBBLE_CONTENT_BLUR_RADIUS,
EM2PIXELS (defaults_get_bubble_width (d), d) -
3 * EM2PIXELS (defaults_get_margin_size (d), d) -
EM2PIXELS (defaults_get_icon_size (d), d),
EM2PIXELS (defaults_get_gauge_size (d), d),
EM2PIXELS (defaults_get_gauge_outline_width (d), d));
// create the surface/blur-cache from the normal surface
if (priv->tile_indicator)
tile_destroy (priv->tile_indicator);
priv->tile_indicator = tile_new (normal, BUBBLE_CONTENT_BLUR_RADIUS/2);
// clean up
cairo_destroy (cr);
cairo_surface_destroy (normal);
}
void
_render_background (Bubble* self,
cairo_t* cr,
gdouble alpha_normal,
gdouble alpha_blur)
{
Defaults* d = self->defaults;
tile_paint (self->priv->tile_background,
cr,
0.0f,
0.0f,
alpha_normal,
alpha_blur);
// layout-grid and urgency-indication bar
if (g_getenv ("DEBUG"))
{
// for debugging layout and positioning issues
_draw_layout_grid (cr, self);
switch (bubble_get_urgency (self))
{
// low urgency-bar is painted blue
case 0:
cairo_set_source_rgb (cr, 0.25f, 0.5f, 1.0f);
break;
// normal urgency-bar is painted green
case 1:
cairo_set_source_rgb (cr, 0.0f, 1.0f, 0.0f);
break;
// urgent urgency-bar is painted red
case 2:
cairo_set_source_rgb (cr, 1.0f, 0.0f, 0.0f);
break;
default:
break;
}
draw_round_rect (
cr,
1.0f,
EM2PIXELS (get_shadow_size (self), d) + 2.0f,
EM2PIXELS (get_shadow_size (self), d) + 2.0f,
EM2PIXELS (get_corner_radius (self), d) - 2.0f,
EM2PIXELS (defaults_get_bubble_width (d), d) - 4.0f,
2.0f * EM2PIXELS (get_shadow_size (self), d) - 2.0f);
cairo_fill (cr);
cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f);
cairo_set_font_size (
cr,
EM2PIXELS (defaults_get_text_body_size (d), d));
cairo_move_to (
cr,
EM2PIXELS (defaults_get_text_body_size (d), d) +
EM2PIXELS (get_shadow_size (self), d) +
2.0f,
EM2PIXELS (defaults_get_text_body_size (d), d) +
EM2PIXELS (get_shadow_size (self), d) +
2.0f +
((2.0f * EM2PIXELS (get_shadow_size (self), d) - 2.0f) -
EM2PIXELS (defaults_get_text_body_size (d), d)) / 2);
switch (bubble_get_urgency (self))
{
case 0:
cairo_show_text (
cr,
"low - report incorrect urgency?");
break;
case 1:
cairo_show_text (
cr,
"normal - report incorrect urgency?");
break;
case 2:
cairo_show_text (
cr,
"urgent - report incorrect urgency?");
break;
default:
break;
}
}
}
void
_render_icon (Bubble* self,
cairo_t* cr,
gint x,
gint y,
gdouble alpha_normal,
gdouble alpha_blur)
{
BubblePrivate* priv = self->priv;
cairo_pattern_t* pattern;
tile_paint (priv->tile_icon,
cr,
x,
y,
alpha_normal,
alpha_blur);
if (priv->alpha)
{
cairo_push_group (cr);
tile_paint (priv->tile_icon,
cr,
x,
y,
0.0f,
(gfloat) egg_alpha_get_alpha (priv->alpha) /
(gfloat) EGG_ALPHA_MAX_ALPHA);
pattern = cairo_pop_group (cr);
if (priv->value == -1)
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 1.0f);
if (priv->value == 101)
cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
}
}
void
_render_title (Bubble* self,
cairo_t* cr,
gint x,
gint y,
gdouble alpha_normal,
gdouble alpha_blur)
{
tile_paint (self->priv->tile_title,
cr,
x,
y,
alpha_normal,
alpha_blur);
}
void
_render_body (Bubble* self,
cairo_t* cr,
gint x,
gint y,
gdouble alpha_normal,
gdouble alpha_blur)
{
tile_paint (self->priv->tile_body,
cr,
x,
y,
alpha_normal,
alpha_blur);
}
void
_render_indicator (Bubble* self,
cairo_t* cr,
gint x,
gint y,
gdouble alpha_normal,
gdouble alpha_blur)
{
BubblePrivate* priv = self->priv;
cairo_pattern_t* pattern;
tile_paint (priv->tile_indicator,
cr,
x,
y,
alpha_normal,
alpha_blur);
if (priv->alpha)
{
cairo_push_group (cr);
tile_paint (priv->tile_indicator,
cr,
x,
y,
0.0f,
(gfloat) egg_alpha_get_alpha (priv->alpha) /
(gfloat) EGG_ALPHA_MAX_ALPHA);
pattern = cairo_pop_group (cr);
if (priv->value == -1)
cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 1.0f);
if (priv->value == 101)
cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f);
cairo_mask (cr, pattern);
cairo_pattern_destroy (pattern);
}
}
void
_render_layout (Bubble* self,
cairo_t* cr,
gdouble alpha_normal,
gdouble alpha_blur)
{
Defaults* d = self->defaults;
gint shadow = EM2PIXELS (get_shadow_size (self), d);
gint icon_half = EM2PIXELS (defaults_get_icon_size (d), d) / 2;
gint width_half = EM2PIXELS (defaults_get_bubble_width (d), d) / 2;
gint height_half = EM2PIXELS (defaults_get_bubble_min_height (d), d) / 2;
gint gauge_half = EM2PIXELS (defaults_get_gauge_size (d), d) / 2;
gint margin = EM2PIXELS (defaults_get_margin_size (d), d);
switch (bubble_get_layout (self))
{
case LAYOUT_ICON_ONLY:
_render_icon (self,
cr,
shadow + width_half - icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + height_half - icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_ICON_INDICATOR:
_render_icon (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
_render_indicator (self,
cr,
shadow + 2 * margin + 2 * icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin + icon_half - gauge_half - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_ICON_TITLE:
_render_icon (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
_render_title (self,
cr,
shadow + 2 * margin + 2 * icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin + icon_half - self->priv->title_height / 2 - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_ICON_TITLE_BODY:
_render_icon (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
_render_title (self,
cr,
shadow + 2 * margin + 2 * icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
_render_body (self,
cr,
shadow + 2 * margin + 2 * icon_half - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin + self->priv->title_height - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_TITLE_BODY:
_render_title (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
_render_body (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin + self->priv->title_height - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_TITLE_ONLY:
_render_title (self,
cr,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
shadow + margin - BUBBLE_CONTENT_BLUR_RADIUS,
alpha_normal,
alpha_blur);
break;
case LAYOUT_NONE:
// should be intercepted by stack_notify_handler()
g_warning ("WARNING: No layout defined!!!\n");
break;
}
}
// the behind-bubble blur only works with the enabled/working compiz-plugin blur
// by setting the hint _COMPIZ_WM_WINDOW_BLUR on the bubble-window
void
_set_bg_blur (GtkWidget* window,
gboolean set_blur,
gint shadow_size)
{
glong data[8];
GtkAllocation a;
GdkWindow *gdkwindow;
// sanity check
if (!window)
return;
gtk_widget_get_allocation (window, &a);
gdkwindow = gtk_widget_get_window (window);
// this is meant to tell the blur-plugin what and how to blur, somehow
// the y-coords are interpreted as being CenterGravity, I wonder why
data[0] = 2; // threshold
data[1] = 0; // filter
data[2] = NorthWestGravity; // gravity of top-left
data[3] = shadow_size; // x-coord of top-left
data[4] = (-a.height / 2) + shadow_size; // y-coord of top-left
data[5] = NorthWestGravity; // gravity of bottom-right
data[6] = a.width - shadow_size; // bottom-right x-coord
data[7] = (a.height / 2) - shadow_size; // bottom-right y-coord
if (set_blur)
{
XChangeProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom (GDK_WINDOW_XDISPLAY (gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE),
XA_INTEGER,
32,
PropModeReplace,
(guchar *) data,
8);
}
else
{
XDeleteProperty (GDK_WINDOW_XDISPLAY (gdkwindow),
GDK_WINDOW_XID (gdkwindow),
XInternAtom (GDK_WINDOW_XDISPLAY (gdkwindow),
"_COMPIZ_WM_WINDOW_BLUR",
FALSE));
}
}
static
void
screen_changed_handler (GtkWindow* window,
GdkScreen* old_screen,
gpointer data)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (window));
GdkVisual* visual;
if (!gdk_screen_is_composited (screen))
return;
visual = gdk_screen_get_rgba_visual (screen);
if (!visual)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (GTK_WIDGET (window), visual);
}
static
void
update_input_shape (GtkWidget* window)
{
cairo_region_t* region = NULL;
const cairo_rectangle_int_t rect = {0, 0, 1, 1};
// sanity check
if (!window)
return;
// set an 1x1 input-region to allow click-through
region = cairo_region_create_rectangle (&rect);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_input_shape_combine_region (window, NULL);
gtk_widget_input_shape_combine_region (window, region);
}
cairo_region_destroy (region);
}
static void
update_shape (Bubble* self)
{
gint width;
gint height;
BubblePrivate* priv;
// sanity test
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
// do we actually need a shape-mask at all?
if (priv->composited)
{
gtk_widget_shape_combine_region (priv->widget, NULL);
return;
}
// we're not-composited, so deal with mouse-over differently
if (bubble_is_mouse_over (self))
{
cairo_region_t* region = NULL;
region = cairo_region_create ();
gdk_window_shape_combine_region (gtk_widget_get_window (priv->widget),
region,
0,
0);
cairo_region_destroy (region);
}
else
{
gtk_widget_get_size_request (priv->widget, &width, &height);
const cairo_rectangle_int_t rects[] = {{2, 0, width - 4, height},
{1, 1, width - 2, height - 2},
{0, 2, width, height - 4}};
cairo_region_t* region = NULL;
region = cairo_region_create_rectangles (rects, 3);
if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS)
{
gtk_widget_shape_combine_region (priv->widget, NULL);
gtk_widget_shape_combine_region (priv->widget, region);
}
}
}
static void
composited_changed_handler (GtkWidget* window,
gpointer data)
{
Bubble* bubble;
BubblePrivate* priv;
bubble = BUBBLE (data);
priv = bubble->priv;
priv->composited = gdk_screen_is_composited (gtk_widget_get_screen (window));
update_shape (bubble);
}
static gboolean
bubble_draw (GtkWidget* widget,
cairo_t* cr,
gpointer data)
{
Bubble* bubble;
Defaults* d;
BubblePrivate* priv;
bubble = (Bubble*) G_OBJECT (data);
d = bubble->defaults;
priv = bubble->priv;
// clear bubble-background
cairo_scale (cr, 1.0f, 1.0f);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
if (priv->prevent_fade || !priv->composited)
{
// render drop-shadow and bubble-background
_render_background (bubble, cr, 1.0f, 0.0f);
// render content of bubble depending on layout
_render_layout (bubble, cr, 1.0f, 0.0f);
}
else
{
// render drop-shadow and bubble-background
_render_background (bubble,
cr,
priv->distance,
1.0f - priv->distance);
// render content of bubble depending on layout
_render_layout (bubble,
cr,
priv->distance,
1.0f - priv->distance);
}
_set_bg_blur (widget,
TRUE,
EM2PIXELS (get_shadow_size (bubble), d));
return TRUE;
}
static gboolean
redraw_handler (Bubble* bubble)
{
GtkWindow* window;
BubblePrivate* priv;
if (!bubble)
return FALSE;
if (!bubble_is_visible (bubble))
return FALSE;
priv = bubble->priv;
if (!priv->composited)
return TRUE;
window = GTK_WINDOW (priv->widget);
if (!GTK_IS_WINDOW (window))
return FALSE;
if (priv->alpha == NULL)
{
if (priv->distance < 1.0f && !priv->prevent_fade)
{
gtk_widget_set_opacity (priv->widget,
WINDOW_MIN_OPACITY +
priv->distance *
(WINDOW_MAX_OPACITY -
WINDOW_MIN_OPACITY));
bubble_refresh (bubble);
}
else
gtk_widget_set_opacity (priv->widget, WINDOW_MAX_OPACITY);
}
return TRUE;
}
static
gboolean
pointer_update (Bubble* bubble)
{
gint pointer_rel_x;
gint pointer_rel_y;
gint pointer_abs_x;
gint pointer_abs_y;
gint win_x;
gint win_y;
gint width;
gint height;
GtkWidget* window;
BubblePrivate* priv;
if (!bubble)
return FALSE;
if (!bubble_is_visible (bubble))
return FALSE;
priv = bubble->priv;
window = priv->widget;
if (!GTK_IS_WINDOW (window))
return FALSE;
if (gtk_widget_get_realized (window))
{
GdkDeviceManager *device_manager;
GdkDevice *device;
gint distance_x;
gint distance_y;
device_manager = gdk_display_get_device_manager (gtk_widget_get_display (window));
device = gdk_device_manager_get_client_pointer (device_manager);
gdk_window_get_device_position (gtk_widget_get_window (window),
device,
&pointer_rel_x,
&pointer_rel_y,
NULL);
gtk_window_get_position (GTK_WINDOW (window), &win_x, &win_y);
pointer_abs_x = win_x + pointer_rel_x;
pointer_abs_y = win_y + pointer_rel_y;
gtk_window_get_size (GTK_WINDOW (window), &width, &height);
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width &&
pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
{
bubble_set_mouse_over (bubble, TRUE);
}
else
{
bubble_set_mouse_over (bubble, FALSE);
}
if (pointer_abs_x >= win_x &&
pointer_abs_x <= win_x + width)
distance_x = 0;
else
{
if (pointer_abs_x < win_x)
distance_x = abs (pointer_rel_x);
if (pointer_abs_x > win_x + width)
distance_x = abs (pointer_rel_x - width);
}
if (pointer_abs_y >= win_y &&
pointer_abs_y <= win_y + height)
distance_y = 0;
else
{
if (pointer_abs_y < win_y)
distance_y = abs (pointer_rel_y);
if (pointer_abs_y > win_y + height)
distance_y = abs (pointer_rel_y - height);
}
priv->distance = sqrt (distance_x * distance_x +
distance_y * distance_y) /
(double) PROXIMITY_THRESHOLD;
// mark mouse-pointer having left bubble and proximity-area
// after inital show-up of bubble
if (priv->prevent_fade && priv->distance > 1.0f)
priv->prevent_fade = FALSE;
}
return TRUE;
}
//-- internal API --------------------------------------------------------------
static void
bubble_dispose (GObject* gobject)
{
Bubble* bubble;
BubblePrivate* priv;
if (!gobject || !IS_BUBBLE (gobject))
return;
bubble = BUBBLE (gobject);
priv = bubble->priv;
if (GTK_IS_WIDGET (priv->widget))
{
gtk_widget_destroy (GTK_WIDGET (priv->widget));
priv->widget = NULL;
}
if (priv->title)
{
g_string_free ((gpointer) priv->title,
TRUE);
priv->title = NULL;
}
if (priv->message_body)
{
g_string_free ((gpointer) priv->message_body,
TRUE);
priv->message_body = NULL;
}
if (priv->synchronous)
{
g_free ((gpointer) priv->synchronous);
priv->synchronous = NULL;
}
if (priv->sender)
{
g_free ((gpointer) priv->sender);
priv->sender = NULL;
}
if (priv->icon_pixbuf)
{
g_object_unref (priv->icon_pixbuf);
priv->icon_pixbuf = NULL;
}
if (priv->alpha)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
if (priv->timeline)
{
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
if (priv->pointer_update_id)
{
g_source_remove (priv->pointer_update_id);
priv->pointer_update_id = 0;
}
if (priv->draw_handler_id)
{
g_source_remove (priv->draw_handler_id);
priv->draw_handler_id = 0;
}
if (priv->timer_id)
{
g_source_remove (priv->timer_id);
priv->timer_id = 0;
}
if (priv->tile_background_part)
{
tile_destroy (priv->tile_background_part);
priv->tile_background_part = NULL;
}
if (priv->tile_background)
{
tile_destroy (priv->tile_background);
priv->tile_background = NULL;
}
if (priv->tile_icon)
{
tile_destroy (priv->tile_icon);
priv->tile_icon = NULL;
}
if (priv->tile_title)
{
tile_destroy (priv->tile_title);
priv->tile_title = NULL;
}
if (priv->tile_body)
{
tile_destroy (priv->tile_body);
priv->tile_body = NULL;
}
if (priv->tile_indicator)
{
tile_destroy (priv->tile_indicator);
priv->tile_indicator = NULL;
}
g_clear_pointer (&priv->old_icon_filename, g_free);
// chain up to the parent class
G_OBJECT_CLASS (bubble_parent_class)->dispose (gobject);
}
static void
bubble_finalize (GObject* gobject)
{
// chain up to the parent class
G_OBJECT_CLASS (bubble_parent_class)->finalize (gobject);
}
static void
bubble_init (Bubble* self)
{
// If you need specific construction properties to complete
// initialization, delay initialization completion until the
// property is set.
BubblePrivate *priv;
self->priv = priv = bubble_get_instance_private (self);
priv->layout = LAYOUT_NONE;
priv->title = NULL;
priv->message_body = NULL;
priv->title_needs_refresh = FALSE;
priv->message_body_needs_refresh = FALSE;
priv->visible = FALSE;
priv->icon_pixbuf = NULL;
priv->value = -2;
priv->synchronous = NULL;
priv->sender = NULL;
priv->draw_handler_id = 0;
priv->pointer_update_id = 0;
}
static void
bubble_get_property (GObject* gobject,
guint prop,
GValue* value,
GParamSpec* spec)
{
switch (prop)
{
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec);
break;
}
}
static void
bubble_class_init (BubbleClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = bubble_dispose;
gobject_class->finalize = bubble_finalize;
gobject_class->get_property = bubble_get_property;
g_bubble_signals[TIMED_OUT] = g_signal_new (
"timed-out",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BubbleClass, timed_out),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
g_bubble_signals[VALUE_CHANGED] = g_signal_new (
"value-changed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BubbleClass, value_changed),
NULL,
NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1,
G_TYPE_INT);
g_bubble_signals[MESSAGE_BODY_DELETED] = g_signal_new (
"message-body-deleted",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BubbleClass, message_body_deleted),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
g_bubble_signals[MESSAGE_BODY_INSERTED] = g_signal_new (
"message-body-inserted",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BubbleClass, message_body_inserted),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1,
G_TYPE_STRING);
}
//-- public API ----------------------------------------------------------------
Bubble*
bubble_new (Defaults* defaults)
{
Bubble* this = NULL;
GtkWidget* window = NULL;
BubblePrivate* priv;
GdkRGBA transparent = {0.0, 0.0, 0.0, 0.0};
this = g_object_new (BUBBLE_TYPE, NULL);
if (!this)
return NULL;
this->defaults = defaults;
priv = this->priv;
priv->widget = bubble_window_new();
window = priv->widget;
if (!window)
return NULL;
g_object_set_data (G_OBJECT(window), "bubble", (gpointer) this);
gtk_window_set_type_hint (GTK_WINDOW (window),
GDK_WINDOW_TYPE_HINT_NOTIFICATION);
gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
gtk_window_stick (GTK_WINDOW (window));
gtk_widget_add_events (window,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
// hook up input/event handlers to window
g_signal_connect (G_OBJECT (window),
"screen-changed",
G_CALLBACK (screen_changed_handler),
NULL);
g_signal_connect (G_OBJECT (window),
"composited-changed",
G_CALLBACK (composited_changed_handler),
this);
gtk_window_move (GTK_WINDOW (window), 0, 0);
// make sure the window opens with a RGBA-visual
screen_changed_handler (GTK_WINDOW (window), NULL, NULL);
gtk_widget_realize (window);
gdk_window_set_background_rgba (gtk_widget_get_window (window),
&transparent);
// hook up window-event handlers to window
g_signal_connect (window,
"draw",
G_CALLBACK (bubble_draw),
this);
// "clear" input-mask, set title/icon/attributes
gtk_widget_set_app_paintable (window, TRUE);
gtk_window_set_title (GTK_WINDOW (window), "notify-osd");
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_focus_on_map (GTK_WINDOW (window), FALSE);
gtk_window_set_accept_focus (GTK_WINDOW (window), FALSE);
gtk_widget_set_opacity (window, 0.0f);
// TODO: fold some of that back into bubble_init
this->priv = this->priv;
this->priv->layout = LAYOUT_NONE;
this->priv->widget = window;
this->priv->title = g_string_new ("");
this->priv->message_body = g_string_new ("");
this->priv->title_needs_refresh = FALSE;
this->priv->message_body_needs_refresh = FALSE;
this->priv->icon_pixbuf = NULL;
this->priv->value = -2;
this->priv->visible = FALSE;
this->priv->timeout = 5000;
this->priv->mouse_over = FALSE;
this->priv->distance = 1.0f;
this->priv->composited = gdk_screen_is_composited (
gtk_widget_get_screen (window));
this->priv->alpha = NULL;
this->priv->timeline = NULL;
this->priv->title_width = 0;
this->priv->title_height = 0;
this->priv->body_width = 0;
this->priv->body_height = 0;
this->priv->append = FALSE;
this->priv->icon_only = FALSE;
this->priv->tile_background_part = NULL;
this->priv->tile_background = NULL;
this->priv->tile_icon = NULL;
this->priv->tile_title = NULL;
this->priv->tile_body = NULL;
this->priv->tile_indicator = NULL;
this->priv->prevent_fade = FALSE;
update_input_shape (window);
return this;
}
gchar*
bubble_get_synchronous (Bubble* self)
{
g_return_val_if_fail (IS_BUBBLE (self), NULL);
return self->priv->synchronous;
}
gchar*
bubble_get_sender (Bubble* self)
{
g_return_val_if_fail (IS_BUBBLE (self), NULL);
return self->priv->sender;
}
void
bubble_set_title (Bubble* self,
const gchar* title)
{
gchar* text;
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
// convert any newline to space
text = newline_to_space (title);
if (priv->title)
{
if (g_strcmp0 (priv->title->str, text))
priv->title_needs_refresh = TRUE;
g_string_free (priv->title, TRUE);
}
priv->title = g_string_new (text);
g_object_notify (
G_OBJECT (gtk_widget_get_accessible (self->priv->widget)),
"accessible-name");
g_free (text);
}
const gchar*
bubble_get_title (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return NULL;
return self->priv->title->str;
}
void
bubble_set_message_body (Bubble* self,
const gchar* body)
{
gchar* text;
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
// filter out any HTML/markup if possible
text = filter_text (body);
g_strstrip (text);
if (priv->message_body)
if (g_strcmp0 (priv->message_body->str, text))
priv->message_body_needs_refresh = TRUE;
if (priv->message_body && priv->message_body->len != 0)
{
g_signal_emit (self,
g_bubble_signals[MESSAGE_BODY_DELETED],
0,
priv->message_body->str);
g_string_free (priv->message_body, TRUE);
}
priv->message_body = g_string_new (text);
g_signal_emit (self, g_bubble_signals[MESSAGE_BODY_INSERTED], 0, text);
g_object_notify (G_OBJECT (gtk_widget_get_accessible (priv->widget)),
"accessible-description");
g_free (text);
}
const gchar*
bubble_get_message_body (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return NULL;
return self->priv->message_body->str;
}
void
bubble_set_icon (Bubble* self,
const gchar* name)
{
BubblePrivate *priv;
gint scale;
gint icon_size;
g_return_if_fail (self != NULL);
g_return_if_fail (name != NULL);
priv = self->priv;
scale = gtk_widget_get_scale_factor (priv->widget);
icon_size = EM2PIXELS (defaults_get_icon_size (self->defaults), self->defaults);
// check if an app tries to set the same file as icon again, this check
// avoids superfluous regeneration of the tile/blur-cache for the icon,
// thus it improves performance in update- and append-cases
if (!g_strcmp0 (priv->old_icon_filename, name))
return;
g_clear_object (&priv->icon_pixbuf);
g_clear_pointer (&priv->old_icon_filename, g_free);
if (g_str_has_prefix (name, "file://"))
{
gchar *filename;
GError *error = NULL;
filename = g_filename_from_uri (name, NULL, &error);
if (filename == NULL)
{
g_warning ("%s is not a valid file uri: %s", name, error->message);
g_error_free (error);
return;
}
priv->icon_pixbuf = gdk_pixbuf_new_from_file_at_scale (filename, scale * icon_size, scale * icon_size, TRUE, NULL);
g_free (filename);
}
/* According to the spec, only file:// uris are allowed in the
* name field. However, many applications send raw paths.
* Support those as well, but only if they're absolute.
*/
else if (name[0] == '/')
{
priv->icon_pixbuf = gdk_pixbuf_new_from_file_at_scale (name, scale * icon_size, scale * icon_size, TRUE, NULL);
}
else
{
GError *error = NULL;
GdkPixbuf *buffer;
GtkIconTheme *theme;
GtkIconLookupFlags flags;
gchar *fallback_name;
theme = gtk_icon_theme_get_default ();
flags = GTK_ICON_LOOKUP_FORCE_SVG | GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_FORCE_SIZE;
fallback_name = g_strconcat ("notification-", name, NULL);
buffer = gtk_icon_theme_load_icon_for_scale (theme, fallback_name, icon_size, scale, flags, &error);
g_free (fallback_name);
if (buffer == NULL && g_error_matches (error, GTK_ICON_THEME_ERROR, GTK_ICON_THEME_NOT_FOUND)) {
g_clear_error (&error);
buffer = gtk_icon_theme_load_icon_for_scale (theme, name, icon_size, scale, flags, &error);
}
if (buffer == NULL)
{
g_warning ("Unable to load icon '%s': %s", name, error->message);
g_error_free (error);
return;
}
/* copy and unref buffer so on an icon-theme change old
** icons are not kept in memory due to dangling
** references, this also makes sure we do not need to
** connect to GtkWidget::style-set signal for the
** GdkPixbuf we get from gtk_icon_theme_load_icon() */
priv->icon_pixbuf = gdk_pixbuf_copy (buffer);
g_object_unref (buffer);
}
// store the new icon-basename
priv->old_icon_filename = g_strdup (name);
_refresh_icon (self);
}
static GdkPixbuf *
scale_pixbuf (const GdkPixbuf *pixbuf, gint size)
{
GdkPixbuf *scaled_icon;
GdkPixbuf *new_icon;
gint w, h, dest_x, dest_y, new_width, new_height, max_edge;
dest_x = dest_y = 0;
w = gdk_pixbuf_get_width (pixbuf);
h = gdk_pixbuf_get_height (pixbuf);
max_edge = MAX (w, h);
// temporarily cast to float so we don't end up missing fractional parts
// from the division, especially nasty for 0.something :)
// e.g.: 99 / 100 = 0 but 99.0 / 100.0 = 0.99
new_width = size * ((gfloat) w / (gfloat) max_edge);
new_height = size * ((gfloat) h / (gfloat) max_edge);
/* Scale the pixbuf down, preserving the aspect ratio */
scaled_icon = gdk_pixbuf_scale_simple (pixbuf,
new_width,
new_height,
GDK_INTERP_BILINEAR);
if (w == h)
return scaled_icon;
/* Create a square pixbuf with an alpha channel */
new_icon = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (scaled_icon),
TRUE,
gdk_pixbuf_get_bits_per_sample (scaled_icon),
size, size);
/* Clear the pixbuf so it is transparent */
gdk_pixbuf_fill (new_icon, 0x00000000);
/* Center the rectangular pixbuf inside the transparent square */
if (new_width > new_height)
dest_y = (new_width - new_height) / 2;
else
dest_x = (new_height - new_width) / 2;
/* Copy the rectangular pixbuf into the new pixbuf at a centered position */
gdk_pixbuf_copy_area (scaled_icon,
0, 0,
gdk_pixbuf_get_width (scaled_icon),
gdk_pixbuf_get_height (scaled_icon),
new_icon,
dest_x, dest_y);
g_object_unref (scaled_icon);
return new_icon;
}
void
bubble_set_icon_from_pixbuf (Bubble* self,
GdkPixbuf* pixbuf)
{
GdkPixbuf* scaled;
gint height;
gint width;
Defaults* d;
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self) || !pixbuf)
return;
priv = self->priv;
// "reset" the stored the icon-filename, fixes LP: #451086
g_clear_pointer (&priv->old_icon_filename, g_free);
if (priv->icon_pixbuf)
{
g_object_unref (priv->icon_pixbuf);
priv->icon_pixbuf = NULL;
}
height = gdk_pixbuf_get_height (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
d = self->defaults;
if (width != defaults_get_icon_size (d) ||
height != defaults_get_icon_size (d))
{
scaled = scale_pixbuf (pixbuf, EM2PIXELS (defaults_get_icon_size (d), d));
g_object_unref (pixbuf);
pixbuf = scaled;
}
priv->icon_pixbuf = pixbuf;
_refresh_icon (self);
}
GdkPixbuf*
bubble_get_icon_pixbuf (Bubble *self)
{
g_return_val_if_fail (IS_BUBBLE (self), NULL);
return self->priv->icon_pixbuf;
}
void
bubble_set_value (Bubble* self,
gint value)
{
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
// only really cause a refresh (blur, recreating tile-/blur-cache) if
// a different value has been set, this helps improve performance when
// a user e.g. presses and holds down keys for Volume-Up/Down or
// Brightness-Up/Down and apps like gnome-settings-daemon or
// gnome-power-daemon fire continues notification-updates due to the
// key-repeat events
if (priv->value != value)
{
priv->value = value;
g_signal_emit (self, g_bubble_signals[VALUE_CHANGED], 0, value);
_refresh_indicator (self);
}
}
gint
bubble_get_value (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return -2;
return self->priv->value;
}
void
bubble_set_size (Bubble* self,
gint width,
gint height)
{
if (!self || !IS_BUBBLE (self))
return;
gtk_widget_set_size_request (self->priv->widget, width, height);
}
void
bubble_get_size (Bubble* self,
gint* width,
gint* height)
{
if (!self || !IS_BUBBLE (self))
return;
gtk_widget_get_size_request (self->priv->widget, width, height);
}
void
bubble_set_timeout (Bubble* self,
guint timeout)
{
if (!self || !IS_BUBBLE (self))
return;
self->priv->timeout = timeout;
}
/* a timeout of 0 doesn't make much sense now does it, thus 0 indicates an
** error */
guint
bubble_get_timeout (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return 0;
return self->priv->timeout;
}
void
bubble_set_timer_id (Bubble* self,
guint timer_id)
{
if (!self || !IS_BUBBLE (self))
return;
self->priv->timer_id = timer_id;
}
/* a valid GLib timer-id is always > 0, thus 0 indicates an error */
guint
bubble_get_timer_id (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return 0;
return self->priv->timer_id;
}
void
bubble_set_mouse_over (Bubble* self,
gboolean flag)
{
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
/* did anything change? */
if (priv->mouse_over != flag)
{
priv->mouse_over = flag;
update_shape (self);
if (flag) {
g_debug("mouse entered bubble, supressing timeout");
bubble_clear_timer(self);
} else {
g_debug("mouse left bubble, continuing timeout");
bubble_set_timeout(self, 3000);
bubble_start_timer(self, TRUE);
}
}
}
gboolean
bubble_is_mouse_over (Bubble* self)
{
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return FALSE;
priv = self->priv;
if (priv->prevent_fade)
return FALSE;
return priv->mouse_over;
}
void
bubble_move (Bubble* self,
gint x,
gint y)
{
if (!self || !IS_BUBBLE (self))
return;
gtk_window_move (GTK_WINDOW (self->priv->widget), x, y);
}
static void
glow_completed_cb (EggTimeline *timeline,
Bubble *bubble)
{
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (bubble));
priv = bubble->priv;
/* get rid of the alpha, so that the mouse-over algorithm notices */
if (priv->alpha)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
if (priv->timeline)
{
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
}
static void
glow_cb (EggTimeline *timeline,
gint frame_no,
Bubble *bubble)
{
g_return_if_fail (IS_BUBBLE (bubble));
bubble_refresh (bubble);
}
static void
bubble_start_glow_effect (Bubble *self,
guint msecs)
{
EggTimeline* timeline;
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (self));
priv = self->priv;
timeline = egg_timeline_new_for_duration (msecs);
egg_timeline_set_speed (timeline, FPS);
priv->timeline = timeline;
if (priv->alpha != NULL)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
priv->alpha = egg_alpha_new_full (timeline,
EGG_ALPHA_RAMP_DEC,
NULL,
NULL);
g_signal_connect (G_OBJECT (timeline),
"completed",
G_CALLBACK (glow_completed_cb),
self);
g_signal_connect (G_OBJECT (timeline),
"new-frame",
G_CALLBACK (glow_cb),
self);
egg_timeline_start (timeline);
}
void
bubble_show (Bubble* self)
{
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
priv->visible = TRUE;
gtk_widget_show_all (priv->widget);
// check if mouse-pointer is over bubble (and proximity-area) initially
pointer_update (self);
if (priv->distance <= 1.0f)
priv->prevent_fade = TRUE;
else
priv->prevent_fade = FALSE;
// FIXME: do nasty busy-polling rendering in the drawing-area
priv->draw_handler_id = g_timeout_add (1000/FPS,
(GSourceFunc) redraw_handler,
self);
// FIXME: read out current mouse-pointer position every 1/25 second
priv->pointer_update_id = g_timeout_add (1000/FPS,
(GSourceFunc) pointer_update,
self);
}
/* mostly called when we change the content of the bubble
and need to force a redraw
*/
void
bubble_refresh (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return;
/* force a redraw */
gtk_widget_queue_draw (self->priv->widget);
}
static inline gboolean
bubble_is_composited (Bubble *bubble)
{
/* no g_return_if_fail(), the caller should have already
checked that */
return gtk_widget_is_composited (bubble->priv->widget);
}
static inline GtkWindow*
bubble_get_window (Bubble *bubble)
{
return GTK_WINDOW (bubble->priv->widget);
}
static void
fade_cb (EggTimeline *timeline,
gint frame_no,
Bubble *bubble)
{
float opacity;
g_return_if_fail (IS_BUBBLE (bubble));
opacity = (float)egg_alpha_get_alpha (bubble->priv->alpha)
/ (float)EGG_ALPHA_MAX_ALPHA
* WINDOW_MAX_OPACITY;
if (bubble_is_mouse_over (bubble))
gtk_widget_set_opacity (bubble->priv->widget,
WINDOW_MIN_OPACITY);
else
gtk_widget_set_opacity (bubble->priv->widget, opacity);
}
static void
fade_out_completed_cb (EggTimeline *timeline,
Bubble *bubble)
{
g_return_if_fail (IS_BUBBLE (bubble));
bubble_hide (bubble);
dbus_send_close_signal (bubble_get_sender (bubble),
bubble_get_id (bubble),
1);
g_signal_emit (bubble, g_bubble_signals[TIMED_OUT], 0);
}
static void
fade_in_completed_cb (EggTimeline* timeline,
Bubble* bubble)
{
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (bubble));
priv = bubble->priv;
/* get rid of the alpha, so that the mouse-over algorithm notices */
if (priv->alpha)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
if (priv->timeline)
{
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
if (bubble_is_mouse_over (bubble))
gtk_widget_set_opacity (bubble->priv->widget,
WINDOW_MIN_OPACITY);
else
gtk_widget_set_opacity (bubble->priv->widget,
WINDOW_MAX_OPACITY);
bubble_start_timer (bubble, TRUE);
}
void
bubble_fade_in (Bubble* self,
guint msecs)
{
EggTimeline* timeline;
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (self));
priv = self->priv;
if (!bubble_is_composited (self)
|| msecs == 0)
{
bubble_show (self);
bubble_start_timer (self, TRUE);
return;
}
timeline = egg_timeline_new_for_duration (msecs);
egg_timeline_set_speed (timeline, FPS);
if (priv->alpha != NULL)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
priv->alpha = egg_alpha_new_full (timeline,
EGG_ALPHA_RAMP_INC,
NULL,
NULL);
g_signal_connect (G_OBJECT (timeline),
"completed",
G_CALLBACK (fade_in_completed_cb),
self);
g_signal_connect (G_OBJECT (timeline),
"new-frame",
G_CALLBACK (fade_cb),
self);
egg_timeline_start (timeline);
gtk_widget_set_opacity (self->priv->widget, 0.0f);
bubble_show (self);
}
void
bubble_fade_out (Bubble* self,
guint msecs)
{
EggTimeline* timeline;
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (self));
priv = self->priv;
timeline = egg_timeline_new_for_duration (msecs);
egg_timeline_set_speed (timeline, FPS);
priv->timeline = timeline;
if (priv->alpha != NULL)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
priv->alpha = egg_alpha_new_full (timeline,
EGG_ALPHA_RAMP_DEC,
NULL,
NULL);
g_signal_connect (G_OBJECT (timeline),
"completed",
G_CALLBACK (fade_out_completed_cb),
self);
g_signal_connect (G_OBJECT (timeline),
"new-frame",
G_CALLBACK (fade_cb),
self);
egg_timeline_start (timeline);
}
gboolean
bubble_timed_out (Bubble* self)
{
g_return_val_if_fail (IS_BUBBLE (self), FALSE);
/* This function always returns FALSE, which removes the timer
* source. Unset priv->timer_id so that we don't call
* g_source_remove() on it later. */
bubble_set_timer_id (self, 0);
if (self->priv->composited)
{
bubble_fade_out (self, 300);
return FALSE;
}
bubble_hide (self);
dbus_send_close_signal (bubble_get_sender (self),
bubble_get_id (self),
1);
g_signal_emit (self, g_bubble_signals[TIMED_OUT], 0);
return FALSE;
}
void
bubble_hide (Bubble* self)
{
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self) || !bubble_is_visible (self))
return;
priv = self->priv;
priv->visible = FALSE;
gtk_widget_hide (priv->widget);
priv->timeout = 0;
if (priv->timeline)
{
egg_timeline_stop (priv->timeline);
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
if (priv->alpha)
{
g_object_unref (priv->alpha);
priv->alpha = NULL;
}
}
void
bubble_set_id (Bubble* self,
guint id)
{
if (!self || !IS_BUBBLE (self))
return;
self->priv->id = id;
}
guint
bubble_get_id (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return 0;
return self->priv->id;
}
gboolean
bubble_is_visible (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return FALSE;
return self->priv->visible;
}
void
bubble_start_timer (Bubble* self,
gboolean trigger)
{
guint timer_id;
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
timer_id = bubble_get_timer_id (self);
if (timer_id > 0)
g_source_remove (timer_id);
/* and now let the timer tick... we use g_timeout_add_seconds() here
** because for the bubble timeouts microsecond-precise resolution is not
** needed, furthermore this also allows glib more room for optimizations
** and improve system-power-usage to be more efficient */
bubble_set_timer_id (
self,
g_timeout_add_seconds (bubble_get_timeout (self) / 1000,
(GSourceFunc) bubble_timed_out,
self));
/* if the bubble is displaying a value that is out of bounds
trigger a dim/glow animation */
if (trigger)
if (priv->value == -1 || priv->value == 101)
bubble_start_glow_effect (self, 500);
}
void
bubble_clear_timer (Bubble* self)
{
guint timer_id;
if (!self || !IS_BUBBLE (self))
return;
timer_id = self->priv->timer_id;
if (timer_id > 0) {
g_source_remove (timer_id);
bubble_set_timer_id(self, 0);
}
}
void
bubble_get_position (Bubble* self,
gint* x,
gint* y)
{
if (!self || !IS_BUBBLE (self))
return;
gtk_window_get_position (GTK_WINDOW (self->priv->widget),
x, y);
}
gint
bubble_get_height (Bubble *self)
{
gint width;
gint height;
if (!self || !IS_BUBBLE (self))
return 0;
gtk_window_get_size (GTK_WINDOW (self->priv->widget),
&width,
&height);
return height;
}
gint
bubble_get_future_height (Bubble *self)
{
if (!self || !IS_BUBBLE (self))
return 0;
return self->priv->future_height;
}
gint
_calc_title_height (Bubble* self,
gint title_width /* requested text-width in pixels */)
{
Defaults* d;
cairo_surface_t* surface;
cairo_t* cr;
PangoFontDescription* desc = NULL;
PangoLayout* layout = NULL;
PangoRectangle log_rect = {0, 0, 0, 0};
gint title_height;
BubblePrivate* priv;
gchar* text_font_face = NULL;
if (!self || !IS_BUBBLE (self))
return 0;
d = self->defaults;
priv = self->priv;
surface = bubble_create_image_surface (self, CAIRO_FORMAT_A1, 1, 1);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
if (surface)
cairo_surface_destroy (surface);
return 0;
}
cr = cairo_create (surface);
cairo_surface_destroy (surface);
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
if (cr)
cairo_destroy (cr);
return 0;
}
layout = pango_cairo_create_layout (cr);
text_font_face = defaults_get_text_font_face (d);
desc = pango_font_description_from_string (text_font_face);
g_free ((gpointer) text_font_face);
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (
pango_layout_get_context (layout),
gdk_screen_get_font_options (
gtk_widget_get_screen (priv->widget)));
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
defaults_get_screen_dpi (d));
pango_layout_context_changed (layout);
pango_font_description_set_size (desc,
defaults_get_system_font_size (d) *
defaults_get_text_title_size (d) *
PANGO_SCALE);
pango_font_description_set_weight (
desc,
defaults_get_text_title_weight (d));
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_width (layout, title_width * PANGO_SCALE);
pango_layout_set_height (layout, -3);
pango_layout_set_text (layout, priv->title->str, priv->title->len);
pango_layout_get_extents (layout, NULL, &log_rect);
title_height = PANGO_PIXELS (log_rect.height);
g_object_unref (layout);
cairo_destroy (cr);
return title_height;
}
gint
_calc_body_height (Bubble* self,
gint body_width /* requested text-width in pixels */)
{
Defaults* d;
cairo_t* cr;
PangoFontDescription* desc = NULL;
PangoLayout* layout = NULL;
PangoRectangle log_rect;
gint body_height;
BubblePrivate* priv;
gchar* text_font_face = NULL;
if (!self || !IS_BUBBLE (self))
return 0;
d = self->defaults;
priv = self->priv;
cr = gdk_cairo_create (gtk_widget_get_window (priv->widget));
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
if (cr)
cairo_destroy (cr);
return 0;
}
layout = pango_cairo_create_layout (cr);
text_font_face = defaults_get_text_font_face (d);
desc = pango_font_description_from_string (text_font_face);
g_free ((gpointer) text_font_face);
// make sure system-wide font-options like hinting, antialiasing etc.
// are taken into account
pango_cairo_context_set_font_options (
pango_layout_get_context (layout),
gdk_screen_get_font_options (
gtk_widget_get_screen (priv->widget)));
pango_cairo_context_set_resolution (pango_layout_get_context (layout),
defaults_get_screen_dpi (d));
pango_layout_context_changed (layout);
pango_font_description_set_size (desc,
defaults_get_system_font_size (d) *
defaults_get_text_body_size (d) *
PANGO_SCALE);
pango_font_description_set_weight (
desc,
defaults_get_text_body_weight (d));
pango_layout_set_font_description (layout, desc);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE);
pango_layout_set_width (layout, body_width * PANGO_SCALE);
pango_layout_set_height (layout, -10);
pango_layout_set_text (layout,
priv->message_body->str,
priv->message_body->len);
/* enforce the 10 line-limit, usually only triggered by appended
** body-message text due to the newline-characters added with each
** append */
if (pango_layout_get_line_count (layout) > 10)
{
/* get it down to 9 lines, because we add our own ...-line */
while (pango_layout_get_line_count (layout) > 9)
{
GString* string = NULL;
/* cut leading chunk of text up to the first newline */
string = g_string_new (g_strstr_len (priv->message_body->str,
priv->message_body->len,
"\n"));
/* also cut the first newline itself */
string = g_string_erase (string, 0, 1);
/* copy that stripped text back to the body-message */
g_string_assign (priv->message_body, string->str);
/* set the new body-message text to the pango-layout */
pango_layout_set_text (layout,
priv->message_body->str,
priv->message_body->len);
/* clean up */
g_string_free (string, TRUE);
}
/* add our own ellipsize-line */
g_string_prepend (priv->message_body, "...\n");
/* set final body-message text to the pango-layout again */
pango_layout_set_text (layout,
priv->message_body->str,
priv->message_body->len);
}
pango_layout_get_extents (layout, NULL, &log_rect);
body_height = PANGO_PIXELS (log_rect.height);
pango_font_description_free (desc);
g_object_unref (layout);
cairo_destroy (cr);
return body_height;
}
void
bubble_recalc_size (Bubble *self)
{
gint old_bubble_width = 0;
gint old_bubble_height = 0;
gint new_bubble_width = 0;
gint new_bubble_height = 0;
Defaults* d;
BubblePrivate* priv;
if (!self || !IS_BUBBLE (self))
return;
d = self->defaults;
priv = self->priv;
/* FIXME: a quick fix to rescale an icon (e.g. user changed font-size or
** DPI while a bubble is displayed, thus bubble is re-rendered and the
** icon needs to adapt to the new size) */
if (priv->icon_pixbuf)
{
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_scale_simple (
priv->icon_pixbuf,
EM2PIXELS (defaults_get_icon_size (d), d),
EM2PIXELS (defaults_get_icon_size (d), d),
GDK_INTERP_BILINEAR);
g_object_unref (priv->icon_pixbuf);
priv->icon_pixbuf = pixbuf;
}
bubble_determine_layout (self);
new_bubble_width =
EM2PIXELS (defaults_get_bubble_width (d), d) +
2 * EM2PIXELS (get_shadow_size (self), d);
switch (priv->layout)
{
case LAYOUT_ICON_ONLY:
case LAYOUT_ICON_INDICATOR:
case LAYOUT_ICON_TITLE:
priv->title_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
3 * EM2PIXELS (defaults_get_margin_size (d), d) -
EM2PIXELS (defaults_get_icon_size (d), d);
priv->title_height = _calc_title_height (
self,
self->priv->title_width);
new_bubble_height =
EM2PIXELS (defaults_get_bubble_min_height (d), d) +
2.0f * EM2PIXELS (get_shadow_size (self), d);
break;
case LAYOUT_ICON_TITLE_BODY:
{
gdouble available_height = 0.0f;
gdouble bubble_height = 0.0f;
priv->title_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
3 * EM2PIXELS (defaults_get_margin_size (d), d) -
EM2PIXELS (defaults_get_icon_size (d), d);
priv->title_height = _calc_title_height (
self,
self->priv->title_width);
priv->body_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
3 * EM2PIXELS (defaults_get_margin_size (d), d) -
EM2PIXELS (defaults_get_icon_size (d), d);
priv->body_height = _calc_body_height (
self,
priv->body_width);
available_height = PIXELS2EM (defaults_get_desktop_height (d), d) -
defaults_get_desktop_bottom_gap (d) -
defaults_get_bubble_min_height (d) -
2.0f * defaults_get_bubble_vert_gap (d);
bubble_height =
PIXELS2EM (priv->title_height, d) +
PIXELS2EM (priv->body_height, d) +
2.0f * defaults_get_margin_size (d);
if (bubble_height >= available_height)
{
new_bubble_height = EM2PIXELS (available_height, d);
}
else
{
if (priv->body_height +
priv->title_height <
EM2PIXELS (defaults_get_icon_size (d), d))
{
new_bubble_height =
EM2PIXELS (defaults_get_icon_size (d), d) +
2.0f * EM2PIXELS (defaults_get_margin_size (d), d) +
2.0f * EM2PIXELS (get_shadow_size (self), d);
}
else
{
new_bubble_height =
priv->body_height +
priv->title_height +
2.0f * EM2PIXELS (defaults_get_margin_size (d), d) +
2.0f * EM2PIXELS (get_shadow_size (self), d);
}
}
}
break;
case LAYOUT_TITLE_BODY:
{
gdouble available_height = 0.0f;
gdouble bubble_height = 0.0f;
priv->title_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
2 * EM2PIXELS (defaults_get_margin_size (d), d);
priv->title_height = _calc_title_height (
self,
priv->title_width);
priv->body_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
2 * EM2PIXELS (defaults_get_margin_size (d), d);
priv->body_height = _calc_body_height (
self,
priv->body_width);
available_height = PIXELS2EM (defaults_get_desktop_height (d), d) -
defaults_get_desktop_bottom_gap (d) -
defaults_get_bubble_min_height (d) -
2.0f * defaults_get_bubble_vert_gap (d);
bubble_height =
PIXELS2EM (priv->title_height, d) +
PIXELS2EM (priv->body_height, d) +
2.0f * defaults_get_margin_size (d);
if (bubble_height >= available_height)
{
new_bubble_height = EM2PIXELS (available_height, d);
}
else
{
new_bubble_height =
priv->body_height +
priv->title_height +
2.0f * EM2PIXELS (defaults_get_margin_size (d), d) +
2.0f * EM2PIXELS (get_shadow_size (self), d);
}
}
break;
case LAYOUT_TITLE_ONLY:
{
priv->title_width =
EM2PIXELS (defaults_get_bubble_width (d), d) -
2 * EM2PIXELS (defaults_get_margin_size (d), d);
priv->title_height = _calc_title_height (
self,
priv->title_width);
new_bubble_height = priv->title_height +
2.0f * EM2PIXELS (defaults_get_margin_size (d), d) +
2.0f * EM2PIXELS (get_shadow_size (self), d);
}
break;
case LAYOUT_NONE:
g_warning ("bubble_recalc_size(): WARNING, no layout!!!\n");
break;
}
priv->future_height = new_bubble_height;
bubble_get_size (self, &old_bubble_width, &old_bubble_height);
bubble_set_size (self, new_bubble_width, new_bubble_height);
// don't refresh tile/blur-caches for background, title or body if the
// size or contents have not changed, this improves performance for the
// update- and replace-cases
if (old_bubble_width != new_bubble_width ||
old_bubble_height != new_bubble_height)
_refresh_background (self);
if (priv->title_needs_refresh)
_refresh_title (self);
if (priv->message_body_needs_refresh)
_refresh_body (self);
update_shape (self);
}
void
bubble_set_synchronous (Bubble *self,
const gchar *sync)
{
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (self));
priv = self->priv;
if (priv->synchronous != NULL)
g_free (priv->synchronous);
priv->synchronous = g_strdup (sync);
}
void
bubble_set_sender (Bubble *self,
const gchar *sender)
{
BubblePrivate* priv;
g_return_if_fail (IS_BUBBLE (self));
priv = self->priv;
if (priv->sender != NULL)
g_free (priv->sender);
priv->sender = g_strdup (sender);
}
gboolean
bubble_is_synchronous (Bubble *self)
{
if (!self || !IS_BUBBLE (self))
return FALSE;
return (self->priv->synchronous != NULL);
}
gboolean
bubble_is_urgent (Bubble *self)
{
g_return_val_if_fail (IS_BUBBLE (self), FALSE);
return (self->priv->urgency == 2);
}
guint
bubble_get_urgency (Bubble *self)
{
g_return_val_if_fail (IS_BUBBLE (self), 0);
return self->priv->urgency;
}
void
bubble_set_urgency (Bubble *self,
guint urgency)
{
g_return_if_fail (IS_BUBBLE (self));
self->priv->urgency = urgency;
}
void
bubble_determine_layout (Bubble* self)
{
BubblePrivate* priv;
/* sanity test */
if (!self || !IS_BUBBLE (self))
return;
priv = self->priv;
/* set a sane default */
priv->layout = LAYOUT_NONE;
/* icon-only layout-case, e.g. eject */
if (priv->icon_only && priv->icon_pixbuf != NULL)
{
priv->layout = LAYOUT_ICON_ONLY;
return;
}
/* icon + indicator layout-case, e.g. volume */
if ((priv->icon_pixbuf != NULL) &&
(priv->title->len != 0) &&
(priv->value >= -1))
{
priv->layout = LAYOUT_ICON_INDICATOR;
return;
}
/* icon + title layout-case, e.g. "Wifi signal lost" */
if ((priv->icon_pixbuf != NULL) &&
(priv->title->len != 0) &&
(priv->message_body->len == 0) &&
(priv->value == -2))
{
priv->layout = LAYOUT_ICON_TITLE;
return;
}
/* icon/avatar + title + body/message layout-case, e.g. IM-message */
if ((priv->icon_pixbuf != NULL) &&
(priv->title->len != 0) &&
(priv->message_body->len != 0) &&
(priv->value == -2))
{
priv->layout = LAYOUT_ICON_TITLE_BODY;
return;
}
/* title + body/message layout-case, e.g. IM-message without avatar */
if ((priv->icon_pixbuf == NULL) &&
(priv->title->len != 0) &&
(priv->message_body->len != 0) &&
(priv->value == -2))
{
priv->layout = LAYOUT_TITLE_BODY;
return;
}
/* title-only layout-case, use discouraged but needs to be supported */
if ((priv->icon_pixbuf == NULL) &&
(priv->title->len != 0) &&
(priv->message_body->len == 0) &&
(priv->value == -2))
{
priv->layout = LAYOUT_TITLE_ONLY;
return;
}
return;
}
BubbleLayout
bubble_get_layout (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return LAYOUT_NONE;
return self->priv->layout;
}
void
bubble_set_icon_only (Bubble* self,
gboolean allowed)
{
if (!self || !IS_BUBBLE (self))
return;
self->priv->icon_only = allowed;
}
void
bubble_set_append (Bubble* self,
gboolean allowed)
{
if (!self || !IS_BUBBLE (self))
return;
self->priv->append = allowed;
}
gboolean
bubble_is_append_allowed (Bubble* self)
{
if (!self || !IS_BUBBLE (self))
return FALSE;
return self->priv->append;
}
void
bubble_append_message_body (Bubble* self,
const gchar* append_body)
{
gboolean result = FALSE;
gchar* text = NULL;
GError* error = NULL;
BubblePrivate* priv = NULL;
if (!self || !IS_BUBBLE (self) || !append_body)
return;
priv = self->priv;
// filter out any HTML/markup if possible
result = pango_parse_markup (append_body,
-1,
0, // no accel-marker needed
NULL, // no PangoAttr needed
&text,
NULL, // no accel-marker-return needed
&error);
if (error && !result)
{
g_warning ("%s(): Got error \"%s\"\n",
G_STRFUNC,
error->message);
g_error_free (error);
error = NULL;
if (text)
g_free (text);
}
if (text)
{
g_strstrip (text);
if (text[0] == '\0')
{
if (priv->message_body->len > 0 &&
priv->message_body->str[priv->message_body->len-1] != '\n')
{
// This is a special combination, that allows us to remember that a
// new empty body line has been requested, but we won't show this till
// something visible will be appended.
g_string_append_c (priv->message_body, '\0');
g_string_append_c (priv->message_body, '\n');
}
g_free (text);
return;
}
if (priv->message_body->len > 1)
{
if (priv->message_body->str[priv->message_body->len-1] == '\n' &&
priv->message_body->str[priv->message_body->len-2] == '\0')
{
// A new message has been appended, let's remove the \0 we put before.
g_string_erase (priv->message_body, priv->message_body->len-2, 1);
}
}
// append text to current message-body
g_string_append_c (priv->message_body, '\n');
g_string_append (priv->message_body, text);
priv->message_body_needs_refresh = TRUE;
g_signal_emit (self,
g_bubble_signals[MESSAGE_BODY_INSERTED],
0,
text);
g_object_notify (
G_OBJECT (gtk_widget_get_accessible (priv->widget)),
"accessible-description");
g_free (text);
}
}
void
bubble_sync_with (Bubble *self,
Bubble *other)
{
g_return_if_fail (IS_BUBBLE (self) && IS_BUBBLE (other));
bubble_set_timeout (self,
bubble_get_timeout (other));
bubble_start_timer (self, FALSE);
bubble_start_timer (other, FALSE);
}
./src/defaults.h 0000644 0000156 0000165 00000015662 12704153542 013661 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** defaults.h - a singelton providing all default values for sizes, colors etc.
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __DEFAULTS_H
#define __DEFAULTS_H
#include
#include
#include
G_BEGIN_DECLS
#define DEFAULTS_TYPE (defaults_get_type ())
#define DEFAULTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEFAULTS_TYPE, Defaults))
#define DEFAULTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEFAULTS_TYPE, DefaultsClass))
#define IS_DEFAULTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEFAULTS_TYPE))
#define IS_DEFAULTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEFAULTS_TYPE))
#define DEFAULTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEFAULTS_TYPE, DefaultsClass))
/* FIXME: quick hack to get every measurement to use em instead of pixels, to
* correctly use these two macros you'll need to pass it a valid Defaults class
* object
*
* example use:
* PIXEL2EM(42, defaults) - that will returns a gdouble
* EM2PIXEL(0.375, defaults) - that will return a gint */
#define PIXELS2EM(pixel_value, d) ((gdouble) ((gdouble) pixel_value / defaults_get_pixel_per_em(d)))
#define EM2PIXELS(em_value, d) ((gint) (em_value * defaults_get_pixel_per_em(d)))
typedef struct _Defaults Defaults;
typedef struct _DefaultsClass DefaultsClass;
typedef enum
{
GRAVITY_NONE = 0,
GRAVITY_NORTH_EAST, // top-right of screen
GRAVITY_EAST // vertically centered at right of screen
} Gravity;
typedef enum
{
SLOT_ALLOCATION_NONE = 0,
SLOT_ALLOCATION_FIXED, // async. always in top, sync. always in bottom
SLOT_ALLOCATION_DYNAMIC // async. and sync can take top or bottom
} SlotAllocation;
/* instance structure */
struct _Defaults
{
GObject parent;
/* private */
GSettings* nosd_settings;
GSettings* gnome_settings;
gint desktop_width;
gint desktop_height;
gdouble desktop_bottom_gap;
gdouble stack_height;
gdouble bubble_vert_gap;
gdouble bubble_horz_gap;
gdouble bubble_width;
gdouble bubble_min_height;
gdouble bubble_max_height;
gdouble bubble_shadow_size;
GString* bubble_shadow_color;
GString* bubble_bg_color;
GString* bubble_bg_opacity;
GString* bubble_hover_opacity;
gdouble bubble_corner_radius;
gdouble content_shadow_size;
GString* content_shadow_color;
gdouble margin_size;
gdouble icon_size;
gdouble gauge_size;
gdouble gauge_outline_width;
gint fade_in_timeout;
gint fade_out_timeout;
gint on_screen_timeout;
GString* text_font_face;
GString* text_title_color;
gint text_title_weight;
gdouble text_title_size;
GString* text_body_color;
gint text_body_weight;
gdouble text_body_size;
gdouble pixels_per_em;
gdouble system_font_size;
gdouble screen_dpi;
Gravity gravity;
SlotAllocation slot_allocation;
};
/* class structure */
struct _DefaultsClass
{
GObjectClass parent;
/*< signals >*/
void (*value_changed) (Defaults* defaults); /* used to "inform" bubble
** about any changes in
** rendering and position */
void (*gravity_changed) (Defaults* defaults); // used to "inform" about
// gravity/position change
// for bubbles
};
GType defaults_get_type (void);
Defaults*
defaults_new (void);
gint
defaults_get_desktop_width (Defaults* self);
gint
defaults_get_desktop_height (Defaults* self);
gint
defaults_get_desktop_top (Defaults* self);
gint
defaults_get_desktop_bottom (Defaults* self);
gint
defaults_get_desktop_left (Defaults* self);
gint
defaults_get_desktop_right (Defaults* self);
gdouble
defaults_get_desktop_bottom_gap (Defaults* self);
gdouble
defaults_get_stack_height (Defaults* self);
gdouble
defaults_get_bubble_width (Defaults* self);
gdouble
defaults_get_bubble_min_height (Defaults* self);
gdouble
defaults_get_bubble_max_height (Defaults* self);
gdouble
defaults_get_bubble_vert_gap (Defaults* self);
gdouble
defaults_get_bubble_horz_gap (Defaults* self);
gdouble
defaults_get_bubble_shadow_size (Defaults* self, gboolean is_composited);
gchar*
defaults_get_bubble_shadow_color (Defaults* self);
gchar*
defaults_get_bubble_bg_color (Defaults* self);
gchar*
defaults_get_bubble_bg_opacity (Defaults* self);
gchar*
defaults_get_bubble_hover_opacity (Defaults* self);
gdouble
defaults_get_bubble_corner_radius (Defaults* self, gboolean is_composited);
gdouble
defaults_get_content_shadow_size (Defaults* self);
gchar*
defaults_get_content_shadow_color (Defaults* self);
gdouble
defaults_get_margin_size (Defaults* self);
gdouble
defaults_get_icon_size (Defaults* self);
gdouble
defaults_get_gauge_size (Defaults* self);
gdouble
defaults_get_gauge_outline_width (Defaults* self);
gint
defaults_get_fade_in_timeout (Defaults* self);
gint
defaults_get_fade_out_timeout (Defaults* self);
gint
defaults_get_on_screen_timeout (Defaults* self);
gchar*
defaults_get_text_font_face (Defaults* self);
gchar*
defaults_get_text_title_color (Defaults* self);
gint
defaults_get_text_title_weight (Defaults* self);
gdouble
defaults_get_text_title_size (Defaults* self);
gchar*
defaults_get_text_body_color (Defaults* self);
gint
defaults_get_text_body_weight (Defaults* self);
gdouble
defaults_get_text_body_size (Defaults* self);
gdouble
defaults_get_pixel_per_em (Defaults* self);
gdouble
defaults_get_system_font_size (Defaults* self);
gdouble
defaults_get_screen_dpi (Defaults* self);
void
defaults_refresh_bg_property (Defaults *self);
void
defaults_refresh_screen_dimension_properties (Defaults *self);
void
defaults_get_top_corner (Defaults *self, GdkScreen **screen, gint *x, gint *y);
Gravity
defaults_get_gravity (Defaults *self);
SlotAllocation
defaults_get_slot_allocation (Defaults *self);
G_END_DECLS
#endif /* __DEFAULTS_H */
./src/bubble-window-accessible-factory.h 0000644 0000156 0000165 00000005162 12704153542 020344 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window-accessible-factory.h - implements an accessible object factory
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef _BUBBLE_WINDOW_ACCESSIBLE_FACTORY_H_
#define _BUBBLE_WINDOW_ACCESSIBLE_FACTORY_H_
#include
G_BEGIN_DECLS
#define BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY (bubble_window_accessible_factory_get_type ())
#define BUBBLE_WINDOW_ACCESSIBLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY, BubbleWindowAccessibleFactory))
#define BUBBLE_WINDOW_ACCESSIBLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY, BubbleWindowAccessibleFactoryClass))
#define BUBBLE_WINDOW_IS_ACCESSIBLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY))
#define BUBBLE_WINDOW_IS_ACCESSIBLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY))
#define BUBBLE_WINDOW_ACCESSIBLE_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE_FACTORY, BubbleWindowAccessibleFactoryClass))
typedef struct _BubbleWindowAccessibleFactoryClass BubbleWindowAccessibleFactoryClass;
typedef struct _BubbleWindowAccessibleFactory BubbleWindowAccessibleFactory;
struct _BubbleWindowAccessibleFactoryClass
{
AtkObjectFactoryClass parent_class;
};
struct _BubbleWindowAccessibleFactory
{
AtkObjectFactory parent_instance;
};
GType bubble_window_accessible_factory_get_type (void) G_GNUC_CONST;
AtkObjectFactory* bubble_window_accessible_factory_new (void);
G_END_DECLS
#endif /* _BUBBLE_WINDOW_ACCESSIBLE_FACTORY_H_ */
./src/dbus.h 0000644 0000156 0000165 00000003413 12704153542 012776 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** dbus.h - dbus boiler-plate code for talking with libnotify
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Mirco "MacSlow" Mueller
** David Barth
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef __NOTIFY_OSD_DBUS_H
#define __NOTIFY_OSD_DBUS_H
#include
#include
#include
#ifndef DBUS_PATH
#define DBUS_PATH "/org/freedesktop/Notifications"
#endif
#ifndef DBUS_NAME
#define DBUS_NAME "org.freedesktop.Notifications"
#endif
DBusGConnection*
dbus_create_service_instance (const char *service_name);
DBusGConnection*
dbus_get_connection (void);
void
dbus_send_close_signal (gchar *dest,
guint id,
guint reason);
void
dbus_send_action_signal (gchar *dest,
guint id,
const char *action_key);
G_END_DECLS
#endif /* __NOTIFY_OSD_DBUS_H */
./src/send-test-notification.sh 0000755 0000156 0000165 00000004421 12704153542 016621 0 ustar jenkins jenkins #!/bin/sh
notify-send "Take note" "The next example will test the icon-only layout-case" -i dialog-info
sleep 2
notify-send "Eject" -i notification-device-eject -h string:x-canonical-private-icon-only:
sleep 2
notify-send "WiFi signal found" -i notification-network-wireless-medium
sleep 2
notify-send "WiFi signal lost" -i notification-network-wireless-disconnected
sleep 2
notify-send "Volume" -i notification-audio-volume-medium -h int:value:75 -h string:x-canonical-private-synchronous:
sleep 2
notify-send "Volume" -i notification-audio-volume-low -h int:value:30 -h string:x-canonical-private-synchronous:
sleep 2
notify-send "Brightness" -i notification-display-brightness-high -h int:value:101 -h string:x-canonical-private-synchronous:
sleep 2
notify-send "Brightness" -i notification-keyboard-brightness-medium -h int:value:45 -h string:x-canonical-private-synchronous:
sleep 2
notify-send "Testing markup" "Some bold, underlined, italic text. Note, you should not see any marked up text."
sleep 2
notify-send "Jamshed Kakar" "Hey, what about this restaurant? http://www.blafasel.org
Would you go from your place by train or should I pick you up from work? What do you think?"
sleep 2
notify-send "English bubble" "The quick brown fox jumps over the lazy dog." -i network
sleep 2
notify-send "Bubble from Germany" "Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark." -i gnome-system
sleep 2
notify-send "Very russian" "Съешь ещё этих мягких французских булок, да выпей чаю." -i dialog-info
sleep 2
notify-send "More from Germany" "Oje, Qualm verwölkt Dix zig Farbtriptychons." -i gnome-globe
sleep 2
notify-send "Filter the world 1/3" "Ubuntu
Don't rock the boat
Kick him while he's down
\"Film spectators are quiet vampires.\"
Peace & Love
War & Peace
Law & Order
Love & War
7 > 3
7 > 3"
sleep 2
notify-send "Filter the world 2/3" "7 > 3
7 > 3
14 < 42
14 < 42
14 < 42
14 < 42
><
<>
< this is not a tag >
Not italic"
sleep 2
notify-send "Filter the world 3/3" "So broken
Nothing to see
Test
Bold
Span
E-flat
Sandwich
Fry
Testing tag"
./src/bubble-window.h 0000644 0000156 0000165 00000004210 12704153542 014575 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window.h - implements bubble window
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef _BUBBLE_WINDOW_H_
#define _BUBBLE_WINDOW_H_
#include
//#include
#include
G_BEGIN_DECLS
#define BUBBLE_TYPE_WINDOW (bubble_window_get_type ())
#define BUBBLE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUBBLE_TYPE_WINDOW, BubbleWindow))
#define BUBBLE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BUBBLE_TYPE_WINDOW, BubbleWindowClass))
#define BUBBLE_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUBBLE_TYPE_WINDOW))
#define BUBBLE_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUBBLE_TYPE_WINDOW))
#define BUBBLE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BUBBLE_TYPE_WINDOW, BubbleWindowClass))
typedef struct _BubbleWindowClass BubbleWindowClass;
typedef struct _BubbleWindow BubbleWindow;
struct _BubbleWindowClass
{
GtkWindowClass parent_class;
};
struct _BubbleWindow
{
GtkWindow parent_instance;
};
GType bubble_window_get_type (void) G_GNUC_CONST;
GtkWidget *bubble_window_new (void);
G_END_DECLS
#endif /* _BUBBLE_WINDOW_H_ */
./src/bubble-window-accessible.h 0000644 0000156 0000165 00000004670 12704153542 016702 0 ustar jenkins jenkins /*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
** 10 20 30 40 50 60 70 80
**
** notify-osd
**
** bubble-window-accessible.h - implements an accessible bubble window
**
** Copyright 2009 Canonical Ltd.
**
** Authors:
** Eitan Isaacson
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License version 3, as published
** by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranties of
** MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
**
*******************************************************************************/
#ifndef _BUBBLE_WINDOW_ACCESSIBLE_H_
#define _BUBBLE_WINDOW_ACCESSIBLE_H_
#include
#include
#include "bubble-window.h"
G_BEGIN_DECLS
#define BUBBLE_WINDOW_TYPE_ACCESSIBLE (bubble_window_accessible_get_type ())
#define BUBBLE_WINDOW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE, BubbleWindowAccessible))
#define BUBBLE_WINDOW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BUBBLE_WINDOW_TYPE_ACCESSIBLE, BubbleWindowAccessibleClass))
#define BUBBLE_WINDOW_IS_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE))
#define BUBBLE_WINDOW_IS_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BUBBLE_WINDOW_TYPE_ACCESSIBLE))
#define BUBBLE_WINDOW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BUBBLE_WINDOW_TYPE_ACCESSIBLE, BubbleWindowAccessibleClass))
typedef struct _BubbleWindowAccessibleClass BubbleWindowAccessibleClass;
typedef struct _BubbleWindowAccessible BubbleWindowAccessible;
struct _BubbleWindowAccessibleClass
{
GtkAccessibleClass parent_class;
};
struct _BubbleWindowAccessible
{
GtkAccessible parent_instance;
};
GType bubble_window_accessible_get_type (void);
AtkObject* bubble_window_accessible_new (GtkWidget *widget);
G_END_DECLS
#endif /* _BUBBLE_WINDOW_ACCESSIBLE_H_ */
./src/tile.c 0000644 0000156 0000165 00000015261 12704153542 012775 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// tile.c - implements public API surface/blur cache
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include "util.h"
#include "tile.h"
#include "raico-blur.h"
struct _tile_private_t
{
cairo_surface_t* normal;
cairo_surface_t* blurred;
guint blur_radius;
gboolean use_padding;
guint pad_width;
guint pad_height;
};
tile_t*
tile_new (cairo_surface_t* source, guint blur_radius)
{
tile_private_t* priv = NULL;
tile_t* tile = NULL;
raico_blur_t* blur = NULL;
if (blur_radius < 1)
return NULL;
priv = g_new0 (tile_private_t, 1);
if (!priv)
return NULL;
tile = g_new0 (tile_t, 1);
if (!tile)
return NULL;
tile->priv = priv;
tile->priv->normal = copy_surface (source);
tile->priv->blurred = copy_surface (source);
tile->priv->blur_radius = blur_radius;
tile->priv->use_padding = FALSE;
tile->priv->pad_width = 0;
tile->priv->pad_height = 0;
blur = raico_blur_create (RAICO_BLUR_QUALITY_LOW);
raico_blur_set_radius (blur, blur_radius);
raico_blur_apply (blur, tile->priv->blurred);
raico_blur_destroy (blur);
return tile;
}
tile_t*
tile_new_for_padding (cairo_surface_t* normal,
cairo_surface_t* blurred,
gint width,
gint height)
{
tile_private_t* priv = NULL;
tile_t* tile = NULL;
priv = g_new0 (tile_private_t, 1);
if (!priv)
return NULL;
tile = g_new0 (tile_t, 1);
if (!tile)
return NULL;
if (cairo_surface_status (normal) != CAIRO_STATUS_SUCCESS ||
cairo_surface_status (blurred) != CAIRO_STATUS_SUCCESS)
return NULL;
tile->priv = priv;
tile->priv->normal = copy_surface (normal);
tile->priv->blurred = copy_surface (blurred);
tile->priv->blur_radius = 0;
tile->priv->use_padding = TRUE;
tile->priv->pad_width = width;
tile->priv->pad_height = height;
return tile;
}
void
tile_destroy (tile_t* tile)
{
if (!tile)
return;
//cairo_surface_write_to_png (tile->priv->normal, "./tile-normal.png");
//cairo_surface_write_to_png (tile->priv->blurred, "./tile-blurred.png");
cairo_surface_destroy (tile->priv->normal);
cairo_surface_destroy (tile->priv->blurred);
g_free ((gpointer) tile->priv);
g_free ((gpointer) tile);
}
// assumes x and y to be actual pixel-measurement values
void
tile_paint (tile_t* tile,
cairo_t* cr,
gdouble x,
gdouble y,
gdouble normal_alpha,
gdouble blurred_alpha)
{
if (!tile)
return;
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
return;
if (normal_alpha > 0.0f)
{
cairo_set_source_surface (cr, tile->priv->normal, x, y);
cairo_paint_with_alpha (cr, normal_alpha);
}
if (blurred_alpha > 0.0f)
{
cairo_set_source_surface (cr, tile->priv->blurred, x, y);
cairo_paint_with_alpha (cr, blurred_alpha);
}
}
void
_pad_paint (cairo_t* cr,
cairo_pattern_t* pattern,
guint x,
guint y,
guint width,
guint height,
guint pad_width,
guint pad_height,
gdouble alpha)
{
cairo_matrix_t matrix;
// top left
cairo_rectangle (cr,
x,
y,
width - pad_width,
height - pad_height);
cairo_clip (cr);
cairo_paint_with_alpha (cr, alpha);
cairo_reset_clip (cr);
// top right
cairo_matrix_init_scale (&matrix, -1.0f, 1.0f);
cairo_matrix_translate (&matrix, -1.0f * width, 0.0f);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
width - pad_width,
y,
pad_width,
height - pad_height);
cairo_clip (cr);
cairo_paint_with_alpha (cr, alpha);
cairo_reset_clip (cr);
// bottom right
cairo_matrix_init_scale (&matrix, -1.0f, -1.0f);
cairo_matrix_translate (&matrix, -1.0f * width, -1.0f * height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
pad_width,
height - pad_height,
width - pad_width,
pad_height);
cairo_clip (cr);
cairo_paint_with_alpha (cr, alpha);
cairo_reset_clip (cr);
// bottom left
cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
cairo_matrix_translate (&matrix, 0.0f, -1.0f * height);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_rectangle (cr,
x,
height - pad_height,
pad_width,
pad_height);
cairo_clip (cr);
cairo_paint_with_alpha (cr, alpha);
cairo_reset_clip (cr);
}
void
tile_paint_with_padding (tile_t* tile,
cairo_t* cr,
gdouble x,
gdouble y,
gdouble width,
gdouble height,
gdouble normal_alpha,
gdouble blurred_alpha)
{
cairo_pattern_t* pattern = NULL;
guint pad_width = 0;
guint pad_height = 0;
if (!tile)
return;
if (!tile->priv->use_padding)
return;
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
return;
pad_width = tile->priv->pad_width;
pad_height = tile->priv->pad_height;
if (normal_alpha > 0.0f)
{
pattern = cairo_pattern_create_for_surface (tile->priv->normal);
if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS) {
if (pattern)
cairo_pattern_destroy (pattern);
return;
}
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_set_source (cr, pattern);
_pad_paint (cr,
pattern,
x,
y,
width,
height,
pad_width,
pad_height,
normal_alpha);
cairo_pattern_destroy (pattern);
}
if (blurred_alpha > 0.0f)
{
pattern = cairo_pattern_create_for_surface (tile->priv->blurred);
if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS) {
if (pattern)
cairo_pattern_destroy (pattern);
return;
}
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_set_source (cr, pattern);
_pad_paint (cr,
pattern,
x,
y,
width,
height,
pad_width,
pad_height,
blurred_alpha);
cairo_pattern_destroy (pattern);
}
}
./src/dialog.c 0000644 0000156 0000165 00000017162 12704153542 013301 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// dialog.c - fallback to display when a notification is not spec-compliant
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
// David Barth
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
//
////////////////////////////////////////////////////////////////////////////////
#include "dialog.h"
#include
#include "dbus.h"
#include "util.h"
typedef struct _DialogInfo DialogInfo;
struct _DialogInfo
{
int id;
gchar* sender;
};
static void
dialog_info_destroy (DialogInfo* dialog_info)
{
if (!dialog_info)
return;
g_free (dialog_info->sender);
g_free (dialog_info);
}
static void
handle_close (GtkWidget* dialog,
guint response_id,
gpointer user_data)
{
DialogInfo* dialog_info = g_object_get_data (G_OBJECT (dialog),
"_dialog_info");
if (!dialog_info)
{
gtk_widget_destroy (GTK_WIDGET (dialog));
return;
}
dbus_send_close_signal (dialog_info->sender,
dialog_info->id,
2);
dialog_info_destroy (dialog_info);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
handle_response (GtkWidget* button,
GdkEventButton* event,
GtkDialog* dialog)
{
gchar *action = g_object_get_data (G_OBJECT (button),
"_libnotify_action");
DialogInfo *dialog_info = g_object_get_data (G_OBJECT (dialog),
"_dialog_info");
if (!dialog_info || !action)
{
gtk_widget_destroy (GTK_WIDGET (dialog));
return;
}
// send a "click" signal...
dbus_send_action_signal (dialog_info->sender,
dialog_info->id,
action);
dbus_send_close_signal (dialog_info->sender,
dialog_info->id,
3);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
add_pathological_action_buttons (GtkWidget* dialog,
gchar** actions)
{
int i;
for (i = 0; actions[i] != NULL; i += 2)
{
gchar *label = actions[i + 1];
if (label == NULL)
{
g_warning ("missing label for action \"%s\""
"; discarding the action",
actions[i]);
break;
}
if (g_strcmp0 (actions[i], "default") == 0)
continue;
GtkWidget *button =
gtk_dialog_add_button (GTK_DIALOG (dialog),
label,
i/2);
g_object_set_data_full (G_OBJECT (button),
"_libnotify_action",
g_strdup (actions[i]),
g_free);
g_signal_connect (G_OBJECT (button),
"button-release-event",
G_CALLBACK (handle_response),
dialog);
}
}
void
fallback_dialog_show (Defaults* d,
const gchar* sender,
const gchar* app_name,
int id,
const gchar* title_text,
const gchar* _body_message,
gchar** actions)
{
GtkWidget* dialog;
GtkWidget* hbox;
GtkWidget* vbox;
GtkWidget* title;
GtkWidget* body;
GtkWidget* image;
gchar* body_message = NULL;
gchar* new_body_message = NULL;
guint gap = EM2PIXELS (defaults_get_margin_size (d), d);
gboolean success = FALSE;
GError* error = NULL;
if (!IS_DEFAULTS (d) ||
!sender ||
!app_name ||
!title_text ||
!_body_message ||
!actions)
return;
DialogInfo* dialog_info = g_new0 (DialogInfo, 1);
if (!dialog_info)
return;
dialog_info->id = id;
dialog_info->sender = g_strdup(sender);
dialog = gtk_dialog_new ();
hbox = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"spacing", gap,
"border-width", 12,
NULL);
// We deliberately use the gtk-dialog-warning icon rather than
// the specified one to discourage people from trying to use
// the notification system as a way of showing custom alert
// dialogs.
image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
GTK_ICON_SIZE_DIALOG);
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
vbox = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_VERTICAL,
NULL);
title = gtk_label_new (NULL);
gtk_label_set_text (GTK_LABEL (title), title_text);
gtk_label_set_line_wrap (GTK_LABEL (title), TRUE);
body = gtk_label_new (NULL);
body_message = filter_text (_body_message);
if (body_message)
{
success = pango_parse_markup (body_message,
-1,
0,
NULL,
&new_body_message,
NULL,
&error);
if (error && !success)
{
g_warning ("fallback_dialog_show(): Got error \"%s\"\n",
error->message);
g_error_free (error);
error = NULL;
}
}
if (new_body_message)
{
gtk_label_set_text (GTK_LABEL (body), new_body_message);
g_free (new_body_message);
}
else
gtk_label_set_text (GTK_LABEL (body), body_message);
g_free (body_message);
gtk_label_set_line_wrap (GTK_LABEL (body), TRUE);
gtk_misc_set_alignment (GTK_MISC (title), 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), title, TRUE, TRUE, 0);
gtk_misc_set_alignment (GTK_MISC (body), 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), body, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (hbox), vbox);
gtk_container_add (GTK_CONTAINER (
gtk_dialog_get_content_area (
GTK_DIALOG (dialog))),
hbox);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 2);
gtk_window_set_position (GTK_WINDOW (dialog),
GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (dialog),
EM2PIXELS (defaults_get_bubble_width (d) * 1.2f, d),
-1);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_window_set_title (GTK_WINDOW (dialog), app_name);
gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE);
// is it a bad notification with actions?
if (actions[0] != NULL)
add_pathological_action_buttons (dialog, actions);
GtkButton *cancel = GTK_BUTTON (
gtk_dialog_add_button (GTK_DIALOG (dialog),
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL));
g_signal_connect_swapped (G_OBJECT (cancel),
"button-release-event",
G_CALLBACK (handle_close),
dialog);
gtk_widget_set_can_default(GTK_WIDGET(cancel), FALSE);
g_signal_connect (G_OBJECT (dialog),
"response",
G_CALLBACK (handle_close),
dialog);
GtkButton *ok = GTK_BUTTON (
gtk_dialog_add_button (GTK_DIALOG (dialog),
GTK_STOCK_OK,
GTK_RESPONSE_OK));
g_object_set_data_full (G_OBJECT (ok),
"_libnotify_action",
g_strdup ("default"),
g_free);
g_signal_connect (G_OBJECT (ok),
"button-release-event",
G_CALLBACK (handle_response),
dialog);
gtk_widget_set_can_default(GTK_WIDGET(ok), FALSE);
g_object_set_data (G_OBJECT (dialog),
"_dialog_info",
dialog_info);
g_signal_connect (G_OBJECT (dialog),
"button-release-event",
G_CALLBACK (handle_response),
dialog);
gtk_window_set_focus (GTK_WINDOW (dialog),
NULL);
gtk_window_set_default (GTK_WINDOW (dialog),
NULL);
gtk_widget_show_all (dialog);
}
./src/notification.c 0000644 0000156 0000165 00000042745 12704153542 014535 0 ustar jenkins jenkins ////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
// 10 20 30 40 50 60 70 80
//
// notify-osd
//
// notification.c - notification object storing attributes like title- and body-
// text, value, icon, id, sender-pid etc.
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
// Mirco "MacSlow" Mueller
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see