./0000755000015600001650000000000012704153542011100 5ustar jenkinsjenkins./autogen.sh0000755000015600001650000000117612704153542013106 0ustar jenkinsjenkins#!/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/0000755000015600001650000000000012704153542012242 5ustar jenkinsjenkins./tests/notifyosd.py0000755000015600001650000000410512704153542014635 0ustar jenkinsjenkins#!/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] [<body-text>] 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <unistd.h> #include <glib.h> #include <gtk/gtk.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <unistd.h> #include <glib.h> #include <gtk/gtk.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <stdlib.h> #include <unistd.h> #include <libnotify/notify.h> #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 <b>bold</b>, <i>italic</i> nor <u>underlined</u>.\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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <unistd.h> #include <glib.h> #include <libnotify/notify.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <cairo.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #define _XOPEN_SOURCE 500 // needed for usleep() from unistd.h #include <unistd.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <gtk/gtk.h> #include <cairo.h> #include <pango/pangocairo.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #include <gtk/gtk.h> /* 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <egg/egg-hack.h> #include <egg/egg-alpha.h> 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <unistd.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <X11/Xatom.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> #include <math.h> #include <stdlib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <stdlib.h> #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 <cody.russell@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #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[] = { { "<a href=\"http://www.ubuntu.com/\">Ubuntu</a>", "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 >" }, { "<i>Not italic</i>", "Not italic" }, { "<b>So broken</i>", "<b>So broken</i>" }, { "<img src=\"foobar.png\" />Nothing to see", "Nothing to see" }, { "<u>Test</u>", "Test" }, { "<b>Bold</b>", "Bold" }, { "<span>Span</span>", "Span" }, { "<s>E-flat</s>", "E-flat" }, { "<sub>Sandwich</sub>", "Sandwich", }, { "<small>Fry</small>", "Fry" }, { "<tt>Testing tag</tt>", "Testing tag" }, { "<html>Surrounded by html</html>", "Surrounded by html" }, { "<qt>Surrounded by qt</qt>", "Surrounded by qt" }, { "First line <br dumb> \r \n Second line", "First line\nSecond line" }, { "First line\n<br /> <br>\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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <unistd.h> #include <glib.h> #include <gtk/gtk.h> #include "dnd.h" #include "util.h" #include <libwnck/libwnck.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <X11/Xatom.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> #include <math.h> #include <stdlib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef __OBSERVER_H #define __OBSERVER_H #include <glib-object.h> #include <gtk/gtk.h> 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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #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 <mirco.mueller@canonical.com> // David Barth <david.barth@canonical.com> // // Contributor(s): // Abhishek Mukherjee <abhishek.mukher.g@gmail.com> (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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef __DIALOG_H #define __DIALOG_H #include <glib.h> #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 <mirco.mueller@canonical.com> // David Barth <david.barth@canonical.com> // // Contributor(s): // Eitan Isaacson <eitan@ascender.com> (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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef __BUBBLE_H #define __BUBBLE_H #include <glib-object.h> #include <gdk-pixbuf/gdk-pixbuf.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef _GAUSSIAN_BLUR_H #define _GAUSSIAN_BLUR_H #include <glib.h> #include <cairo.h> 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** Contributor(s): ** Abhishek Mukherjee <abhishek.mukher.g@gmail.com> (append fixes, rev. 280) ** Aurélien Gâteau <aurelien.gateau@canonical.com> (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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <assert.h> #include "dbus.h" #include <dbus/dbus-glib-lowlevel.h> #include <glib-object.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include "config.h" #include <stdlib.h> #include <glib.h> #include <glib-object.h> #include <dbus/dbus-glib.h> #include <X11/Xproto.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <gdk/gdkx.h> #include <libwnck/libwnck.h> #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 <mirco.mueller@canonical.com> // // Notes: // based on stack-blur algorithm by Mario Klingemann <mario@quasimondo.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef _STACK_BLUR_H #define _STACK_BLUR_H #include <glib.h> #include <cairo.h> 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef _RAICO_BLUR_H #define _RAICO_BLUR_H #include <glib.h> #include <cairo.h> 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ /* 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <math.h> #include <pixman.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <string.h> #include <stdlib.h> #include <glib.h> #include <gtk/gtk.h> #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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include "bubble-window-accessible.h" #include "bubble.h" #include <string.h> 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** Contributor(s): ** Sense "qense" Hofstede <qense@ubuntu.com> (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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include "config.h" #include <sys/time.h> #include <time.h> #include <stdio.h> #include <glib.h> #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 <mirco.mueller@canonical.com> // Jason Smith <jason.smith@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// // FIXME: not working yet, unfinished #include <math.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <math.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <string.h> #include <stdlib.h> #include <dbus/dbus.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> #include <dbus/dbus-glib-lowlevel.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef _TILE_H #define _TILE_H #include <glib.h> #include <cairo.h> 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����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <node name="/org/freedesktop/Notifications"> <interface name="org.freedesktop.Notifications"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="stack"/> <method name="Notify"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="stack_notify_handler"/> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg type="s" name="app_name" direction="in" /> <arg type="u" name="id" direction="in" /> <arg type="s" name="icon" direction="in" /> <arg type="s" name="summary" direction="in" /> <arg type="s" name="body" direction="in" /> <arg type="as" name="actions" direction="in" /> <arg type="a{sv}" name="hints" direction="in" /> <arg type="i" name="timeout" direction="in" /> <arg type="u" name="return_id" direction="out" /> </method> <method name="CloseNotification"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="stack_close_notification_handler"/> <arg type="u" name="id" direction="in" /> </method> <method name="GetCapabilities"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="stack_get_capabilities"/> <arg type="as" name="return_caps" direction="out"/> </method> <method name="GetServerInformation"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="stack_get_server_information"/> <arg type="s" name="return_name" direction="out"/> <arg type="s" name="return_vendor" direction="out"/> <arg type="s" name="return_version" direction="out"/> <arg type="s" name="return_spec_version" direction="out"/> </method> </interface> </node> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ /* 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <gtk/gtk.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef __TIMINGS_H #define __TIMINGS_H #include <glib-object.h> 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #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 <cody.russell@canonical.com> ** Mirco "MacSlow" Mueller <mirco.mueller@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> #include <cairo.h> #include <gtk/gtk.h> #include <gdk/gdkx.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** Contributor(s): ** Chow Loong Jin <hyperair@gmail.com> (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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <X11/Xlib.h> #include <X11/Xatom.h> #include <gdk/gdk.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> #include <libwnck/libwnck.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef __NOTIFICATION_H #define __NOTIFICATION_H #include <glib-object.h> #include <gdk-pixbuf/gdk-pixbuf.h> 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #ifndef _EXPONENTIAL_BLUR_H #define _EXPONENTIAL_BLUR_H #include <glib.h> #include <cairo.h> 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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #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 <cody.russell@canonical.com> ** Mirco "MacSlow" Mueller <mirco.mueller@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <string.h> #include <glib.h> #include <gtk/gtk.h> #include <gdk/gdkx.h> #include <pango/pango.h> #include <cairo.h> #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 " *((<br[^/>]*/?>|\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 <mirco.mueller@canonical.com> // // Notes: // based on stack-blur algorithm by Mario Klingemann <mario@quasimondo.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// // FIXME: not working yet, unfinished #include <math.h> #include <stdlib.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #include <glib.h> 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef __STACK_H #define __STACK_H #include <glib-object.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> #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 <mirco.mueller@canonical.com> // David Barth <david.barth@canonical.com> // // Contributor(s): // Frederic "fredp" Peters <fpeters@gnome.org> (icon-only fix, rev. 204) // Eitan Isaacson <eitan@ascender.com> (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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include <string.h> #include <stdlib.h> #include <X11/Xatom.h> #include <glib.h> #include <gtk/gtk.h> //#include <gdk/gdkx.h> #include <pixman.h> #include <math.h> #include <egg/egg-hack.h> #include <egg/egg-alpha.h> #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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef __DEFAULTS_H #define __DEFAULTS_H #include <glib-object.h> #include <gio/gio.h> #include <gdk/gdk.h> 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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef _BUBBLE_WINDOW_ACCESSIBLE_FACTORY_H_ #define _BUBBLE_WINDOW_ACCESSIBLE_FACTORY_H_ #include <atk/atkobjectfactory.h> 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 <mirco.mueller@canonical.com> ** David Barth <david.barth@canonical.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef __NOTIFY_OSD_DBUS_H #define __NOTIFY_OSD_DBUS_H #include <dbus/dbus.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> #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 <b>bold</b>, <u>underlined</u>, <i>italic</i> 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" "<a href=\"http://www.ubuntu.com/\">Ubuntu</a> 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 > <i>Not italic</i>" sleep 2 notify-send "Filter the world 3/3" "<b>So broken</i> <img src=\"foobar.png\" />Nothing to see <u>Test</u> <b>Bold</b> <span>Span</span> <s>E-flat</s> <sub>Sandwich</sub> <small>Fry</small> <tt>Testing tag</tt>" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef _BUBBLE_WINDOW_H_ #define _BUBBLE_WINDOW_H_ #include <glib-object.h> //#include <gtk/gtkwindow.h> #include <gtk/gtk.h> 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 <eitan@ascender.com> ** ** 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 <http://www.gnu.org/licenses/>. ** *******************************************************************************/ #ifndef _BUBBLE_WINDOW_ACCESSIBLE_H_ #define _BUBBLE_WINDOW_ACCESSIBLE_H_ #include <gtk/gtk.h> #include <atk/atk.h> #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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #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 <mirco.mueller@canonical.com> // David Barth <david.barth@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include "dialog.h" #include <gtk/gtk.h> #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... <sigh> 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 <mirco.mueller@canonical.com> // // 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 <http://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////////////// #include "notification.h" G_DEFINE_TYPE (Notification, notification, G_TYPE_OBJECT); enum { PROP_DUMMY = 0, PROP_ID, PROP_TITLE, PROP_BODY, PROP_VALUE, PROP_ICON_THEMENAME, PROP_ICON_FILENAME, PROP_ICON_PIXBUF, PROP_ONSCREEN_TIME, PROP_SENDER_NAME, PROP_SENDER_PID, PROP_TIMESTAMP, PROP_URGENCY }; #define GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), NOTIFICATION_TYPE, NotificationPrivate)) struct _NotificationPrivate { gint id; // unique notification-id GString* title; // summary-text strdup'ed from setter GString* body; // body-text strdup'ed from setter gint value; // range: 0..100, special: -1, 101 GString* icon_themename; // e.g. "notification-message-email" GString* icon_filename; // e.g. "/usr/share/icons/icon.png" GdkPixbuf* icon_pixbuf; // from setter memcpy'ed pixbuf gint onscreen_time; // time on-screen in ms GString* sender_name; // app-name, strdup'ed from setter gint sender_pid; // pid of sending application GTimeVal timestamp; // timestamp of reception Urgency urgency; // urgency-level: low, normal, high }; #define RETURN_GCHAR(n, string)\ NotificationPrivate* priv;\ g_return_val_if_fail (IS_NOTIFICATION (n), NULL);\ priv = GET_PRIVATE (n);\ if (!priv->string)\ return NULL;\ return GET_PRIVATE (n)->string->str; #define SET_GCHAR(n, string)\ NotificationPrivate* priv;\ g_assert (IS_NOTIFICATION (n));\ if (!string)\ return;\ priv = GET_PRIVATE (n);\ if (priv->string)\ {\ g_string_free (priv->string, TRUE);\ priv->string = NULL;\ }\ priv->string = g_string_new (string); //-- private functions --------------------------------------------------------- //-- internal functions -------------------------------------------------------- // this is what gets called if one does g_object_unref(bla) static void notification_dispose (GObject* gobject) { Notification* n; NotificationPrivate* priv; // sanity checks g_assert (gobject); n = NOTIFICATION (gobject); g_assert (n); g_assert (IS_NOTIFICATION (n)); priv = GET_PRIVATE (n); g_assert (priv); // free any allocated resources if (priv->title) { g_string_free (priv->title, TRUE); priv->title = NULL; } if (priv->body) { g_string_free (priv->body, TRUE); priv->body = NULL; } if (priv->icon_themename) { g_string_free (priv->icon_themename, TRUE); priv->icon_themename = NULL; } if (priv->icon_filename) { g_string_free (priv->icon_filename, TRUE); priv->icon_filename = NULL; } if (priv->icon_pixbuf) { g_object_unref (priv->icon_pixbuf); } if (priv->sender_name) { g_string_free (priv->sender_name, TRUE); priv->sender_name = NULL; } // chain up to the parent class G_OBJECT_CLASS (notification_parent_class)->dispose (gobject); } static void notification_finalize (GObject* gobject) { // chain up to the parent class G_OBJECT_CLASS (notification_parent_class)->finalize (gobject); } static void notification_init (Notification* n) { // nothing to be done here for now } static void notification_get_property (GObject* gobject, guint prop, GValue* value, GParamSpec* spec) { Notification* n = NOTIFICATION (gobject); // sanity checks are done in public getters switch (prop) { case PROP_ID: g_value_set_int (value, notification_get_id (n)); break; case PROP_TITLE: g_value_set_string (value, notification_get_title (n)); break; case PROP_BODY: g_value_set_string (value, notification_get_body (n)); break; case PROP_VALUE: g_value_set_int (value, notification_get_value (n)); break; case PROP_ICON_THEMENAME: g_value_set_string (value, notification_get_icon_themename (n)); break; case PROP_ICON_FILENAME: g_value_set_string (value, notification_get_icon_filename (n)); break; case PROP_ICON_PIXBUF: g_value_set_pointer (value, notification_get_icon_pixbuf (n)); break; case PROP_ONSCREEN_TIME: g_value_set_int (value, notification_get_onscreen_time (n)); break; case PROP_SENDER_NAME: g_value_set_string (value, notification_get_sender_name (n)); break; case PROP_SENDER_PID: g_value_set_int (value, notification_get_sender_pid (n)); break; case PROP_TIMESTAMP: g_value_set_pointer (value, notification_get_timestamp (n)); break; case PROP_URGENCY: g_value_set_int (value, notification_get_urgency (n)); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec); break; } } static void notification_set_property (GObject* gobject, guint prop, const GValue* value, GParamSpec* spec) { Notification* n = NOTIFICATION (gobject); // sanity checks are done in the public setters switch (prop) { case PROP_ID: notification_set_id (n, g_value_get_int (value)); break; case PROP_TITLE: notification_set_title (n, g_value_get_string (value)); break; case PROP_BODY: notification_set_body (n, g_value_get_string (value)); break; case PROP_VALUE: notification_set_value (n, g_value_get_int (value)); break; case PROP_ICON_THEMENAME: notification_set_icon_themename ( n, g_value_get_string (value)); break; case PROP_ICON_FILENAME: notification_set_icon_filename ( n, g_value_get_string (value)); break; case PROP_ICON_PIXBUF: notification_set_icon_pixbuf ( n, g_value_get_pointer (value)); break; case PROP_ONSCREEN_TIME: notification_set_onscreen_time ( n, g_value_get_int (value)); break; case PROP_SENDER_NAME: notification_set_sender_name ( n, g_value_get_string (value)); break; case PROP_SENDER_PID: notification_set_sender_pid ( n, g_value_get_int (value)); break; case PROP_TIMESTAMP: notification_set_timestamp ( n, g_value_get_pointer (value)); break; case PROP_URGENCY: notification_set_urgency ( n, g_value_get_int (value)); break; default : G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop, spec); break; } } static void notification_class_init (NotificationClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS (klass); GParamSpec* property_id; GParamSpec* property_title; GParamSpec* property_body; GParamSpec* property_value; GParamSpec* property_icon_themename; GParamSpec* property_icon_filename; GParamSpec* property_icon_pixbuf; GParamSpec* property_onscreen_time; GParamSpec* property_sender_name; GParamSpec* property_sender_pid; GParamSpec* property_timestamp; GParamSpec* property_urgency; g_type_class_add_private (klass, sizeof (NotificationPrivate)); gobject_class->dispose = notification_dispose; gobject_class->finalize = notification_finalize; gobject_class->get_property = notification_get_property; gobject_class->set_property = notification_set_property; property_id = g_param_spec_int ("id", "id", "unique notification id", -1, G_MAXINT, -1, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ID, property_id); property_title = g_param_spec_string ("title", "title", "title-text of a notification", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_TITLE, property_title); property_body = g_param_spec_string ("body", "body", "body-text of a notification", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_BODY, property_body); property_value = g_param_spec_int ("value", "value", "value between -1..101 to render", -2, 101, -2, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_VALUE, property_value); property_icon_themename = g_param_spec_string ( "icon-themename", "icon-themename", "theme-name of icon to use", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ICON_THEMENAME, property_icon_themename); property_icon_filename = g_param_spec_string ( "icon-filename", "icon-filename", "file-name of icon to use", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ICON_FILENAME, property_icon_filename); property_icon_pixbuf = g_param_spec_pointer ("icon-pixbuf", "icon-pixbuf", "pixbuf of icon to use", G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ICON_PIXBUF, property_icon_pixbuf); property_onscreen_time = g_param_spec_int ("onscreen-time", "onscreen-time", "time on screen sofar", 0, G_MAXINT, 0, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_ONSCREEN_TIME, property_onscreen_time); property_sender_name = g_param_spec_string ( "sender-name", "sender-name", "name of sending application", NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_SENDER_NAME, property_sender_name); property_sender_pid = g_param_spec_int ( "sender-pid", "sender-pid", "process ID of sending application", 0, G_MAXSHORT, 0, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_SENDER_PID, property_sender_pid); property_timestamp = g_param_spec_pointer ("timestamp", "timestamp", "timestamp of reception", G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_TIMESTAMP, property_timestamp); property_urgency = g_param_spec_int ("urgency", "urgency", "urgency-level of notification", URGENCY_LOW, URGENCY_NONE, URGENCY_NONE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_URGENCY, property_urgency); } //-- public functions ---------------------------------------------------------- Notification* notification_new () { const GTimeVal timestamp = {0}; return g_object_new (NOTIFICATION_TYPE, "timestamp", ×tamp, NULL); } gint notification_get_id (Notification* n) { g_return_val_if_fail (IS_NOTIFICATION (n), -1); return GET_PRIVATE (n)->id; } // -1 is meant to "unset" the id, 0 is the smallest possible PID, but very // unlikely to ever be passed around void notification_set_id (Notification* n, gint id) { g_assert (IS_NOTIFICATION (n)); // IDs can't be negative, except for -1 to indicate it's "unset" if (id < -1) return; GET_PRIVATE (n)->id = id; } gchar* notification_get_title (Notification* n) { RETURN_GCHAR (n, title) } void notification_set_title (Notification* n, const gchar* title) { SET_GCHAR (n, title) } gchar* notification_get_body (Notification* n) { RETURN_GCHAR (n, body) } void notification_set_body (Notification* n, const gchar* body) { SET_GCHAR (n, body) } // the allowed range for stored values is -1..101, thus a return-value of -2 // indicates an error on behalf of the caller gint notification_get_value (Notification* n) { g_return_val_if_fail (IS_NOTIFICATION (n), -2); return GET_PRIVATE (n)->value; } // valid range is -1..101, -2 is used to indicate it's "unset" void notification_set_value (Notification* n, gint value) { NotificationPrivate* priv; g_assert (IS_NOTIFICATION (n)); priv = GET_PRIVATE (n); // this is used to indicate the "unset" state if (value == -2) { priv->value = value; return; } // don't store any values outside of allowed range -1..101 if (value <= NOTIFICATION_VALUE_MIN_ALLOWED) { priv->value = NOTIFICATION_VALUE_MIN_ALLOWED; return; } if (value >= NOTIFICATION_VALUE_MAX_ALLOWED) { priv->value = NOTIFICATION_VALUE_MAX_ALLOWED; return; } priv->value = value; } gchar* notification_get_icon_themename (Notification* n) { RETURN_GCHAR (n, icon_themename) } void notification_set_icon_themename (Notification* n, const gchar* icon_themename) { SET_GCHAR (n, icon_themename) } gchar* notification_get_icon_filename (Notification* n) { RETURN_GCHAR (n, icon_filename) } void notification_set_icon_filename (Notification* n, const gchar* icon_filename) { SET_GCHAR (n, icon_filename) } GdkPixbuf* notification_get_icon_pixbuf (Notification* n) { NotificationPrivate* priv; g_return_val_if_fail (IS_NOTIFICATION (n), NULL); priv = GET_PRIVATE (n); if (!priv->icon_pixbuf) return NULL; return GET_PRIVATE (n)->icon_pixbuf; } void notification_set_icon_pixbuf (Notification* n, const GdkPixbuf* icon_pixbuf) { NotificationPrivate* priv; // sanity checks g_assert (IS_NOTIFICATION (n)); if (!icon_pixbuf) return; priv = GET_PRIVATE (n); // free any previous stored pixbuf if (priv->icon_pixbuf) { g_object_unref (priv->icon_pixbuf); priv->icon_pixbuf = NULL; } // create a new/private copy of the supplied pixbuf priv->icon_pixbuf = gdk_pixbuf_copy (icon_pixbuf); } // a return-value of -1 indicates an error on behalf of the caller, a // return-value of 0 would indicate that a notification has not been displayed // yet gint notification_get_onscreen_time (Notification* n) { g_return_val_if_fail (IS_NOTIFICATION (n), -1); return GET_PRIVATE (n)->onscreen_time; } // only onscreen_time values <= 0 are considered valid void notification_set_onscreen_time (Notification* n, gint onscreen_time) { NotificationPrivate* priv; g_assert (IS_NOTIFICATION (n)); priv = GET_PRIVATE (n); // avoid storing negative values if (onscreen_time < 0) return; // onscreen-time can only increase not decrease if (priv->onscreen_time > onscreen_time) return; // you made it upto here, congratulations... let's store the new value priv->onscreen_time = onscreen_time; } gchar* notification_get_sender_name (Notification* n) { RETURN_GCHAR (n, sender_name) } void notification_set_sender_name (Notification* n, const gchar* sender_name) { SET_GCHAR (n, sender_name) } // a return-value of 0 indicates an error on behalf of the caller, PIDs are // never negative gint notification_get_sender_pid (Notification* n) { g_return_val_if_fail (IS_NOTIFICATION (n), 0); return GET_PRIVATE (n)->sender_pid; } void notification_set_sender_pid (Notification* n, const gint sender_pid) { g_assert (IS_NOTIFICATION (n)); // it's hardly possible we'll get a notification from init, but anyway if (sender_pid <= 0) return; GET_PRIVATE (n)->sender_pid = sender_pid; } GTimeVal* notification_get_timestamp (Notification* n) { NotificationPrivate* priv; g_return_val_if_fail (IS_NOTIFICATION (n), NULL); priv = GET_PRIVATE (n); return &priv->timestamp; } void notification_set_timestamp (Notification* n, const GTimeVal* timestamp) { NotificationPrivate* priv; // sanity checks g_assert (IS_NOTIFICATION (n)); if (!timestamp) return; priv = GET_PRIVATE (n); // don't store older timestamp over newer one if (priv->timestamp.tv_sec > timestamp->tv_sec) return; if (priv->timestamp.tv_sec == timestamp->tv_sec) if (priv->timestamp.tv_usec > timestamp->tv_usec) return; // new timestamp certainly more current that stored one priv->timestamp.tv_sec = timestamp->tv_sec; priv->timestamp.tv_usec = timestamp->tv_usec; } gint notification_get_urgency (Notification* n) { g_return_val_if_fail (IS_NOTIFICATION (n), URGENCY_NONE); return GET_PRIVATE (n)->urgency; } void notification_set_urgency (Notification* n, Urgency urgency) { NotificationPrivate* priv; g_assert (IS_NOTIFICATION (n)); priv = GET_PRIVATE (n); // URGENCY_NONE is meant to indicate the "unset" state if (urgency == URGENCY_NONE) { priv->urgency = URGENCY_NONE; return; } // don't store any values outside of allowed range LOW..HIGH if (urgency != URGENCY_LOW && urgency != URGENCY_NORMAL && urgency != URGENCY_HIGH) return; GET_PRIVATE (n)->urgency = urgency; } ���������������������������./README��������������������������������������������������������������������������������������������0000644�0000156�0000165�00000001004�12704153542�011753� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������The Desktop Notifications framework provides a standard way of doing passive pop-up notifications on the Linux desktop. These are designed to notify the user of something without interrupting their work with a dialog box that they must close. Passive popups can automatically disappear after a short period of time. The project homepage is located here: https://edge.launchpad.net/notify-osd This version of Notify OSD implements the specification defined here: https://wiki.ubuntu.com/NotifyOSD?rev=143 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./Makefile.am���������������������������������������������������������������������������������������0000644�0000156�0000165�00000000255�12704153542�013136� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������EXTRA_DIST = icons SUBDIRS = src tests data examples test: check tests: check test-report: check check-valgrind: all cd tests && $(MAKE) $(AM_MAKEFLAGS) check-valgrind ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/����������������������������������������������������������������������������������������������0000755�0000156�0000165�00000000000�12704153542�011642� 5����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-debug.h�����������������������������������������������������������������������������������0000644�0000156�0000165�00000006173�12704153542�013650� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __EGG_DEBUG_H__ #define __EGG_DEBUG_H__ #include <glib.h> #include "egg-hack.h" G_BEGIN_DECLS typedef enum { EGG_DEBUG_MISC = 1 << 0, EGG_DEBUG_ACTOR = 1 << 1, EGG_DEBUG_TEXTURE = 1 << 2, EGG_DEBUG_EVENT = 1 << 3, EGG_DEBUG_PAINT = 1 << 4, EGG_DEBUG_GL = 1 << 5, EGG_DEBUG_ALPHA = 1 << 6, EGG_DEBUG_BEHAVIOUR = 1 << 7, EGG_DEBUG_PANGO = 1 << 8, EGG_DEBUG_BACKEND = 1 << 9, EGG_DEBUG_SCHEDULER = 1 << 10, EGG_DEBUG_SCRIPT = 1 << 11, EGG_DEBUG_SHADER = 1 << 12, EGG_DEBUG_MULTISTAGE = 1 << 13 } EggDebugFlag; #ifdef EGG_ENABLE_DEBUG #ifdef __GNUC_ #define EGG_NOTE(type,x,a...) G_STMT_START { \ if (egg_debug_flags & EGG_DEBUG_##type) \ { g_message ("[" #type "] " G_STRLOC ": " x, ##a); } \ } G_STMT_END #define EGG_TIMESTAMP(type,x,a...) G_STMT_START { \ if (egg_debug_flags & EGG_DEBUG_##type) \ { g_message ("[" #type "]" " %li:" G_STRLOC ": " \ x, egg_get_timestamp(), ##a); } \ } G_STMT_END #else /* Try the C99 version; unfortunately, this does not allow us to pass * empty arguments to the macro, which means we have to * do an intemediate printf. */ #define EGG_NOTE(type,...) G_STMT_START { \ if (egg_debug_flags & EGG_DEBUG_##type) \ { \ gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ g_message ("[" #type "] " G_STRLOC ": %s",_fmt); \ g_free (_fmt); \ } \ } G_STMT_END #define EGG_TIMESTAMP(type,...) G_STMT_START { \ if (egg_debug_flags & EGG_DEBUG_##type) \ { \ gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ g_message ("[" #type "]" " %li:" G_STRLOC ": %s", \ egg_get_timestamp(), _fmt); \ g_free (_fmt); \ } \ } G_STMT_END #endif #define EGG_MARK() EGG_NOTE(MISC, "== mark ==") #define EGG_DBG(x) { a } #define EGG_GLERR() G_STMT_START { \ if (egg_debug_flags & EGG_DEBUG_GL) \ { GLenum _err = glGetError (); /* roundtrip */ \ if (_err != GL_NO_ERROR) \ g_warning (G_STRLOC ": GL Error %x", _err); \ } } G_STMT_END #else /* !EGG_ENABLE_DEBUG */ #define EGG_NOTE(type,...) #define EGG_MARK() #define EGG_DBG(x) #define EGG_GLERR() #define EGG_TIMESTAMP(type,...) #endif /* EGG_ENABLE_DEBUG */ extern guint egg_debug_flags; G_END_DECLS #endif /* __EGG_DEBUG_H__ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/test-timeline.c�������������������������������������������������������������������������������0000644�0000156�0000165�00000007476�12704153542�014607� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include <string.h> #include <egg/egg-hack.h> static void timeline_1_complete (EggTimeline *timeline) { g_debug ("1: Completed"); } static void timeline_2_complete (EggTimeline *timeline) { g_debug ("2: Completed"); } static void timeline_3_complete (EggTimeline *timeline) { g_debug ("3: Completed"); } static void timeline_1_new_frame_cb (EggTimeline *timeline, gint frame_no) { g_debug ("1: Doing frame %d.", frame_no); } static void timeline_2_new_frame_cb (EggTimeline *timeline, gint frame_no) { g_debug ("2: Doing frame %d.", frame_no); } static void timeline_3_new_frame_cb (EggTimeline *timeline, gint frame_no) { g_debug ("3: Doing frame %d.", frame_no); } static void timeline_1_marker_reached (EggTimeline *timeline, const gchar *marker_name, guint frame_num) { g_print ("1: Marker `%s' (%d) reached\n", marker_name, frame_num); } static void timeline_2_marker_reached (EggTimeline *timeline, const gchar *marker_name, guint frame_num) { g_print ("2: Marker `%s' (%d) reached\n", marker_name, frame_num); } static void timeline_3_marker_reached (EggTimeline *timeline, const gchar *marker_name, guint frame_num) { g_print ("3: Marker `%s' (%d) reached\n", marker_name, frame_num); } int main (int argc, char **argv) { EggTimeline *timeline_1; EggTimeline *timeline_2; EggTimeline *timeline_3; gchar **markers; gsize n_markers; timeline_1 = egg_timeline_new (10, 120); egg_timeline_add_marker_at_frame (timeline_1, "foo", 5); egg_timeline_add_marker_at_frame (timeline_1, "bar", 5); egg_timeline_add_marker_at_frame (timeline_1, "baz", 5); markers = egg_timeline_list_markers (timeline_1, 5, &n_markers); g_assert (markers != NULL); g_assert (n_markers == 3); g_strfreev (markers); timeline_2 = egg_timeline_clone (timeline_1); egg_timeline_add_marker_at_frame (timeline_2, "bar", 2); markers = egg_timeline_list_markers (timeline_2, -1, &n_markers); g_assert (markers != NULL); g_assert (n_markers == 1); g_assert (strcmp (markers[0], "bar") == 0); g_strfreev (markers); timeline_3 = egg_timeline_clone (timeline_1); egg_timeline_set_direction (timeline_3, EGG_TIMELINE_BACKWARD); egg_timeline_add_marker_at_frame (timeline_3, "baz", 8); g_signal_connect (timeline_1, "marker-reached", G_CALLBACK (timeline_1_marker_reached), NULL); g_signal_connect (timeline_1, "new-frame", G_CALLBACK (timeline_1_new_frame_cb), NULL); g_signal_connect (timeline_1, "completed", G_CALLBACK (timeline_1_complete), NULL); g_signal_connect (timeline_2, "marker-reached::bar", G_CALLBACK (timeline_2_marker_reached), NULL); g_signal_connect (timeline_2, "new-frame", G_CALLBACK (timeline_2_new_frame_cb), NULL); g_signal_connect (timeline_2, "completed", G_CALLBACK (timeline_2_complete), NULL); g_signal_connect (timeline_3, "marker-reached", G_CALLBACK (timeline_3_marker_reached), NULL); g_signal_connect (timeline_3, "new-frame", G_CALLBACK (timeline_3_new_frame_cb), NULL); g_signal_connect (timeline_3, "completed", G_CALLBACK (timeline_3_complete), NULL); egg_timeline_start (timeline_1); egg_timeline_start (timeline_2); egg_timeline_start (timeline_3); egg_main (); g_object_unref (timeline_1); g_object_unref (timeline_2); g_object_unref (timeline_3); return EXIT_SUCCESS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-units.c�����������������������������������������������������������������������������������0000644�0000156�0000165�00000022201�12704153542�013705� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By: Tomas Frydrych <tf@openedhand.com> * Emmanuele Bassi <ebassi@openedhand.com> * * Copyright (C) 2007 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:egg-units * @short_description: A logical distance unit. * * Egg units are logical units with granularity greater than that of the * device units; they are used by #EggActorBox and the units-based family * of #EggActor functions. To convert between Egg units and device * units, use %EGG_UNITS_FROM_DEVICE and %EGG_UNITS_TO_DEVICE macros. * * #EggUnit<!-- -->s can be converted from other units like millimeters, * typographic points (at the current resolution) and percentages. It is * also possible to convert fixed point values to and from #EggUnit * values. * * In order to register a #EggUnit property, the #EggParamSpecUnit * #GParamSpec sub-class should be used: * * |[ * GParamSpec *pspec; * * pspec = egg_param_spec_unit ("width", * "Width", * "Width of the actor, in units", * 0, EGG_MAXUNIT, * 0, * G_PARAM_READWRITE); * g_object_class_install_property (gobject_class, PROP_WIDTH, pspec); * ]| * * A #GValue holding units can be manipulated using egg_value_set_unit() * and egg_value_get_unit(). #GValue<!-- -->s containing a #EggUnit * value can also be transformed to #GValue<!-- -->s containing integer * values - with a loss of precision: * * |[ * static gboolean * units_to_int (const GValue *src, * GValue *dest) * { * g_return_val_if_fail (EGG_VALUE_HOLDS_UNIT (src), FALSE); * * g_value_init (dest, G_TYPE_INT); * return g_value_transform (src, &dest); * } * ]| * * The code above is equivalent to: * * |[ * static gboolean * units_to_int (const GValue *src, * GValue *dest) * { * g_return_val_if_fail (EGG_VALUE_HOLDS_UNIT (src), FALSE); * * g_value_init (dest, G_TYPE_INT); * g_value_set_int (dest, * EGG_UNITS_TO_INT (egg_value_get_unit (src))); * * return TRUE; * } * ]| * * #EggUnit is available since Egg 0.4 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <glib-object.h> #include <gobject/gvaluecollector.h> #include "egg-units.h" // #include "egg-private.h" #include "egg-hack.h" static GTypeInfo _info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo _finfo = { 0, }; static void egg_value_init_unit (GValue *value) { value->data[0].v_int = 0; } static void egg_value_copy_unit (const GValue *src, GValue *dest) { dest->data[0].v_int = src->data[0].v_int; } static gchar * egg_value_collect_unit (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { value->data[0].v_int = collect_values[0].v_int; return NULL; } static gchar * egg_value_lcopy_unit (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint32 *units_p = collect_values[0].v_pointer; if (!units_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *units_p = value->data[0].v_int; return NULL; } static void egg_value_transform_unit_int (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_UNITS_TO_INT (src->data[0].v_int); } static void egg_value_transform_int_unit (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_UNITS_FROM_INT (src->data[0].v_int); } static const GTypeValueTable _egg_unit_value_table = { egg_value_init_unit, NULL, egg_value_copy_unit, NULL, "i", egg_value_collect_unit, "p", egg_value_lcopy_unit }; GType egg_unit_get_type (void) { static GType _egg_unit_type = 0; if (G_UNLIKELY (_egg_unit_type == 0)) { _info.value_table = & _egg_unit_value_table; _egg_unit_type = g_type_register_fundamental (g_type_fundamental_next (), I_("EggUnit"), &_info, &_finfo, 0); g_value_register_transform_func (_egg_unit_type, G_TYPE_INT, egg_value_transform_unit_int); g_value_register_transform_func (G_TYPE_INT, _egg_unit_type, egg_value_transform_int_unit); } return _egg_unit_type; } /** * egg_value_set_unit: * @value: a #GValue initialized to #EGG_TYPE_UNIT * @units: the units to set * * Sets @value to @units * * Since: 0.8 */ void egg_value_set_unit (GValue *value, EggUnit units) { g_return_if_fail (EGG_VALUE_HOLDS_UNIT (value)); value->data[0].v_int = units; } /** * egg_value_get_unit: * @value: a #GValue initialized to #EGG_TYPE_UNIT * * Gets the #EggUnit<!-- -->s contained in @value. * * Return value: the units inside the passed #GValue * * Since: 0.8 */ EggUnit egg_value_get_unit (const GValue *value) { g_return_val_if_fail (EGG_VALUE_HOLDS_UNIT (value), 0); return value->data[0].v_int; } static void param_unit_init (GParamSpec *pspec) { EggParamSpecUnit *uspec = EGG_PARAM_SPEC_UNIT (pspec); uspec->minimum = EGG_MINUNIT; uspec->maximum = EGG_MAXUNIT; uspec->default_value = 0; } static void param_unit_set_default (GParamSpec *pspec, GValue *value) { value->data[0].v_int = EGG_PARAM_SPEC_UNIT (pspec)->default_value; } static gboolean param_unit_validate (GParamSpec *pspec, GValue *value) { EggParamSpecUnit *uspec = EGG_PARAM_SPEC_UNIT (pspec); gint oval = EGG_UNITS_TO_INT (value->data[0].v_int); gint min, max, val; g_assert (EGG_IS_PARAM_SPEC_UNIT (pspec)); /* we compare the integer part of the value because the minimum * and maximum values cover just that part of the representation */ min = uspec->minimum; max = uspec->maximum; val = EGG_UNITS_TO_INT (value->data[0].v_int); val = CLAMP (val, min, max); if (val != oval) { value->data[0].v_int = val; return TRUE; } return FALSE; } static gint param_unit_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { if (value1->data[0].v_int < value2->data[0].v_int) return -1; else return value1->data[0].v_int > value2->data[0].v_int; } GType egg_param_unit_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { sizeof (EggParamSpecUnit), 16, param_unit_init, EGG_TYPE_UNIT, NULL, param_unit_set_default, param_unit_validate, param_unit_values_cmp, }; pspec_type = g_param_type_register_static (I_("EggParamSpecUnit"), &pspec_info); } return pspec_type; } /** * egg_param_spec_unit: * @name: name of the property * @nick: short name * @blurb: description (can be translatable) * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * * Creates a #GParamSpec for properties using #EggUnit<!-- -->s. * * Return value: the newly created #GParamSpec * * Since: 0.8 */ GParamSpec * egg_param_spec_unit (const gchar *name, const gchar *nick, const gchar *blurb, EggUnit minimum, EggUnit maximum, EggUnit default_value, GParamFlags flags) { EggParamSpecUnit *uspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); uspec = g_param_spec_internal (EGG_TYPE_PARAM_UNIT, name, nick, blurb, flags); uspec->minimum = minimum; uspec->maximum = maximum; uspec->default_value = default_value; return G_PARAM_SPEC (uspec); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/test-timeline-dup-frames.c��������������������������������������������������������������������0000644�0000156�0000165�00000004106�12704153542�016633� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <egg/egg-hack.h> /* We use a nice slow timeline for this test since we * dont want the timeouts to interpolate the timeline * forward multiple frames */ #define TEST_TIMELINE_FPS 10 #define TEST_TIMELINE_FRAME_COUNT 20 typedef struct _TestState { EggTimeline *timeline; gint prev_frame; gint completion_count; gint passed; }TestState; static void new_frame_cb (EggTimeline *timeline, gint frame_num, TestState *state) { gint current_frame = egg_timeline_get_current_frame (state->timeline); if (state->prev_frame != egg_timeline_get_current_frame (state->timeline)) { g_print("timeline previous frame=%-4i actual frame=%-4i (OK)\n", state->prev_frame, current_frame); } else { g_print("timeline previous frame=%-4i actual frame=%-4i (FAILED)\n", state->prev_frame, current_frame); state->passed = FALSE; } state->prev_frame = current_frame; } static void completed_cb (EggTimeline *timeline, TestState *state) { state->completion_count++; if (state->completion_count == 2) { if (state->passed) { g_print("Passed\n"); exit(EXIT_SUCCESS); } else { g_print("Failed\n"); exit(EXIT_FAILURE); } } } int main(int argc, char **argv) { TestState state; state.timeline = egg_timeline_new (TEST_TIMELINE_FRAME_COUNT, TEST_TIMELINE_FPS); egg_timeline_set_loop (state.timeline, TRUE); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_signal_connect (G_OBJECT(state.timeline), "completed", G_CALLBACK(completed_cb), &state); state.prev_frame = -1; state.completion_count = 0; state.passed = TRUE; egg_timeline_start (state.timeline); egg_main(); return EXIT_FAILURE; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/test-timeline-rewind.c������������������������������������������������������������������������0000644�0000156�0000165�00000004045�12704153542�016062� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <egg/egg-hack.h> #define TEST_TIMELINE_FPS 10 #define TEST_TIMELINE_FRAME_COUNT 5 #define TEST_WATCHDOG_KICK_IN_SECONDS 10 typedef struct _TestState { EggTimeline *timeline; gint rewind_count; }TestState; static gboolean watchdog_timeout (TestState *state) { g_print ("Watchdog timer kicking in\n"); g_print ("rewind_count=%i\n", state->rewind_count); if (state->rewind_count <= 3) { /* The test has hung */ g_print ("Failed (This test shouldn't have hung!)\n"); exit (EXIT_FAILURE); } else { g_print ("Passed\n"); exit (EXIT_SUCCESS); } return FALSE; } static void new_frame_cb (EggTimeline *timeline, gint frame_num, TestState *state) { gint current_frame = egg_timeline_get_current_frame (timeline); if (current_frame == TEST_TIMELINE_FRAME_COUNT) { g_print ("new-frame signal recieved (end of timeline)\n"); g_print ("Rewinding timeline\n"); egg_timeline_rewind (timeline); state->rewind_count++; } else { if (current_frame == 0) { g_print ("new-frame signal recieved (start of timeline)\n"); } else { g_print ("new-frame signal recieved (mid frame)\n"); } if (state->rewind_count >= 2) { g_print ("Sleeping for 1 second\n"); g_usleep (1000000); } } } int main (int argc, char **argv) { TestState state; state.timeline = egg_timeline_new (TEST_TIMELINE_FRAME_COUNT, TEST_TIMELINE_FPS); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_print ("Installing a watchdog timeout to determin if this test hangs\n"); g_timeout_add (TEST_WATCHDOG_KICK_IN_SECONDS*1000, (GSourceFunc)watchdog_timeout, &state); state.rewind_count = 0; egg_timeline_start (state.timeline); egg_main(); return EXIT_FAILURE; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-hack.c������������������������������������������������������������������������������������0000644�0000156�0000165�00000015041�12704153542�013455� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdlib.h> #include <glib.h> #include <locale.h> #include "egg-hack.h" static guint egg_default_fps = 60; guint egg_get_default_frame_rate (void) { return egg_default_fps; } guint egg_debug_flags = 0; /* global egg debug flag */ #ifdef EGG_ENABLE_DEBUG static const GDebugKey egg_debug_keys[] = { { "misc", EGG_DEBUG_MISC }, { "actor", EGG_DEBUG_ACTOR }, { "texture", EGG_DEBUG_TEXTURE }, { "event", EGG_DEBUG_EVENT }, { "paint", EGG_DEBUG_PAINT }, { "gl", EGG_DEBUG_GL }, { "alpha", EGG_DEBUG_ALPHA }, { "behaviour", EGG_DEBUG_BEHAVIOUR }, { "pango", EGG_DEBUG_PANGO }, { "backend", EGG_DEBUG_BACKEND }, { "scheduler", EGG_DEBUG_SCHEDULER }, { "script", EGG_DEBUG_SCRIPT }, { "shader", EGG_DEBUG_SHADER }, { "multistage", EGG_DEBUG_MULTISTAGE }, }; #endif /* EGG_ENABLE_DEBUG */ gboolean egg_get_debug_enabled (void) { #ifdef EGG_ENABLE_DEBUG return egg_debug_flags != 0; #else return FALSE; #endif } void egg_threads_enter (void) { return; } void egg_threads_leave (void) { return; } static guint egg_main_loop_level = 0; static GSList *main_loops = NULL; /** * egg_main: * * Starts the Egg mainloop. */ void egg_main (void) { GMainLoop *loop; #if 0 /* Make sure there is a context */ EGG_CONTEXT (); #endif EGG_MARK (); egg_main_loop_level++; loop = g_main_loop_new (NULL, TRUE); main_loops = g_slist_prepend (main_loops, loop); #ifdef HAVE_EGG_FRUITY /* egg fruity creates an application that forwards events and manually * spins the mainloop */ egg_fruity_main (); #else if (g_main_loop_is_running (main_loops->data)) { egg_threads_leave (); g_main_loop_run (loop); egg_threads_enter (); } #endif main_loops = g_slist_remove (main_loops, loop); g_main_loop_unref (loop); egg_main_loop_level--; EGG_MARK (); } /* -------------------------------------------------------------------------- */ /* auto-generated code taken from egg-enum-types.c */ /* enumerations from "./egg-timeline.h" */ #include "./egg-timeline.h" GType egg_timeline_direction_get_type(void) { static GType etype = 0; if (G_UNLIKELY (!etype)) { static const GEnumValue values[] = { { EGG_TIMELINE_FORWARD, "EGG_TIMELINE_FORWARD", "forward" }, { EGG_TIMELINE_BACKWARD, "EGG_TIMELINE_BACKWARD", "backward" }, { 0, NULL, NULL } }; etype = g_enum_register_static (g_intern_static_string ("EggTimelineDirection"), values); } return etype; } /* auto-generated code taken from egg-marshal.c */ #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_int(v) (v)->data[0].v_int /* VOID:STRING,INT (./egg-marshal.list:12) */ void egg_marshal_VOID__STRING_INT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1, gpointer arg_1, gint arg_2, gpointer data2); register GMarshalFunc_VOID__STRING_INT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_string (param_values + 1), g_marshal_value_peek_int (param_values + 2), data2); } /* VOID:INT,INT (./egg-marshal.list:6) */ void egg_marshal_VOID__INT_INT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer data1, gint arg_1, gint arg_2, gpointer data2); register GMarshalFunc_VOID__INT_INT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_int (param_values + 2), data2); } /* UINT:VOID (./egg-marshal.list:2) */ void egg_marshal_UINT__VOID (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef guint (*GMarshalFunc_UINT__VOID) (gpointer data1, gpointer data2); register GMarshalFunc_UINT__VOID callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; guint v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 1); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_UINT__VOID) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, data2); g_value_set_uint (return_value, v_return); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-units.h�����������������������������������������������������������������������������������0000644�0000156�0000165�00000013361�12704153542�013721� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych <tf@openedhand.com> * * Copyright (C) 2007 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _HAVE_EGG_UNITS_H #define _HAVE_EGG_UNITS_H #include <glib-object.h> #include <egg/egg-fixed.h> G_BEGIN_DECLS /** * EggUnit: * * Device independent unit used by Egg. The value held can be transformed * into other units, likes pixels. * * Since: 0.4 */ typedef gint32 EggUnit; /* * Currently EGG_UNIT maps directly onto EggFixed. Nevertheless, the * _FROM_FIXED and _TO_FIXED macros should always be used in case that we * decide to change this relationship in the future. */ #define EGG_UNITS_FROM_INT(x) EGG_INT_TO_FIXED ((x)) #define EGG_UNITS_TO_INT(x) EGG_FIXED_TO_INT ((x)) #define EGG_UNITS_FROM_FLOAT(x) EGG_FLOAT_TO_FIXED ((x)) #define EGG_UNITS_TO_FLOAT(x) EGG_FIXED_TO_FLOAT ((x)) #define EGG_UNITS_FROM_FIXED(x) (x) #define EGG_UNITS_TO_FIXED(x) (x) /** * EGG_UNITS_FROM_DEVICE: * @x: value in pixels * * Converts @x from pixels to #EggUnit<!-- -->s * * Since: 0.6 */ #define EGG_UNITS_FROM_DEVICE(x) EGG_UNITS_FROM_INT ((x)) /** * EGG_UNITS_TO_DEVICE: * @x: value in #EggUnit<!-- -->s * * Converts @x from #EggUnit<!-- -->s to pixels * * Since: 0.6 */ #define EGG_UNITS_TO_DEVICE(x) EGG_UNITS_TO_INT ((x)) #define EGG_UNITS_TMP_FROM_DEVICE(x) (x) #define EGG_UNITS_TMP_TO_DEVICE(x) (x) /** * EGG_UNITS_FROM_PANGO_UNIT: * @x: value in Pango units * * Converts a value in Pango units to #EggUnit<!-- -->s * * Since: 0.6 */ #define EGG_UNITS_FROM_PANGO_UNIT(x) ((x) << 6) /** * EGG_UNITS_TO_PANGO_UNIT: * @x: value in #EggUnit<!-- -->s * * Converts a value in #EggUnit<!-- -->s to Pango units * * Since: 0.6 */ #define EGG_UNITS_TO_PANGO_UNIT(x) ((x) >> 6) #define EGG_UNITS_FROM_STAGE_WIDTH_PERCENTAGE(x) \ ((egg_actor_get_widthu (egg_stage_get_default ()) * x) / 100) #define EGG_UNITS_FROM_STAGE_HEIGHT_PERCENTAGE(x) \ ((egg_actor_get_heightu (egg_stage_get_default ()) * x) / 100) #define EGG_UNITS_FROM_PARENT_WIDTH_PERCENTAGE(a, x) \ ((egg_actor_get_widthu (egg_actor_get_parent (a)) * x) / 100) #define EGG_UNITS_FROM_PARENT_HEIGHT_PERCENTAGE(a, x) \ ((egg_actor_get_heightu (egg_actor_get_parent (a)) * x) / 100) /** * EGG_UNITS_FROM_MM: * @x: a value in millimeters * * Converts a value in millimeters into #EggUnit<!-- -->s * * Since: 0.6 */ #define EGG_UNITS_FROM_MM(x) \ (EGG_UNITS_FROM_FLOAT ((((x) * egg_stage_get_resolution ((EggStage *) egg_stage_get_default ())) / 25.4))) #define EGG_UNITS_FROM_MMX(x) \ (CFX_DIV (CFX_MUL ((x), egg_stage_get_resolutionx ((EggStage *) egg_stage_get_default ())), 0x196666)) /** * EGG_UNITS_FROM_POINTS: * @x: a value in typographic points * * Converts a value in typographic points into #EggUnit<!-- -->s * * Since: 0.6 */ #define EGG_UNITS_FROM_POINTS(x) \ EGG_UNITS_FROM_FLOAT ((((x) * egg_stage_get_resolution ((EggStage *) egg_stage_get_default ())) / 72.0)) #define EGG_UNITS_FROM_POINTSX(x) \ (CFX_MUL ((x), egg_stage_get_resolutionx ((EggStage *) egg_stage_get_default ())) / 72) #define EGG_TYPE_UNIT (egg_unit_get_type ()) #define EGG_TYPE_PARAM_UNIT (egg_param_unit_get_type ()) #define EGG_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), EGG_TYPE_PARAM_UNIT, EggParamSpecUnit)) #define EGG_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), EGG_TYPE_PARAM_UNIT)) /** * EGG_MAXUNIT: * * Higher boundary for a #EggUnit * * Since: 0.8 */ #define EGG_MAXUNIT (0x7fffffff) /** * EGG_MINUNIT: * * Lower boundary for a #EggUnit * * Since: 0.8 */ #define EGG_MINUNIT (0x80000000) /** * EGG_VALUE_HOLDS_UNIT: * @x: a #GValue * * Evaluates to %TRUE if @x holds #EggUnit<!-- -->s. * * Since: 0.8 */ #define EGG_VALUE_HOLDS_UNIT(x) (G_VALUE_HOLDS ((x), EGG_TYPE_UNIT)) typedef struct _EggParamSpecUnit EggParamSpecUnit; /** * EggParamSpecUnit: * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * * #GParamSpec subclass for unit based properties. * * Since: 0.8 */ struct _EggParamSpecUnit { /*< private >*/ GParamSpec parent_instance; /*< public >*/ EggUnit minimum; EggUnit maximum; EggUnit default_value; }; GType egg_unit_get_type (void) G_GNUC_CONST; GType egg_param_unit_get_type (void) G_GNUC_CONST; void egg_value_set_unit (GValue *value, EggUnit units); EggUnit egg_value_get_unit (const GValue *value); GParamSpec *egg_param_spec_unit (const gchar *name, const gchar *nick, const gchar *blurb, EggUnit minimum, EggUnit maximum, EggUnit default_value, GParamFlags flags); G_END_DECLS #endif /* _HAVE_EGG_UNITS_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/test-timeline-smoothness.c��������������������������������������������������������������������0000644�0000156�0000165�00000005007�12704153542�016773� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <egg/egg-hack.h> #define TEST_TIMELINE_FPS 10 #define TEST_TIMELINE_FRAME_COUNT 20 #define TEST_ERROR_TOLERANCE 5 typedef struct _TestState { EggTimeline *timeline; GTimeVal start_time; GTimeVal prev_frame_time; guint frame; gint completion_count; gint passed; }TestState; static void new_frame_cb (EggTimeline *timeline, gint frame_num, TestState *state) { GTimeVal current_time; glong total_elapsed_ms; glong frame_elapsed_ms = 0; gchar *bump = ""; g_get_current_time (¤t_time); total_elapsed_ms = (current_time.tv_sec - state->start_time.tv_sec) * 1000; total_elapsed_ms += (current_time.tv_usec - state->start_time.tv_usec)/1000; if (state->frame>0) { frame_elapsed_ms = (current_time.tv_sec - state->prev_frame_time.tv_sec) * 1000; frame_elapsed_ms += (current_time.tv_usec - state->prev_frame_time.tv_usec)/1000; if (ABS(frame_elapsed_ms - (1000/TEST_TIMELINE_FPS)) > TEST_ERROR_TOLERANCE) { state->passed = FALSE; bump = " (BUMP)"; } } g_print ("timeline frame=%-2d total elapsed=%-4li(ms) since last frame=%-4li(ms)%s\n", egg_timeline_get_current_frame(state->timeline), total_elapsed_ms, frame_elapsed_ms, bump); state->prev_frame_time = current_time; state->frame++; } static void completed_cb (EggTimeline *timeline, TestState *state) { state->completion_count++; if (state->completion_count == 2) { if (state->passed) { g_print("Passed\n"); exit(EXIT_SUCCESS); } else { g_print("Failed\n"); exit(EXIT_FAILURE); } } } int main(int argc, char **argv) { TestState state; state.timeline = egg_timeline_new (TEST_TIMELINE_FRAME_COUNT, TEST_TIMELINE_FPS); egg_timeline_set_loop (state.timeline, TRUE); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_signal_connect (G_OBJECT(state.timeline), "completed", G_CALLBACK(completed_cb), &state); state.frame = 0; state.completion_count = 0; state.passed = TRUE; g_get_current_time (&state.start_time); egg_timeline_start (state.timeline); egg_main(); return EXIT_FAILURE; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-timeout-pool.c����������������������������������������������������������������������������0000644�0000156�0000165�00000034455�12704153542�015216� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * EggTimeoutPool: pool of timeout functions using the same slice of * the GLib main loop * * Author: Emmanuele Bassi <ebassi@openedhand.com> * * Based on similar code by Tristan van Berkom */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "egg-debug.h" #include "egg-timeout-pool.h" typedef struct _EggTimeout EggTimeout; typedef enum { EGG_TIMEOUT_NONE = 0, EGG_TIMEOUT_READY = 1 << 1 } EggTimeoutFlags; struct _EggTimeout { guint id; EggTimeoutFlags flags; gint refcount; guint interval; guint last_time; GSourceFunc func; gpointer data; GDestroyNotify notify; }; struct _EggTimeoutPool { GSource source; guint next_id; GTimeVal start_time; GList *timeouts, *dispatched_timeouts; gint ready; guint id; }; #define TIMEOUT_READY(timeout) (timeout->flags & EGG_TIMEOUT_READY) static gboolean egg_timeout_pool_prepare (GSource *source, gint *next_timeout); static gboolean egg_timeout_pool_check (GSource *source); static gboolean egg_timeout_pool_dispatch (GSource *source, GSourceFunc callback, gpointer data); static void egg_timeout_pool_finalize (GSource *source); static GSourceFuncs egg_timeout_pool_funcs = { egg_timeout_pool_prepare, egg_timeout_pool_check, egg_timeout_pool_dispatch, egg_timeout_pool_finalize }; static gint egg_timeout_sort (gconstpointer a, gconstpointer b) { const EggTimeout *t_a = a; const EggTimeout *t_b = b; gint comparison; /* Keep 'ready' timeouts at the front */ if (TIMEOUT_READY (t_a)) return -1; if (TIMEOUT_READY (t_b)) return 1; /* Otherwise sort by expiration time */ comparison = (t_a->last_time + t_a->interval) - (t_b->last_time + t_b->interval); if (comparison < 0) return -1; if (comparison > 0) return 1; return 0; } static gint egg_timeout_find_by_id (gconstpointer a, gconstpointer b) { const EggTimeout *t_a = a; return t_a->id == GPOINTER_TO_UINT (b) ? 0 : 1; } static guint egg_timeout_pool_get_ticks (EggTimeoutPool *pool) { GTimeVal time_now; g_source_get_current_time ((GSource *) pool, &time_now); return (time_now.tv_sec - pool->start_time.tv_sec) * 1000 + (time_now.tv_usec - pool->start_time.tv_usec) / 1000; } static gboolean egg_timeout_prepare (EggTimeoutPool *pool, EggTimeout *timeout, gint *next_timeout) { guint now = egg_timeout_pool_get_ticks (pool); /* If time has gone backwards or the time since the last frame is greater than the two frames worth then reset the time and do a frame now */ if (timeout->last_time > now || now - timeout->last_time > timeout->interval * 2) { timeout->last_time = now - timeout->interval; if (next_timeout) *next_timeout = 0; return TRUE; } else if (now - timeout->last_time >= timeout->interval) { if (next_timeout) *next_timeout = 0; return TRUE; } else { if (next_timeout) *next_timeout = timeout->interval + timeout->last_time - now; return FALSE; } } static gboolean egg_timeout_dispatch (GSource *source, EggTimeout *timeout) { gboolean retval = FALSE; if (G_UNLIKELY (!timeout->func)) { g_warning ("Timeout dispatched without a callback."); return FALSE; } if (timeout->func (timeout->data)) { timeout->last_time += timeout->interval; retval = TRUE; } return retval; } static EggTimeout * egg_timeout_new (guint interval) { EggTimeout *timeout; timeout = g_slice_new0 (EggTimeout); timeout->interval = interval; timeout->flags = EGG_TIMEOUT_NONE; timeout->refcount = 1; return timeout; } /* ref and unref are always called under the main Egg lock, so there * is not need for us to use g_atomic_int_* API. */ static EggTimeout * egg_timeout_ref (EggTimeout *timeout) { g_return_val_if_fail (timeout != NULL, timeout); g_return_val_if_fail (timeout->refcount > 0, timeout); timeout->refcount += 1; return timeout; } static void egg_timeout_unref (EggTimeout *timeout) { g_return_if_fail (timeout != NULL); g_return_if_fail (timeout->refcount > 0); timeout->refcount -= 1; if (timeout->refcount == 0) { if (timeout->notify) timeout->notify (timeout->data); g_slice_free (EggTimeout, timeout); } } static void egg_timeout_free (EggTimeout *timeout) { if (G_LIKELY (timeout)) { if (timeout->notify) timeout->notify (timeout->data); g_slice_free (EggTimeout, timeout); } } static gboolean egg_timeout_pool_prepare (GSource *source, gint *next_timeout) { EggTimeoutPool *pool = (EggTimeoutPool *) source; GList *l = pool->timeouts; /* the pool is ready if the first timeout is ready */ if (l && l->data) { EggTimeout *timeout = l->data; return egg_timeout_prepare (pool, timeout, next_timeout); } else { *next_timeout = -1; return FALSE; } } static gboolean egg_timeout_pool_check (GSource *source) { EggTimeoutPool *pool = (EggTimeoutPool *) source; GList *l = pool->timeouts; egg_threads_enter (); for (l = pool->timeouts; l; l = l->next) { EggTimeout *timeout = l->data; /* since the timeouts are sorted by expiration, as soon * as we get a check returning FALSE we know that the * following timeouts are not expiring, so we break as * soon as possible */ if (egg_timeout_prepare (pool, timeout, NULL)) { timeout->flags |= EGG_TIMEOUT_READY; pool->ready += 1; } else break; } egg_threads_leave (); return (pool->ready > 0); } static gboolean egg_timeout_pool_dispatch (GSource *source, GSourceFunc func, gpointer data) { EggTimeoutPool *pool = (EggTimeoutPool *) source; GList *dispatched_timeouts; /* the main loop might have predicted this, so we repeat the * check for ready timeouts. */ if (!pool->ready) egg_timeout_pool_check (source); egg_threads_enter (); /* Iterate by moving the actual start of the list along so that it * can cope with adds and removes while a timeout is being dispatched */ while (pool->timeouts && pool->timeouts->data && pool->ready-- > 0) { EggTimeout *timeout = pool->timeouts->data; GList *l; /* One of the ready timeouts may have been removed during dispatch, * in which case pool->ready will be wrong, but the ready timeouts * are always kept at the start of the list so we can stop once * we've reached the first non-ready timeout */ if (!(TIMEOUT_READY (timeout))) break; /* Add a reference to the timeout so it can't disappear * while it's being dispatched */ egg_timeout_ref (timeout); timeout->flags &= ~EGG_TIMEOUT_READY; /* Move the list node to a list of dispatched timeouts */ l = pool->timeouts; if (l->next) l->next->prev = NULL; pool->timeouts = l->next; if (pool->dispatched_timeouts) pool->dispatched_timeouts->prev = l; l->prev = NULL; l->next = pool->dispatched_timeouts; pool->dispatched_timeouts = l; if (!egg_timeout_dispatch (source, timeout)) { /* The timeout may have already been removed, but nothing * can be added to the dispatched_timeout list except in this * function so it will always either be at the head of the * dispatched list or have been removed */ if (pool->dispatched_timeouts && pool->dispatched_timeouts->data == timeout) { pool->dispatched_timeouts = g_list_delete_link (pool->dispatched_timeouts, pool->dispatched_timeouts); /* Remove the reference that was held by it being in the list */ egg_timeout_unref (timeout); } } egg_timeout_unref (timeout); } /* Re-insert the dispatched timeouts in sorted order */ dispatched_timeouts = pool->dispatched_timeouts; while (dispatched_timeouts) { EggTimeout *timeout = dispatched_timeouts->data; GList *next = dispatched_timeouts->next; if (timeout) pool->timeouts = g_list_insert_sorted (pool->timeouts, timeout, egg_timeout_sort); dispatched_timeouts = next; } g_list_free (pool->dispatched_timeouts); pool->dispatched_timeouts = NULL; pool->ready = 0; egg_threads_leave (); return TRUE; } static void egg_timeout_pool_finalize (GSource *source) { EggTimeoutPool *pool = (EggTimeoutPool *) source; /* force destruction */ g_list_foreach (pool->timeouts, (GFunc) egg_timeout_free, NULL); g_list_free (pool->timeouts); } /** * egg_timeout_pool_new: * @priority: the priority of the timeout pool. Typically this will * be #G_PRIORITY_DEFAULT * * Creates a new timeout pool source. A timeout pool should be used when * multiple timeout functions, running at the same priority, are needed and * the g_timeout_add() API might lead to starvation of the time slice of * the main loop. A timeout pool allocates a single time slice of the main * loop and runs every timeout function inside it. The timeout pool is * always sorted, so that the extraction of the next timeout function is * a constant time operation. * * Inside Egg, every #EggTimeline share the same timeout pool, unless * the EGG_TIMELINE=no-pool environment variable is set. * * #EggTimeoutPool is part of the #EggTimeline implementation * and should not be used by application developers. * * Return value: the newly created #EggTimeoutPool. The created pool * is owned by the GLib default context and will be automatically * destroyed when the context is destroyed. It is possible to force * the destruction of the timeout pool using g_source_destroy() * * Since: 0.4 */ EggTimeoutPool * egg_timeout_pool_new (gint priority) { EggTimeoutPool *pool; GSource *source; source = g_source_new (&egg_timeout_pool_funcs, sizeof (EggTimeoutPool)); if (!source) return NULL; if (priority != G_PRIORITY_DEFAULT) g_source_set_priority (source, priority); pool = (EggTimeoutPool *) source; g_get_current_time (&pool->start_time); pool->next_id = 1; pool->id = g_source_attach (source, NULL); /* let the default GLib context manage the pool */ g_source_unref (source); return pool; } /** * egg_timeout_pool_add: * @pool: a #EggTimeoutPool * @interval: the time between calls to the function, in milliseconds * @func: function to call * @data: data to pass to the function, or %NULL * @notify: function to call when the timeout is removed, or %NULL * * Sets a function to be called at regular intervals, and puts it inside * the @pool. The function is repeatedly called until it returns %FALSE, * at which point the timeout is automatically destroyed and the function * won't be called again. If @notify is not %NULL, the @notify function * will be called. The first call to @func will be at the end of @interval. * * Since version 0.8 this will try to compensate for delays. For * example, if @func takes half the interval time to execute then the * function will be called again half the interval time after it * finished. Before version 0.8 it would not fire until a full * interval after the function completes so the delay between calls * would be @interval * 1.5. This function does not however try to * invoke the function multiple times to catch up missing frames if * @func takes more than @interval ms to execute. * * Return value: the ID (greater than 0) of the timeout inside the pool. * Use egg_timeout_pool_remove() to stop the timeout. * * Since: 0.4 */ guint egg_timeout_pool_add (EggTimeoutPool *pool, guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify) { EggTimeout *timeout; guint retval = 0; timeout = egg_timeout_new (interval); retval = timeout->id = pool->next_id++; timeout->last_time = egg_timeout_pool_get_ticks (pool); timeout->func = func; timeout->data = data; timeout->notify = notify; pool->timeouts = g_list_insert_sorted (pool->timeouts, timeout, egg_timeout_sort); return retval; } /** * egg_timeout_pool_remove: * @pool: a #EggTimeoutPool * @id: the id of the timeout to remove * * Removes a timeout function with @id from the timeout pool. The id * is the same returned when adding a function to the timeout pool with * egg_timeout_pool_add(). * * Since: 0.4 */ void egg_timeout_pool_remove (EggTimeoutPool *pool, guint id) { GList *l; if ((l = g_list_find_custom (pool->timeouts, GUINT_TO_POINTER (id), egg_timeout_find_by_id))) { egg_timeout_unref (l->data); pool->timeouts = g_list_delete_link (pool->timeouts, l); } else if ((l = g_list_find_custom (pool->dispatched_timeouts, GUINT_TO_POINTER (id), egg_timeout_find_by_id))) { egg_timeout_unref (l->data); pool->dispatched_timeouts = g_list_delete_link (pool->dispatched_timeouts, l); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-hack.h������������������������������������������������������������������������������������0000644�0000156�0000165�00000005062�12704153542�013464� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef __EGG_HACK_H__ #define __EGG_HACK_H__ #include <stdlib.h> #include <stdio.h> #include <string.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <math.h> #include <glib.h> // #include "egg-backend.h" // #include "egg-event.h" // #include "egg-feature.h" // #include "egg-id-pool.h" // #include "egg-stage-manager.h" // #include "egg-stage-window.h" // #include "egg-stage.h" // #include "pango/pangoegg.h" #include "egg-debug.h" #include "egg-fixed.h" #include "egg-units.h" #include "egg-timeline.h" #include "egg-timeout-pool.h" #define I_(str) (g_intern_static_string ((str))) #define EGG_PRIORITY_TIMELINE (G_PRIORITY_DEFAULT + 30) #include <glib-object.h> G_BEGIN_DECLS #define EGG_PARAM_READABLE \ G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB #define EGG_PARAM_WRITABLE \ G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB #define EGG_PARAM_READWRITE \ G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB guint egg_get_default_frame_rate (void); void egg_threads_enter (void); void egg_threads_leave (void); void egg_main (void); /* enumerations from "./egg-timeline.h" */ GType egg_timeline_direction_get_type (void) G_GNUC_CONST; #define EGG_TYPE_TIMELINE_DIRECTION (egg_timeline_direction_get_type()) /* VOID:STRING,INT (./egg-marshal.list:12) */ extern void egg_marshal_VOID__STRING_INT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:VOID (./egg-marshal.list:13) */ #define egg_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID /* VOID:INT (./egg-marshal.list:4) */ #define egg_marshal_VOID__INT g_cclosure_marshal_VOID__INT /* UINT:VOID (./egg-marshal.list:2) */ extern void egg_marshal_UINT__VOID (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); G_END_DECLS #endif /* !__EGG_HACK_H__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-alpha.h�����������������������������������������������������������������������������������0000644�0000156�0000165�00000013527�12704153542�013650� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * Jorn Baayen <jorn@openedhand.com> * Emmanuele Bassi <ebassi@openedhand.com> * Tomas Frydrych <tf@openedhand.com> * * Copyright (C) 2006, 2007 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __EGG_ALPHA_H__ #define __EGG_ALPHA_H__ #include <glib-object.h> #include <egg/egg-timeline.h> #include <egg/egg-fixed.h> G_BEGIN_DECLS #define EGG_TYPE_ALPHA egg_alpha_get_type() #define EGG_ALPHA(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EGG_TYPE_ALPHA, EggAlpha)) #define EGG_ALPHA_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EGG_TYPE_ALPHA, EggAlphaClass)) #define EGG_IS_ALPHA(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EGG_TYPE_ALPHA)) #define EGG_IS_ALPHA_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EGG_TYPE_ALPHA)) #define EGG_ALPHA_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EGG_TYPE_ALPHA, EggAlphaClass)) typedef struct _EggAlpha EggAlpha; typedef struct _EggAlphaClass EggAlphaClass; typedef struct _EggAlphaPrivate EggAlphaPrivate; /** * EggAlphaFunc: * @alpha: a #EggAlpha * @user_data: user data passed to the function * * A function of time, which returns a value between 0 and * %EGG_ALPHA_MAX_ALPHA. * * Return value: an unsigned integer value, between 0 and * %EGG_ALPHA_MAX_ALPHA. * * Since: 0.2 */ typedef guint32 (*EggAlphaFunc) (EggAlpha *alpha, gpointer user_data); /** * EggAlpha: * * #EggAlpha combines a #EggTimeline and a function. * The contents of the #EggAlpha structure are private and should * only be accessed using the provided API. * * Since: 0.2 */ struct _EggAlpha { /*< private >*/ GInitiallyUnowned parent; EggAlphaPrivate *priv; }; /** * EggAlphaClass: * * Base class for #EggAlpha * * Since: 0.2 */ struct _EggAlphaClass { /*< private >*/ GInitiallyUnownedClass parent_class; void (*_egg_alpha_1) (void); void (*_egg_alpha_2) (void); void (*_egg_alpha_3) (void); void (*_egg_alpha_4) (void); void (*_egg_alpha_5) (void); }; /** * EGG_ALPHA_MAX_ALPHA: * * Maximum value returned by #EggAlphaFunc * * Since: 0.2 */ #define EGG_ALPHA_MAX_ALPHA 0xffff GType egg_alpha_get_type (void) G_GNUC_CONST; EggAlpha * egg_alpha_new (void); EggAlpha * egg_alpha_new_full (EggTimeline *timeline, EggAlphaFunc func, gpointer data, GDestroyNotify destroy); guint32 egg_alpha_get_alpha (EggAlpha *alpha); void egg_alpha_set_func (EggAlpha *alpha, EggAlphaFunc func, gpointer data, GDestroyNotify destroy); void egg_alpha_set_closure (EggAlpha *alpha, GClosure *closure); void egg_alpha_set_timeline (EggAlpha *alpha, EggTimeline *timeline); EggTimeline *egg_alpha_get_timeline (EggAlpha *alpha); /* convenience functions */ #define EGG_ALPHA_RAMP_INC egg_ramp_inc_func #define EGG_ALPHA_RAMP_DEC egg_ramp_dec_func #define EGG_ALPHA_RAMP egg_ramp_func #define EGG_ALPHA_SINE egg_sine_func #define EGG_ALPHA_SINE_INC egg_sine_inc_func #define EGG_ALPHA_SINE_DEC egg_sine_dec_func #define EGG_ALPHA_SINE_HALF egg_sine_half_func #define EGG_ALPHA_SQUARE egg_square_func #define EGG_ALPHA_SMOOTHSTEP_INC egg_smoothstep_inc_func #define EGG_ALPHA_SMOOTHSTEP_DEC egg_smoothstep_dec_func #define EGG_ALPHA_EXP_INC egg_exp_inc_func #define EGG_ALPHA_EXP_DEC egg_exp_dec_func guint32 egg_ramp_inc_func (EggAlpha *alpha, gpointer dummy); guint32 egg_ramp_dec_func (EggAlpha *alpha, gpointer dummy); guint32 egg_ramp_func (EggAlpha *alpha, gpointer dummy); guint32 egg_sine_func (EggAlpha *alpha, gpointer dummy); guint32 egg_sine_inc_func (EggAlpha *alpha, gpointer dummy); guint32 egg_sine_dec_func (EggAlpha *alpha, gpointer dummy); guint32 egg_sine_half_func (EggAlpha *alpha, gpointer dummy); guint32 egg_square_func (EggAlpha *alpha, gpointer dummy); guint32 egg_smoothstep_inc_func (EggAlpha *alpha, gpointer dummy); guint32 egg_smoothstep_dec_func (EggAlpha *alpha, gpointer dummy); guint32 egg_exp_inc_func (EggAlpha *alpha, gpointer dummy); guint32 egg_exp_dec_func (EggAlpha *alpha, gpointer dummy); G_END_DECLS #endif /* __EGG_ALPHA_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-timeout-pool.h����������������������������������������������������������������������������0000644�0000156�0000165�00000003565�12704153542�015221� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * EggTimeoutPool: pool of timeout functions using the same slice of * the GLib main loop * * Author: Emmanuele Bassi <ebassi@openedhand.com> * * Based on similar code by Tristan van Berkom */ #ifndef __EGG_TIMEOUT_POOL_H__ #define __EGG_TIMEOUT_POOL_H__ #include <glib.h> G_BEGIN_DECLS typedef struct _EggTimeoutPool EggTimeoutPool; EggTimeoutPool *egg_timeout_pool_new (gint priority); guint egg_timeout_pool_add (EggTimeoutPool *pool, guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify); void egg_timeout_pool_remove (EggTimeoutPool *pool, guint id); G_END_DECLS #endif /* __EGG_TIMEOUT_POOL_H__ */ �������������������������������������������������������������������������������������������������������������������������������������������./egg/test-timeline-interpolate.c�������������������������������������������������������������������0000644�0000156�0000165�00000010130�12704153542�017110� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdlib.h> #include <glib.h> #include <egg/egg-hack.h> /* We ask for 1 frame per millisecond. * Whenever this rate can't be achieved then the timeline * will interpolate the number frames that should have * passed between timeouts. */ #define TEST_TIMELINE_FPS 1000 #define TEST_TIMELINE_FRAME_COUNT 5000 /* We are at the mercy of the system scheduler so this * may not be a very reliable tolerance. */ #define TEST_ERROR_TOLERANCE 20 typedef struct _TestState { EggTimeline *timeline; GTimeVal start_time; guint new_frame_counter; gint expected_frame; gint completion_count; gboolean passed; }TestState; static void new_frame_cb (EggTimeline *timeline, gint frame_num, TestState *state) { GTimeVal current_time; gint current_frame; glong msec_diff; gint loop_overflow = 0; static gint step = 1; g_get_current_time (¤t_time); current_frame = egg_timeline_get_current_frame (state->timeline); msec_diff = (current_time.tv_sec - state->start_time.tv_sec) * 1000; msec_diff += (current_time.tv_usec - state->start_time.tv_usec)/1000; /* If we expect to have interpolated past the end of the timeline * we keep track of the overflow so we can determine when * the next timeout will happen. We then clip expected_frames * to TEST_TIMELINE_FRAME_COUNT since egg-timeline * semantics guaranty this frame is always signaled before * looping */ if (state->expected_frame > TEST_TIMELINE_FRAME_COUNT) { loop_overflow = state->expected_frame - TEST_TIMELINE_FRAME_COUNT; state->expected_frame = TEST_TIMELINE_FRAME_COUNT; } if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE) && current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE)) { g_print ("\nelapsed milliseconds=%-5li expected frame=%-4i actual frame=%-4i (OK)\n", msec_diff, state->expected_frame, current_frame); } else { g_print ("\nelapsed milliseconds=%-5li expected frame=%-4i actual frame=%-4i (FAILED)\n", msec_diff, state->expected_frame, current_frame); state->passed = FALSE; } if (step>0) { state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4); g_print ("Sleeping for 250ms so next frame should be (%i + %i) = %i\n", current_frame, (TEST_TIMELINE_FPS / 4), state->expected_frame); g_usleep (250000); } else { state->expected_frame = current_frame + TEST_TIMELINE_FPS; g_print ("Sleeping for 1sec so next frame should be (%i + %i) = %i\n", current_frame, TEST_TIMELINE_FPS, state->expected_frame); g_usleep (1000000); } if (current_frame >= TEST_TIMELINE_FRAME_COUNT) { state->expected_frame += loop_overflow; state->expected_frame -= TEST_TIMELINE_FRAME_COUNT; g_print ("End of timeline reached: Wrapping expected frame too %i\n", state->expected_frame); } state->new_frame_counter++; step = -step; } static void completed_cb (EggTimeline *timeline, TestState *state) { state->completion_count++; if (state->completion_count == 2) { if (state->passed) { g_print("Passed\n"); exit(EXIT_SUCCESS); } else { g_print("Failed\n"); exit(EXIT_FAILURE); } } } int main (int argc, char **argv) { TestState state; state.timeline = egg_timeline_new (TEST_TIMELINE_FRAME_COUNT, TEST_TIMELINE_FPS); egg_timeline_set_loop (state.timeline, TRUE); g_signal_connect (G_OBJECT(state.timeline), "new-frame", G_CALLBACK(new_frame_cb), &state); g_signal_connect (G_OBJECT(state.timeline), "completed", G_CALLBACK(completed_cb), &state); state.completion_count = 0; state.new_frame_counter = 0; state.passed = TRUE; state.expected_frame = 0; g_get_current_time (&state.start_time); egg_timeline_start (state.timeline); egg_main(); return EXIT_FAILURE; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-timeline.h��������������������������������������������������������������������������������0000644�0000156�0000165�00000015544�12704153542�014372� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _HAVE_EGG_TIMELINE_H #define _HAVE_EGG_TIMELINE_H #include <glib-object.h> #include <egg/egg-fixed.h> G_BEGIN_DECLS #define EGG_TYPE_TIMELINE (egg_timeline_get_type ()) #define EGG_TIMELINE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ EGG_TYPE_TIMELINE, EggTimeline)) #define EGG_TIMELINE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), \ EGG_TYPE_TIMELINE, EggTimelineClass)) #define EGG_IS_TIMELINE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ EGG_TYPE_TIMELINE)) #define EGG_IS_TIMELINE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE ((klass), \ EGG_TYPE_TIMELINE)) #define EGG_TIMELINE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ EGG_TYPE_TIMELINE, EggTimelineClass)) /** * EggTimelineDirection: * @EGG_TIMELINE_FORWARD: forward direction for a timeline * @EGG_TIMELINE_BACKWARD: backward direction for a timeline * * The direction of a #EggTimeline * * Since: 0.6 */ typedef enum { EGG_TIMELINE_FORWARD, EGG_TIMELINE_BACKWARD } EggTimelineDirection; typedef struct _EggTimeline EggTimeline; typedef struct _EggTimelineClass EggTimelineClass; typedef struct _EggTimelinePrivate EggTimelinePrivate; struct _EggTimeline { /*< private >*/ GObject parent; EggTimelinePrivate *priv; }; struct _EggTimelineClass { /*< private >*/ GObjectClass parent_class; /*< public >*/ void (*started) (EggTimeline *timeline); void (*completed) (EggTimeline *timeline); void (*paused) (EggTimeline *timeline); void (*new_frame) (EggTimeline *timeline, gint frame_num); void (*marker_reached) (EggTimeline *timeline, const gchar *marker_name, gint frame_num); /*< private >*/ void (*_egg_timeline_1) (void); void (*_egg_timeline_2) (void); void (*_egg_timeline_3) (void); void (*_egg_timeline_4) (void); void (*_egg_timeline_5) (void); }; GType egg_timeline_get_type (void) G_GNUC_CONST; EggTimeline *egg_timeline_new (guint n_frames, guint fps); EggTimeline *egg_timeline_new_for_duration (guint msecs); EggTimeline *egg_timeline_clone (EggTimeline *timeline); guint egg_timeline_get_duration (EggTimeline *timeline); void egg_timeline_set_duration (EggTimeline *timeline, guint msecs); guint egg_timeline_get_speed (EggTimeline *timeline); void egg_timeline_set_speed (EggTimeline *timeline, guint fps); EggTimelineDirection egg_timeline_get_direction (EggTimeline *timeline); void egg_timeline_set_direction (EggTimeline *timeline, EggTimelineDirection direction); void egg_timeline_start (EggTimeline *timeline); void egg_timeline_pause (EggTimeline *timeline); void egg_timeline_stop (EggTimeline *timeline); void egg_timeline_set_loop (EggTimeline *timeline, gboolean loop); gboolean egg_timeline_get_loop (EggTimeline *timeline); void egg_timeline_rewind (EggTimeline *timeline); void egg_timeline_skip (EggTimeline *timeline, guint n_frames); void egg_timeline_advance (EggTimeline *timeline, guint frame_num); gint egg_timeline_get_current_frame (EggTimeline *timeline); gdouble egg_timeline_get_progress (EggTimeline *timeline); EggFixed egg_timeline_get_progressx (EggTimeline *timeline); void egg_timeline_set_n_frames (EggTimeline *timeline, guint n_frames); guint egg_timeline_get_n_frames (EggTimeline *timeline); gboolean egg_timeline_is_playing (EggTimeline *timeline); void egg_timeline_set_delay (EggTimeline *timeline, guint msecs); guint egg_timeline_get_delay (EggTimeline *timeline); guint egg_timeline_get_delta (EggTimeline *timeline, guint *msecs); void egg_timeline_add_marker_at_frame (EggTimeline *timeline, const gchar *marker_name, guint frame_num); void egg_timeline_add_marker_at_time (EggTimeline *timeline, const gchar *marker_name, guint msecs); void egg_timeline_remove_marker (EggTimeline *timeline, const gchar *marker_name); gchar ** egg_timeline_list_markers (EggTimeline *timeline, gint frame_num, gsize *n_markers) G_GNUC_MALLOC; gboolean egg_timeline_has_marker (EggTimeline *timeline, const gchar *marker_name); void egg_timeline_advance_to_marker (EggTimeline *timeline, const gchar *marker_name); G_END_DECLS #endif /* _HAVE_EGG_TIMELINE_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-fixed.c�����������������������������������������������������������������������������������0000644�0000156�0000165�00000114310�12704153542�013645� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Tomas Frydrych <tf@openedhand.com> * * Copyright (C) 2006, 2007 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define G_IMPLEMENT_INLINES #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <glib-object.h> #include <gobject/gvaluecollector.h> #include "egg-fixed.h" // #include "egg-private.h" #include "egg-hack.h" /** * SECTION:egg-fixed * @short_description: Fixed Point API * * Egg has a fixed point API targeted at platforms without a * floating point unit, such as embedded devices. On such platforms * this API should be preferred to the floating point one as it does * not trigger the slow path of software emulation, relying on integer * math for fixed-to-floating and floating-to-fixed conversion. * * It is no recommened for use on platforms with a floating point unit * (eg desktop systems) nor for use in bindings. * * Basic rules of Fixed Point arithmethic: * * <itemizedlist> * <listitem> * <para>Two fixed point numbers can be directly added, * subtracted and have their modulus taken.</para> * </listitem> * <listitem> * <para>To add other numerical type to a fixed point number it has to * be first converted to fixed point.</para> * </listitem> * <listitem> * <para>A fixed point number can be directly multiplied or divided by * an integer.</para> * </listitem> * <listitem> * <para>Two fixed point numbers can only be multiplied and divided by the * provided #EGG_FIXED_MUL and #EGG_FIXED_DIV macros.</para> * </listitem> * </itemizedlist> */ /* pre-computed sin table for 1st quadrant * * Currently contains 257 entries. * * The current error (compared to system sin) is about * 0.5% for values near the start of the table where the * curve is steep, but improving rapidly. If this precission * is not enough, we can increase the size of the table */ static EggFixed sin_tbl [] = { 0x00000000L, 0x00000192L, 0x00000324L, 0x000004B6L, 0x00000648L, 0x000007DAL, 0x0000096CL, 0x00000AFEL, 0x00000C90L, 0x00000E21L, 0x00000FB3L, 0x00001144L, 0x000012D5L, 0x00001466L, 0x000015F7L, 0x00001787L, 0x00001918L, 0x00001AA8L, 0x00001C38L, 0x00001DC7L, 0x00001F56L, 0x000020E5L, 0x00002274L, 0x00002402L, 0x00002590L, 0x0000271EL, 0x000028ABL, 0x00002A38L, 0x00002BC4L, 0x00002D50L, 0x00002EDCL, 0x00003067L, 0x000031F1L, 0x0000337CL, 0x00003505L, 0x0000368EL, 0x00003817L, 0x0000399FL, 0x00003B27L, 0x00003CAEL, 0x00003E34L, 0x00003FBAL, 0x0000413FL, 0x000042C3L, 0x00004447L, 0x000045CBL, 0x0000474DL, 0x000048CFL, 0x00004A50L, 0x00004BD1L, 0x00004D50L, 0x00004ECFL, 0x0000504DL, 0x000051CBL, 0x00005348L, 0x000054C3L, 0x0000563EL, 0x000057B9L, 0x00005932L, 0x00005AAAL, 0x00005C22L, 0x00005D99L, 0x00005F0FL, 0x00006084L, 0x000061F8L, 0x0000636BL, 0x000064DDL, 0x0000664EL, 0x000067BEL, 0x0000692DL, 0x00006A9BL, 0x00006C08L, 0x00006D74L, 0x00006EDFL, 0x00007049L, 0x000071B2L, 0x0000731AL, 0x00007480L, 0x000075E6L, 0x0000774AL, 0x000078ADL, 0x00007A10L, 0x00007B70L, 0x00007CD0L, 0x00007E2FL, 0x00007F8CL, 0x000080E8L, 0x00008243L, 0x0000839CL, 0x000084F5L, 0x0000864CL, 0x000087A1L, 0x000088F6L, 0x00008A49L, 0x00008B9AL, 0x00008CEBL, 0x00008E3AL, 0x00008F88L, 0x000090D4L, 0x0000921FL, 0x00009368L, 0x000094B0L, 0x000095F7L, 0x0000973CL, 0x00009880L, 0x000099C2L, 0x00009B03L, 0x00009C42L, 0x00009D80L, 0x00009EBCL, 0x00009FF7L, 0x0000A130L, 0x0000A268L, 0x0000A39EL, 0x0000A4D2L, 0x0000A605L, 0x0000A736L, 0x0000A866L, 0x0000A994L, 0x0000AAC1L, 0x0000ABEBL, 0x0000AD14L, 0x0000AE3CL, 0x0000AF62L, 0x0000B086L, 0x0000B1A8L, 0x0000B2C9L, 0x0000B3E8L, 0x0000B505L, 0x0000B620L, 0x0000B73AL, 0x0000B852L, 0x0000B968L, 0x0000BA7DL, 0x0000BB8FL, 0x0000BCA0L, 0x0000BDAFL, 0x0000BEBCL, 0x0000BFC7L, 0x0000C0D1L, 0x0000C1D8L, 0x0000C2DEL, 0x0000C3E2L, 0x0000C4E4L, 0x0000C5E4L, 0x0000C6E2L, 0x0000C7DEL, 0x0000C8D9L, 0x0000C9D1L, 0x0000CAC7L, 0x0000CBBCL, 0x0000CCAEL, 0x0000CD9FL, 0x0000CE8EL, 0x0000CF7AL, 0x0000D065L, 0x0000D14DL, 0x0000D234L, 0x0000D318L, 0x0000D3FBL, 0x0000D4DBL, 0x0000D5BAL, 0x0000D696L, 0x0000D770L, 0x0000D848L, 0x0000D91EL, 0x0000D9F2L, 0x0000DAC4L, 0x0000DB94L, 0x0000DC62L, 0x0000DD2DL, 0x0000DDF7L, 0x0000DEBEL, 0x0000DF83L, 0x0000E046L, 0x0000E107L, 0x0000E1C6L, 0x0000E282L, 0x0000E33CL, 0x0000E3F4L, 0x0000E4AAL, 0x0000E55EL, 0x0000E610L, 0x0000E6BFL, 0x0000E76CL, 0x0000E817L, 0x0000E8BFL, 0x0000E966L, 0x0000EA0AL, 0x0000EAABL, 0x0000EB4BL, 0x0000EBE8L, 0x0000EC83L, 0x0000ED1CL, 0x0000EDB3L, 0x0000EE47L, 0x0000EED9L, 0x0000EF68L, 0x0000EFF5L, 0x0000F080L, 0x0000F109L, 0x0000F18FL, 0x0000F213L, 0x0000F295L, 0x0000F314L, 0x0000F391L, 0x0000F40CL, 0x0000F484L, 0x0000F4FAL, 0x0000F56EL, 0x0000F5DFL, 0x0000F64EL, 0x0000F6BAL, 0x0000F724L, 0x0000F78CL, 0x0000F7F1L, 0x0000F854L, 0x0000F8B4L, 0x0000F913L, 0x0000F96EL, 0x0000F9C8L, 0x0000FA1FL, 0x0000FA73L, 0x0000FAC5L, 0x0000FB15L, 0x0000FB62L, 0x0000FBADL, 0x0000FBF5L, 0x0000FC3BL, 0x0000FC7FL, 0x0000FCC0L, 0x0000FCFEL, 0x0000FD3BL, 0x0000FD74L, 0x0000FDACL, 0x0000FDE1L, 0x0000FE13L, 0x0000FE43L, 0x0000FE71L, 0x0000FE9CL, 0x0000FEC4L, 0x0000FEEBL, 0x0000FF0EL, 0x0000FF30L, 0x0000FF4EL, 0x0000FF6BL, 0x0000FF85L, 0x0000FF9CL, 0x0000FFB1L, 0x0000FFC4L, 0x0000FFD4L, 0x0000FFE1L, 0x0000FFECL, 0x0000FFF5L, 0x0000FFFBL, 0x0000FFFFL, 0x00010000L, }; /* the difference of the angle for two adjacent values in the table * expressed as EggFixed number */ #define CFX_SIN_STEP 0x00000192 /* <private> */ const double _magic = 68719476736.0 * 1.5; /* Where in the 64 bits of double is the mantisa */ #if (__FLOAT_WORD_ORDER == 1234) #define _CFX_MAN 0 #elif (__FLOAT_WORD_ORDER == 4321) #define _CFX_MAN 1 #else #define CFX_NO_FAST_CONVERSIONS #endif /* * egg_double_to_fixed : * @value: value to be converted * * A fast conversion from double precision floating to fixed point * * Return value: Fixed point representation of the value * * Since: 0.2 */ EggFixed egg_double_to_fixed (double val) { #ifdef CFX_NO_FAST_CONVERSIONS return (EggFixed)(val * (double)CFX_ONE); #else union { double d; unsigned int i[2]; } dbl; dbl.d = val; dbl.d = dbl.d + _magic; return dbl.i[_CFX_MAN]; #endif } /* * egg_double_to_int : * @value: value to be converted * * A fast conversion from doulbe precision floatint point to int; * used this instead of casting double/float to int. * * Return value: Integer part of the double * * Since: 0.2 */ gint egg_double_to_int (double val) { #ifdef CFX_NO_FAST_CONVERSIONS return (gint)(val); #else union { double d; unsigned int i[2]; } dbl; dbl.d = val; dbl.d = dbl.d + _magic; return ((int)dbl.i[_CFX_MAN]) >> 16; #endif } guint egg_double_to_uint (double val) { #ifdef CFX_NO_FAST_CONVERSIONS return (guint)(val); #else union { double d; unsigned int i[2]; } dbl; dbl.d = val; dbl.d = dbl.d + _magic; return (dbl.i[_CFX_MAN]) >> 16; #endif } #undef _CFX_MAN /** * egg_sinx: * @angle: a #EggFixed angle in radians * * Fixed point implementation of sine function * * Return value: #EggFixed sine value. * * Since: 0.2 */ EggFixed egg_sinx (EggFixed angle) { int sign = 1, indx1, indx2; EggFixed low, high, d1, d2; /* convert negative angle to positive + sign */ if ((int)angle < 0) { sign = 1 + ~sign; angle = 1 + ~angle; } /* reduce to <0, 2*pi) */ angle = angle % CFX_2PI; /* reduce to first quadrant and sign */ if (angle > CFX_PI) { sign = 1 + ~sign; if (angle > CFX_PI + CFX_PI_2) { /* fourth qudrant */ angle = CFX_2PI - angle; } else { /* third quadrant */ angle -= CFX_PI; } } else { if (angle > CFX_PI_2) { /* second quadrant */ angle = CFX_PI - angle; } } /* Calculate indices of the two nearest values in our table * and return weighted average * * Handle the end of the table gracefully */ indx1 = EGG_FIXED_DIV (angle, CFX_SIN_STEP); indx1 = EGG_FIXED_TO_INT (indx1); if (indx1 == sizeof (sin_tbl)/sizeof (EggFixed) - 1) { indx2 = indx1; indx1 = indx2 - 1; } else { indx2 = indx1 + 1; } low = sin_tbl[indx1]; high = sin_tbl[indx2]; d1 = angle - indx1 * CFX_SIN_STEP; d2 = indx2 * CFX_SIN_STEP - angle; angle = ((low * d2 + high * d1) / (CFX_SIN_STEP)); if (sign < 0) angle = (1 + ~angle); return angle; } /** * egg_sini: * @angle: a #EggAngle * * Very fast fixed point implementation of sine function. * * EggAngle is an integer such that 1024 represents * full circle. * * Return value: #EggFixed sine value. * * Since: 0.2 */ EggFixed egg_sini (EggAngle angle) { int sign = 1; EggFixed result; /* reduce negative angle to positive + sign */ if (angle < 0) { sign = 1 + ~sign; angle = 1 + ~angle; } /* reduce to <0, 2*pi) */ angle &= 0x3ff; /* reduce to first quadrant and sign */ if (angle > 512) { sign = 1 + ~sign; if (angle > 768) { /* fourth qudrant */ angle = 1024 - angle; } else { /* third quadrant */ angle -= 512; } } else { if (angle > 256) { /* second quadrant */ angle = 512 - angle; } } result = sin_tbl[angle]; if (sign < 0) result = (1 + ~result); return result; } /* pre-computed tan table for 1st quadrant * * Currently contains 257 entries. * */ static EggFixed tan_tbl [] = { 0x00000000L, 0x00000192L, 0x00000324L, 0x000004b7L, 0x00000649L, 0x000007dbL, 0x0000096eL, 0x00000b01L, 0x00000c94L, 0x00000e27L, 0x00000fbaL, 0x0000114eL, 0x000012e2L, 0x00001477L, 0x0000160cL, 0x000017a1L, 0x00001937L, 0x00001acdL, 0x00001c64L, 0x00001dfbL, 0x00001f93L, 0x0000212cL, 0x000022c5L, 0x0000245fL, 0x000025f9L, 0x00002795L, 0x00002931L, 0x00002aceL, 0x00002c6cL, 0x00002e0aL, 0x00002faaL, 0x0000314aL, 0x000032ecL, 0x0000348eL, 0x00003632L, 0x000037d7L, 0x0000397dL, 0x00003b24L, 0x00003cccL, 0x00003e75L, 0x00004020L, 0x000041ccL, 0x00004379L, 0x00004528L, 0x000046d8L, 0x0000488aL, 0x00004a3dL, 0x00004bf2L, 0x00004da8L, 0x00004f60L, 0x0000511aL, 0x000052d5L, 0x00005492L, 0x00005651L, 0x00005812L, 0x000059d5L, 0x00005b99L, 0x00005d60L, 0x00005f28L, 0x000060f3L, 0x000062c0L, 0x0000648fL, 0x00006660L, 0x00006834L, 0x00006a0aL, 0x00006be2L, 0x00006dbdL, 0x00006f9aL, 0x0000717aL, 0x0000735dL, 0x00007542L, 0x0000772aL, 0x00007914L, 0x00007b02L, 0x00007cf2L, 0x00007ee6L, 0x000080dcL, 0x000082d6L, 0x000084d2L, 0x000086d2L, 0x000088d6L, 0x00008adcL, 0x00008ce7L, 0x00008ef4L, 0x00009106L, 0x0000931bL, 0x00009534L, 0x00009750L, 0x00009971L, 0x00009b95L, 0x00009dbeL, 0x00009febL, 0x0000a21cL, 0x0000a452L, 0x0000a68cL, 0x0000a8caL, 0x0000ab0eL, 0x0000ad56L, 0x0000afa3L, 0x0000b1f5L, 0x0000b44cL, 0x0000b6a8L, 0x0000b909L, 0x0000bb70L, 0x0000bdddL, 0x0000c04fL, 0x0000c2c7L, 0x0000c545L, 0x0000c7c9L, 0x0000ca53L, 0x0000cce3L, 0x0000cf7aL, 0x0000d218L, 0x0000d4bcL, 0x0000d768L, 0x0000da1aL, 0x0000dcd4L, 0x0000df95L, 0x0000e25eL, 0x0000e52eL, 0x0000e806L, 0x0000eae7L, 0x0000edd0L, 0x0000f0c1L, 0x0000f3bbL, 0x0000f6bfL, 0x0000f9cbL, 0x0000fce1L, 0x00010000L, 0x00010329L, 0x0001065dL, 0x0001099aL, 0x00010ce3L, 0x00011036L, 0x00011394L, 0x000116feL, 0x00011a74L, 0x00011df6L, 0x00012184L, 0x0001251fL, 0x000128c6L, 0x00012c7cL, 0x0001303fL, 0x00013410L, 0x000137f0L, 0x00013bdfL, 0x00013fddL, 0x000143ebL, 0x00014809L, 0x00014c37L, 0x00015077L, 0x000154c9L, 0x0001592dL, 0x00015da4L, 0x0001622eL, 0x000166ccL, 0x00016b7eL, 0x00017045L, 0x00017523L, 0x00017a17L, 0x00017f22L, 0x00018444L, 0x00018980L, 0x00018ed5L, 0x00019445L, 0x000199cfL, 0x00019f76L, 0x0001a53aL, 0x0001ab1cL, 0x0001b11dL, 0x0001b73fL, 0x0001bd82L, 0x0001c3e7L, 0x0001ca71L, 0x0001d11fL, 0x0001d7f4L, 0x0001def1L, 0x0001e618L, 0x0001ed6aL, 0x0001f4e8L, 0x0001fc96L, 0x00020473L, 0x00020c84L, 0x000214c9L, 0x00021d44L, 0x000225f9L, 0x00022ee9L, 0x00023818L, 0x00024187L, 0x00024b3aL, 0x00025534L, 0x00025f78L, 0x00026a0aL, 0x000274edL, 0x00028026L, 0x00028bb8L, 0x000297a8L, 0x0002a3fbL, 0x0002b0b5L, 0x0002bdddL, 0x0002cb79L, 0x0002d98eL, 0x0002e823L, 0x0002f740L, 0x000306ecL, 0x00031730L, 0x00032816L, 0x000339a6L, 0x00034bebL, 0x00035ef2L, 0x000372c6L, 0x00038776L, 0x00039d11L, 0x0003b3a6L, 0x0003cb48L, 0x0003e40aL, 0x0003fe02L, 0x00041949L, 0x000435f7L, 0x0004542bL, 0x00047405L, 0x000495a9L, 0x0004b940L, 0x0004def6L, 0x00050700L, 0x00053196L, 0x00055ef9L, 0x00058f75L, 0x0005c35dL, 0x0005fb14L, 0x00063709L, 0x000677c0L, 0x0006bdd0L, 0x000709ecL, 0x00075ce6L, 0x0007b7bbL, 0x00081b98L, 0x000889e9L, 0x0009046eL, 0x00098d4dL, 0x000a2736L, 0x000ad593L, 0x000b9cc6L, 0x000c828aL, 0x000d8e82L, 0x000ecb1bL, 0x001046eaL, 0x00121703L, 0x00145b00L, 0x0017448dL, 0x001b2672L, 0x002095afL, 0x0028bc49L, 0x0036519aL, 0x00517bb6L, 0x00a2f8fdL, 0x46d3eab2L, }; /** * egg_tani: * @angle: a #EggAngle * * Very fast fixed point implementation of tan function. * * EggAngle is an integer such that 1024 represents * full circle. * * Return value: #EggFixed sine value. * * Since: 0.3 */ EggFixed egg_tani (EggAngle angle) { int sign = 1; EggFixed result; /* reduce negative angle to positive + sign */ if (angle < 0) { sign = 1 + ~sign; angle = 1 + ~angle; } /* reduce to <0, pi) */ angle &= 0x1ff; /* reduce to first quadrant and sign */ if (angle > 256) { sign = 1 + ~sign; angle = 512 - angle; } result = tan_tbl[angle]; if (sign < 0) result = (1 + ~result); return result; } /* 257-value table of atan. atan_tbl[0] is atan(0.0) and atan_tbl[256] is atan(1). The angles are radians in EggFixed truncated to 16-bit (they're all less than one) */ static guint16 atan_tbl[] = { 0x0000, 0x00FF, 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, 0x07FF, 0x08FF, 0x09FE, 0x0AFE, 0x0BFD, 0x0CFD, 0x0DFC, 0x0EFB, 0x0FFA, 0x10F9, 0x11F8, 0x12F7, 0x13F5, 0x14F3, 0x15F2, 0x16F0, 0x17EE, 0x18EB, 0x19E9, 0x1AE6, 0x1BE3, 0x1CE0, 0x1DDD, 0x1ED9, 0x1FD5, 0x20D1, 0x21CD, 0x22C8, 0x23C3, 0x24BE, 0x25B9, 0x26B3, 0x27AD, 0x28A7, 0x29A1, 0x2A9A, 0x2B93, 0x2C8B, 0x2D83, 0x2E7B, 0x2F72, 0x306A, 0x3160, 0x3257, 0x334D, 0x3442, 0x3538, 0x362D, 0x3721, 0x3815, 0x3909, 0x39FC, 0x3AEF, 0x3BE2, 0x3CD4, 0x3DC5, 0x3EB6, 0x3FA7, 0x4097, 0x4187, 0x4277, 0x4365, 0x4454, 0x4542, 0x462F, 0x471C, 0x4809, 0x48F5, 0x49E0, 0x4ACB, 0x4BB6, 0x4CA0, 0x4D89, 0x4E72, 0x4F5B, 0x5043, 0x512A, 0x5211, 0x52F7, 0x53DD, 0x54C2, 0x55A7, 0x568B, 0x576F, 0x5852, 0x5934, 0x5A16, 0x5AF7, 0x5BD8, 0x5CB8, 0x5D98, 0x5E77, 0x5F55, 0x6033, 0x6110, 0x61ED, 0x62C9, 0x63A4, 0x647F, 0x6559, 0x6633, 0x670C, 0x67E4, 0x68BC, 0x6993, 0x6A6A, 0x6B40, 0x6C15, 0x6CEA, 0x6DBE, 0x6E91, 0x6F64, 0x7036, 0x7108, 0x71D9, 0x72A9, 0x7379, 0x7448, 0x7516, 0x75E4, 0x76B1, 0x777E, 0x7849, 0x7915, 0x79DF, 0x7AA9, 0x7B72, 0x7C3B, 0x7D03, 0x7DCA, 0x7E91, 0x7F57, 0x801C, 0x80E1, 0x81A5, 0x8269, 0x832B, 0x83EE, 0x84AF, 0x8570, 0x8630, 0x86F0, 0x87AF, 0x886D, 0x892A, 0x89E7, 0x8AA4, 0x8B5F, 0x8C1A, 0x8CD5, 0x8D8E, 0x8E47, 0x8F00, 0x8FB8, 0x906F, 0x9125, 0x91DB, 0x9290, 0x9345, 0x93F9, 0x94AC, 0x955F, 0x9611, 0x96C2, 0x9773, 0x9823, 0x98D2, 0x9981, 0x9A2F, 0x9ADD, 0x9B89, 0x9C36, 0x9CE1, 0x9D8C, 0x9E37, 0x9EE0, 0x9F89, 0xA032, 0xA0DA, 0xA181, 0xA228, 0xA2CE, 0xA373, 0xA418, 0xA4BC, 0xA560, 0xA602, 0xA6A5, 0xA746, 0xA7E8, 0xA888, 0xA928, 0xA9C7, 0xAA66, 0xAB04, 0xABA1, 0xAC3E, 0xACDB, 0xAD76, 0xAE11, 0xAEAC, 0xAF46, 0xAFDF, 0xB078, 0xB110, 0xB1A7, 0xB23E, 0xB2D5, 0xB36B, 0xB400, 0xB495, 0xB529, 0xB5BC, 0xB64F, 0xB6E2, 0xB773, 0xB805, 0xB895, 0xB926, 0xB9B5, 0xBA44, 0xBAD3, 0xBB61, 0xBBEE, 0xBC7B, 0xBD07, 0xBD93, 0xBE1E, 0xBEA9, 0xBF33, 0xBFBC, 0xC046, 0xC0CE, 0xC156, 0xC1DD, 0xC264, 0xC2EB, 0xC371, 0xC3F6, 0xC47B, 0xC4FF, 0xC583, 0xC606, 0xC689, 0xC70B, 0xC78D, 0xC80E, 0xC88F, 0xC90F }; /** * egg_atani: * @x: The tangent to calculate the angle for * * Fast fixed-point version of the arctangent function. * * Return value: The angle in radians represented as a #EggFixed * for which the tangent is @x. */ EggFixed egg_atani (EggFixed x) { gboolean negative = FALSE; EggFixed angle; if (x < 0) { negative = TRUE; x = -x; } if (x > CFX_ONE) /* if x > 1 then atan(x) = pi/2 - atan(1/x) */ angle = CFX_PI / 2 - atan_tbl[CFX_QDIV (CFX_ONE, x) >> 8]; else angle = atan_tbl[x >> 8]; return negative ? -angle : angle; } /** * egg_atan2i: * @y: Numerator of tangent * @x: Denominator of tangent * * Calculates the arctangent of @y / @x but uses the sign of both * arguments to return the angle in right quadrant. * * Return value: The arctangent of @y / @x */ EggFixed egg_atan2i (EggFixed y, EggFixed x) { EggFixed angle; if (x == 0) angle = y >= 0 ? CFX_PI_2 : -CFX_PI_2; else { angle = egg_atani (CFX_QDIV (y, x)); if (x < 0) angle += y >= 0 ? CFX_PI : -CFX_PI; } return angle; } EggFixed sqrt_tbl [] = { 0x00000000L, 0x00010000L, 0x00016A0AL, 0x0001BB68L, 0x00020000L, 0x00023C6FL, 0x00027312L, 0x0002A550L, 0x0002D414L, 0x00030000L, 0x0003298BL, 0x0003510EL, 0x000376CFL, 0x00039B05L, 0x0003BDDDL, 0x0003DF7CL, 0x00040000L, 0x00041F84L, 0x00043E1EL, 0x00045BE1L, 0x000478DEL, 0x00049524L, 0x0004B0BFL, 0x0004CBBCL, 0x0004E624L, 0x00050000L, 0x00051959L, 0x00053237L, 0x00054AA0L, 0x0005629AL, 0x00057A2BL, 0x00059159L, 0x0005A828L, 0x0005BE9CL, 0x0005D4B9L, 0x0005EA84L, 0x00060000L, 0x00061530L, 0x00062A17L, 0x00063EB8L, 0x00065316L, 0x00066733L, 0x00067B12L, 0x00068EB4L, 0x0006A21DL, 0x0006B54DL, 0x0006C847L, 0x0006DB0CL, 0x0006ED9FL, 0x00070000L, 0x00071232L, 0x00072435L, 0x0007360BL, 0x000747B5L, 0x00075935L, 0x00076A8CL, 0x00077BBBL, 0x00078CC2L, 0x00079DA3L, 0x0007AE60L, 0x0007BEF8L, 0x0007CF6DL, 0x0007DFBFL, 0x0007EFF0L, 0x00080000L, 0x00080FF0L, 0x00081FC1L, 0x00082F73L, 0x00083F08L, 0x00084E7FL, 0x00085DDAL, 0x00086D18L, 0x00087C3BL, 0x00088B44L, 0x00089A32L, 0x0008A906L, 0x0008B7C2L, 0x0008C664L, 0x0008D4EEL, 0x0008E361L, 0x0008F1BCL, 0x00090000L, 0x00090E2EL, 0x00091C45L, 0x00092A47L, 0x00093834L, 0x0009460CL, 0x000953CFL, 0x0009617EL, 0x00096F19L, 0x00097CA1L, 0x00098A16L, 0x00099777L, 0x0009A4C6L, 0x0009B203L, 0x0009BF2EL, 0x0009CC47L, 0x0009D94FL, 0x0009E645L, 0x0009F32BL, 0x000A0000L, 0x000A0CC5L, 0x000A1979L, 0x000A261EL, 0x000A32B3L, 0x000A3F38L, 0x000A4BAEL, 0x000A5816L, 0x000A646EL, 0x000A70B8L, 0x000A7CF3L, 0x000A8921L, 0x000A9540L, 0x000AA151L, 0x000AAD55L, 0x000AB94BL, 0x000AC534L, 0x000AD110L, 0x000ADCDFL, 0x000AE8A1L, 0x000AF457L, 0x000B0000L, 0x000B0B9DL, 0x000B172DL, 0x000B22B2L, 0x000B2E2BL, 0x000B3998L, 0x000B44F9L, 0x000B504FL, 0x000B5B9AL, 0x000B66D9L, 0x000B720EL, 0x000B7D37L, 0x000B8856L, 0x000B936AL, 0x000B9E74L, 0x000BA973L, 0x000BB467L, 0x000BBF52L, 0x000BCA32L, 0x000BD508L, 0x000BDFD5L, 0x000BEA98L, 0x000BF551L, 0x000C0000L, 0x000C0AA6L, 0x000C1543L, 0x000C1FD6L, 0x000C2A60L, 0x000C34E1L, 0x000C3F59L, 0x000C49C8L, 0x000C542EL, 0x000C5E8CL, 0x000C68E0L, 0x000C732DL, 0x000C7D70L, 0x000C87ACL, 0x000C91DFL, 0x000C9C0AL, 0x000CA62CL, 0x000CB047L, 0x000CBA59L, 0x000CC464L, 0x000CCE66L, 0x000CD861L, 0x000CE254L, 0x000CEC40L, 0x000CF624L, 0x000D0000L, 0x000D09D5L, 0x000D13A2L, 0x000D1D69L, 0x000D2727L, 0x000D30DFL, 0x000D3A90L, 0x000D4439L, 0x000D4DDCL, 0x000D5777L, 0x000D610CL, 0x000D6A9AL, 0x000D7421L, 0x000D7DA1L, 0x000D871BL, 0x000D908EL, 0x000D99FAL, 0x000DA360L, 0x000DACBFL, 0x000DB618L, 0x000DBF6BL, 0x000DC8B7L, 0x000DD1FEL, 0x000DDB3DL, 0x000DE477L, 0x000DEDABL, 0x000DF6D8L, 0x000E0000L, 0x000E0922L, 0x000E123DL, 0x000E1B53L, 0x000E2463L, 0x000E2D6DL, 0x000E3672L, 0x000E3F70L, 0x000E4869L, 0x000E515DL, 0x000E5A4BL, 0x000E6333L, 0x000E6C16L, 0x000E74F3L, 0x000E7DCBL, 0x000E869DL, 0x000E8F6BL, 0x000E9832L, 0x000EA0F5L, 0x000EA9B2L, 0x000EB26BL, 0x000EBB1EL, 0x000EC3CBL, 0x000ECC74L, 0x000ED518L, 0x000EDDB7L, 0x000EE650L, 0x000EEEE5L, 0x000EF775L, 0x000F0000L, 0x000F0886L, 0x000F1107L, 0x000F1984L, 0x000F21FCL, 0x000F2A6FL, 0x000F32DDL, 0x000F3B47L, 0x000F43ACL, 0x000F4C0CL, 0x000F5468L, 0x000F5CBFL, 0x000F6512L, 0x000F6D60L, 0x000F75AAL, 0x000F7DEFL, 0x000F8630L, 0x000F8E6DL, 0x000F96A5L, 0x000F9ED9L, 0x000FA709L, 0x000FAF34L, 0x000FB75BL, 0x000FBF7EL, 0x000FC79DL, 0x000FCFB7L, 0x000FD7CEL, 0x000FDFE0L, 0x000FE7EEL, 0x000FEFF8L, 0x000FF7FEL, 0x00100000L, }; /** * egg_sqrtx: * @x: a #EggFixed * * A fixed point implementation of squre root * * Return value: #EggFixed square root. * * Since: 0.2 */ EggFixed egg_sqrtx (EggFixed x) { /* The idea for this comes from the Alegro library, exploiting the * fact that, * sqrt (x) = sqrt (x/d) * sqrt (d); * * For d == 2^(n): * * sqrt (x) = sqrt (x/2^(2n)) * 2^n * * By locating suitable n for given x such that x >> 2n is in <0,255> * we can use a LUT of precomputed values. * * This algorithm provides both good performance and precission; * on ARM this function is about 5 times faster than c-lib sqrt, whilst * producing errors < 1%. * */ int t = 0; int sh = 0; #ifndef __arm__ unsigned int mask = 0x40000000; #endif unsigned fract = x & 0x0000ffff; unsigned int d1, d2; EggFixed v1, v2; if (x <= 0) return 0; if (x > CFX_255 || x < CFX_ONE) { /* * Find the highest bit set */ #if __arm__ /* This actually requires at least arm v5, but gcc does not seem * to set the architecture defines correctly, and it is I think * very unlikely that anyone will want to use egg on anything * less than v5. */ int bit; __asm__ ("clz %0, %1\n" "rsb %0, %0, #31\n" :"=r"(bit) :"r" (x)); /* make even (2n) */ bit &= 0xfffffffe; #else /* TODO -- add i386 branch using bshr * * NB: it's been said that the bshr instruction is poorly implemented * and that it is possible to write a faster code in C using binary * search -- at some point we should explore this */ int bit = 30; while (bit >= 0) { if (x & mask) break; mask = (mask >> 1 | mask >> 2); bit -= 2; } #endif /* now bit indicates the highest bit set; there are two scenarios * * 1) bit < 23: Our number is smaller so we shift it left to maximase * precision (< 16 really, since <16,23> never goes * through here. * * 2) bit > 23: our number is above the table, so we shift right */ sh = ((bit - 22) >> 1); if (bit >= 8) t = (x >> (16 - 22 + bit)); else t = (x << (22 - 16 - bit)); } else { t = EGG_FIXED_TO_INT (x); } /* Do a weighted average of the two nearest values */ v1 = sqrt_tbl[t]; v2 = sqrt_tbl[t+1]; /* * 12 is fairly arbitrary -- we want integer that is not too big to cost * us precission */ d1 = (unsigned)(fract) >> 12; d2 = ((unsigned)CFX_ONE >> 12) - d1; x = ((v1*d2) + (v2*d1))/(CFX_ONE >> 12); if (sh > 0) x = x << sh; else if (sh < 0) x = (x >> (1 + ~sh)); return x; } /** * egg_sqrti: * @x: integer value * * Very fast fixed point implementation of square root for integers. * * This function is at least 6x faster than clib sqrt() on x86, and (this is * not a typo!) about 500x faster on ARM without FPU. It's error is < 5% * for arguments < #EGG_SQRTI_ARG_5_PERCENT and < 10% for arguments < * #EGG_SQRTI_ARG_10_PERCENT. The maximum argument that can be passed to * this function is EGG_SQRTI_ARG_MAX. * * Return value: integer square root. * * * Since: 0.2 */ gint egg_sqrti (gint number) { #if defined __SSE2__ /* The GCC built-in with SSE2 (sqrtsd) is up to twice as fast as * the pure integer code below. It is also more accurate. */ return __builtin_sqrt (number); #else /* This is a fixed point implementation of the Quake III sqrt algorithm, * described, for example, at * http://www.codemaestro.com/reviews/review00000105.html * * While the original QIII is extremely fast, the use of floating division * and multiplication makes it perform very on arm processors without FPU. * * The key to successfully replacing the floating point operations with * fixed point is in the choice of the fixed point format. The QIII * algorithm does not calculate the square root, but its reciprocal ('y' * below), which is only at the end turned to the inverse value. In order * for the algorithm to produce satisfactory results, the reciprocal value * must be represented with sufficient precission; the 16.16 we use * elsewhere in egg is not good enough, and 10.22 is used instead. */ EggFixed x; guint32 y_1; /* 10.22 fixed point */ guint32 f = 0x600000; /* '1.5' as 10.22 fixed */ union { float f; guint32 i; } flt, flt2; flt.f = number; x = EGG_INT_TO_FIXED (number) / 2; /* The QIII initial estimate */ flt.i = 0x5f3759df - ( flt.i >> 1 ); /* Now, we convert the float to 10.22 fixed. We exploit the mechanism * described at http://www.d6.com/users/checker/pdfs/gdmfp.pdf. * * We want 22 bit fraction; a single precission float uses 23 bit * mantisa, so we only need to add 2^(23-22) (no need for the 1.5 * multiplier as we are only dealing with positive numbers). * * Note: we have to use two separate variables here -- for some reason, * if we try to use just the flt variable, gcc on ARM optimises the whole * addition out, and it all goes pear shape, since without it, the bits * in the float will not be correctly aligned. */ flt2.f = flt.f + 2.0; flt2.i &= 0x7FFFFF; /* Now we correct the estimate */ y_1 = (flt2.i >> 11) * (flt2.i >> 11); y_1 = (y_1 >> 8) * (x >> 8); y_1 = f - y_1; flt2.i = (flt2.i >> 11) * (y_1 >> 11); /* If the original argument is less than 342, we do another * iteration to improve precission (for arguments >= 342, the single * iteration produces generally better results). */ if (x < 171) { y_1 = (flt2.i >> 11) * (flt2.i >> 11); y_1 = (y_1 >> 8) * (x >> 8); y_1 = f - y_1; flt2.i = (flt2.i >> 11) * (y_1 >> 11); } /* Invert, round and convert from 10.22 to an integer * 0x1e3c68 is a magical rounding constant that produces slightly * better results than 0x200000. */ return (number * flt2.i + 0x1e3c68) >> 22; #endif } /** * egg_qmulx: * @op1: #EggFixed * @op2: #EggFixed * * Multiplies two fixed values using 64bit arithmetic; this provides * significantly better precission than the #EGG_FIXED_MUL macro, * but at performance cost (about 2.7 times slowdown on ARMv5e, and 2 times * on x86). * * Return value: the result of the operation * * Since: 0.4 */ EggFixed egg_qmulx (EggFixed op1, EggFixed op2) { #ifdef __arm__ /* This provides about 12% speedeup on the gcc -O2 optimised * C version * * Based on code found in the following thread: * http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2006-August/014405.html */ int res_low, res_hi; __asm__ ("smull %0, %1, %2, %3 \n" "mov %0, %0, lsr %4 \n" "add %1, %0, %1, lsl %5 \n" : "=r"(res_hi), "=r"(res_low)\ : "r"(op1), "r"(op2), "i"(CFX_Q), "i"(32-CFX_Q)); return (EggFixed) res_low; #else long long r = (long long) op1 * (long long) op2; return (unsigned int)(r >> CFX_Q); #endif } /** * egg_qdivx: * @op1: #EggFixed * @op2: #EggFixed * * Divides two fixed values using 64bit arithmetic; this provides * significantly better precission than the #EGG_FIXED_DIV macro, * but at performance cost. * * Return value: #EggFixed * * Since: 0.4 */ EggFixed egg_qdivx (EggFixed op1, EggFixed op2) { return (EggFixed) ((((gint64) op1) << CFX_Q) / op2); } /* * The log2x() and pow2x() functions * * The implementation of the log2x() and pow2x() exploits the well-documented * fact that the exponent part of IEEE floating number provides a good estimate * of log2 of that number, while the mantisa serves as a good error-correction. * * The implemenation here uses a quadratic error correction as described by * Ian Stephenson at http://www.dctsystems.co.uk/Software/power.html. */ /** * egg_log2x : * @x: value to calculate base 2 logarithm from * * Calculates base 2 logarithm. * * This function is some 2.5 times faster on x86, and over 12 times faster on * fpu-less arm, than using libc log(). * * Return value: base 2 logarithm. * * Since: 0.4 */ EggFixed egg_log2x (guint x) { /* Note: we could easily have a version for EggFixed x, but the int * precission is enough for the current purposes. */ union { float f; EggFixed i; } flt; EggFixed magic = 0x58bb; EggFixed y; /* * Convert x to float, then extract exponent. * * We want the result to be 16.16 fixed, so we shift (23-16) bits only */ flt.f = x; flt.i >>= 7; flt.i -= EGG_INT_TO_FIXED (127); y = EGG_FIXED_FRACTION (flt.i); y = CFX_MUL ((y - CFX_MUL (y, y)), magic); return flt.i + y; } /** * egg_pow2x : * @x: exponent * * Calculates 2 to x power. * * This function is around 11 times faster on x86, and around 22 times faster * on fpu-less arm than libc pow(2, x). * * Return value: 2 in x power. * * Since: 0.4 */ guint egg_pow2x (EggFixed x) { /* Note: we could easily have a version that produces EggFixed result, * but the the range would be limited to x < 15, and the int precission * is enough for the current purposes. */ union { float f; guint32 i; } flt; EggFixed magic = 0x56f7; EggFixed y; flt.i = x; /* * Reverse of the log2x function -- convert the fixed value to a suitable * floating point exponent, and mantisa adjusted with quadratic error * correction y. */ y = EGG_FIXED_FRACTION (x); y = CFX_MUL ((y - CFX_MUL (y, y)), magic); /* Shift the exponent into it's position in the floating point * representation; as our number is not int but 16.16 fixed, shift only * by (23 - 16) */ flt.i += (EGG_INT_TO_FIXED (127) - y); flt.i <<= 7; return EGG_FLOAT_TO_UINT (flt.f); } /** * egg_powx : * @x: base * @y: #EggFixed exponent * * Calculates x to y power. (Note, if x is a constant it will be faster to * calculate the power as egg_pow2x (EGG_FIXED_MUL(y, log2 (x))) * * Return value: x in y power. * * Since: 0.4 */ guint egg_powx (guint x, EggFixed y) { return egg_pow2x (CFX_MUL (y, egg_log2x (x))); } static GTypeInfo _info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, }; static GTypeFundamentalInfo _finfo = { 0, }; static void egg_value_init_fixed (GValue *value) { value->data[0].v_int = 0; } static void egg_value_copy_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = src->data[0].v_int; } static gchar * egg_value_collect_fixed (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { value->data[0].v_int = collect_values[0].v_int; return NULL; } static gchar * egg_value_lcopy_fixed (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags) { gint32 *fixed_p = collect_values[0].v_pointer; if (!fixed_p) return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); *fixed_p = value->data[0].v_int; return NULL; } static void egg_value_transform_fixed_int (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_FIXED_TO_INT (src->data[0].v_int); } static void egg_value_transform_fixed_double (const GValue *src, GValue *dest) { dest->data[0].v_double = EGG_FIXED_TO_DOUBLE (src->data[0].v_int); } static void egg_value_transform_fixed_float (const GValue *src, GValue *dest) { dest->data[0].v_float = EGG_FIXED_TO_FLOAT (src->data[0].v_int); } static void egg_value_transform_int_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_INT_TO_FIXED (src->data[0].v_int); } static void egg_value_transform_double_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_FLOAT_TO_FIXED (src->data[0].v_double); } static void egg_value_transform_float_fixed (const GValue *src, GValue *dest) { dest->data[0].v_int = EGG_FLOAT_TO_FIXED (src->data[0].v_float); } static const GTypeValueTable _egg_fixed_value_table = { egg_value_init_fixed, NULL, egg_value_copy_fixed, NULL, "i", egg_value_collect_fixed, "p", egg_value_lcopy_fixed }; GType egg_fixed_get_type (void) { static GType _egg_fixed_type = 0; if (G_UNLIKELY (_egg_fixed_type == 0)) { _info.value_table = & _egg_fixed_value_table; _egg_fixed_type = g_type_register_fundamental (g_type_fundamental_next (), I_("EggFixed"), &_info, &_finfo, 0); g_value_register_transform_func (_egg_fixed_type, G_TYPE_INT, egg_value_transform_fixed_int); g_value_register_transform_func (G_TYPE_INT, _egg_fixed_type, egg_value_transform_int_fixed); g_value_register_transform_func (_egg_fixed_type, G_TYPE_FLOAT, egg_value_transform_fixed_float); g_value_register_transform_func (G_TYPE_FLOAT, _egg_fixed_type, egg_value_transform_float_fixed); g_value_register_transform_func (_egg_fixed_type, G_TYPE_DOUBLE, egg_value_transform_fixed_double); g_value_register_transform_func (G_TYPE_DOUBLE, _egg_fixed_type, egg_value_transform_double_fixed); } return _egg_fixed_type; } /** * egg_value_set_fixed: * @value: a #GValue initialized to #EGG_TYPE_FIXED * @fixed_: the fixed point value to set * * Sets @value to @fixed_. * * Since: 0.8 */ void egg_value_set_fixed (GValue *value, EggFixed fixed_) { g_return_if_fail (EGG_VALUE_HOLDS_FIXED (value)); value->data[0].v_int = fixed_; } /** * egg_value_get_fixed: * @value: a #GValue initialized to #EGG_TYPE_FIXED * * Gets the fixed point value stored inside @value. * * Return value: the value inside the passed #GValue * * Since: 0.8 */ EggFixed egg_value_get_fixed (const GValue *value) { g_return_val_if_fail (EGG_VALUE_HOLDS_FIXED (value), 0); return value->data[0].v_int; } static void param_fixed_init (GParamSpec *pspec) { EggParamSpecFixed *fspec = EGG_PARAM_SPEC_FIXED (pspec); fspec->minimum = EGG_MINFIXED; fspec->maximum = EGG_MAXFIXED; fspec->default_value = 0; } static void param_fixed_set_default (GParamSpec *pspec, GValue *value) { value->data[0].v_int = EGG_PARAM_SPEC_FIXED (pspec)->default_value; } static gboolean param_fixed_validate (GParamSpec *pspec, GValue *value) { EggParamSpecFixed *fspec = EGG_PARAM_SPEC_FIXED (pspec); gint oval = EGG_FIXED_TO_INT (value->data[0].v_int); gint min, max, val; g_assert (EGG_IS_PARAM_SPEC_FIXED (pspec)); /* we compare the integer part of the value because the minimum * and maximum values cover just that part of the representation */ min = fspec->minimum; max = fspec->maximum; val = EGG_FIXED_TO_INT (value->data[0].v_int); val = CLAMP (val, min, max); if (val != oval) { value->data[0].v_int = val; return TRUE; } return FALSE; } static gint param_fixed_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { if (value1->data[0].v_int < value2->data[0].v_int) return -1; else return value1->data[0].v_int > value2->data[0].v_int; } GType egg_param_fixed_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { sizeof (EggParamSpecFixed), 16, param_fixed_init, EGG_TYPE_FIXED, NULL, param_fixed_set_default, param_fixed_validate, param_fixed_values_cmp, }; pspec_type = g_param_type_register_static (I_("EggParamSpecFixed"), &pspec_info); } return pspec_type; } /** * egg_param_spec_fixed: * @name: name of the property * @nick: short name * @blurb: description (can be translatable) * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * * Creates a #GParamSpec for properties using #EggFixed values * * Return value: the newly created #GParamSpec * * Since: 0.8 */ GParamSpec * egg_param_spec_fixed (const gchar *name, const gchar *nick, const gchar *blurb, EggUnit minimum, EggUnit maximum, EggUnit default_value, GParamFlags flags) { EggParamSpecFixed *fspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); fspec = g_param_spec_internal (EGG_TYPE_PARAM_FIXED, name, nick, blurb, flags); fspec->minimum = minimum; fspec->maximum = maximum; fspec->default_value = default_value; return G_PARAM_SPEC (fspec); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-fixed.h�����������������������������������������������������������������������������������0000644�0000156�0000165�00000025300�12704153542�013652� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * Tomas Frydrych <tf@openedhand.com> * * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _HAVE_EGG_FIXED_H #define _HAVE_EGG_FIXED_H #include <glib-object.h> G_BEGIN_DECLS /** * EggFixed: * * Fixed point number (16.16) */ typedef gint32 EggFixed; /** * EggAngle: * * Integer representation of an angle such that 1024 corresponds to * full circle (i.e., 2*Pi). */ typedef gint32 EggAngle; /* angle such that 1024 == 2*PI */ #define EGG_ANGLE_FROM_DEG(x) (EGG_FLOAT_TO_INT (((x) * 1024.0) / 360.0)) #define EGG_ANGLE_FROM_DEGF(x) (EGG_FLOAT_TO_INT (((float)(x) * 1024.0f) / 360.0f)) #define EGG_ANGLE_FROM_DEGX(x) (CFX_INT((((x)/360)*1024) + CFX_HALF)) #define EGG_ANGLE_TO_DEG(x) (((x) * 360.0)/ 1024.0) #define EGG_ANGLE_TO_DEGF(x) (((float)(x) * 360.0)/ 1024.0) #define EGG_ANGLE_TO_DEGX(x) (EGG_INT_TO_FIXED((x) * 45)/128) /* * some commonly used constants */ /** * CFX_Q: * * Size in bits of decimal part of floating point value. */ #define CFX_Q 16 /* Decimal part size in bits */ /** * CFX_ONE: * * 1.0 represented as a fixed point value. */ #define CFX_ONE (1 << CFX_Q) /* 1 */ /** * CFX_HALF: * * 0.5 represented as a fixed point value. */ #define CFX_HALF 32768 /** * CFX_MAX: * * Maximum fixed point value. */ #define CFX_MAX 0x7fffffff /** * CFX_MIN: * * Minimum fixed point value. */ #define CFX_MIN 0x80000000 /** * CFX_PI: * * Fixed point representation of Pi */ #define CFX_PI 0x0003243f /** * CFX_2PI: * * Fixed point representation of Pi*2 */ #define CFX_2PI 0x0006487f /** * CFX_PI_2: * * Fixed point representation of Pi/2 */ #define CFX_PI_2 0x00019220 /* pi/2 */ /** * CFX_PI_4: * * Fixed point representation of Pi/4 */ #define CFX_PI_4 0x0000c910 /* pi/4 */ /** * CFX_360: * * Fixed point representation of the number 360 */ #define CFX_360 EGG_INT_TO_FIXED (360) /** * CFX_240: * * Fixed point representation of the number 240 */ #define CFX_240 EGG_INT_TO_FIXED (240) /** * CFX_180: * * Fixed point representation of the number 180 */ #define CFX_180 EGG_INT_TO_FIXED (180) /** * CFX_120: * * Fixed point representation of the number 120 */ #define CFX_120 EGG_INT_TO_FIXED (120) /** * CFX_60: * * Fixed point representation of the number 60 */ #define CFX_60 EGG_INT_TO_FIXED (60) /** * CFX_RADIANS_TO_DEGREES: * * Fixed point representation of the number 180 / pi */ #define CFX_RADIANS_TO_DEGREES 0x394bb8 /** * CFX_255: * * Fixed point representation of the number 255 */ #define CFX_255 EGG_INT_TO_FIXED (255) /** * EGG_FIXED_TO_FLOAT: * @x: a fixed point value * * Convert a fixed point value to float. */ #define EGG_FIXED_TO_FLOAT(x) ((float) ((int)(x) / 65536.0)) /** * EGG_FIXED_TO_DOUBLE: * @x: a fixed point value * * Convert a fixed point value to double. */ #define EGG_FIXED_TO_DOUBLE(x) ((double) ((int)(x) / 65536.0)) /** * EGG_FLOAT_TO_FIXED: * @x: a floating point value * * Convert a float value to fixed. */ #define EGG_FLOAT_TO_FIXED(x) (egg_double_to_fixed ((x))) /** * EGG_FLOAT_TO_INT: * @x: a floating point value * * Convert a float value to int. */ #define EGG_FLOAT_TO_INT(x) (egg_double_to_int ((x))) /** * EGG_FLOAT_TO_UINT: * @x: a floating point value * * Convert a float value to unsigned int. */ #define EGG_FLOAT_TO_UINT(x) (egg_double_to_uint ((x))) /** * EGG_INT_TO_FIXED: * @x: an integer value * * Convert an integer value to fixed point. */ #define EGG_INT_TO_FIXED(x) ((x) << CFX_Q) /** * EGG_FIXED_TO_INT: * @x: a fixed point value * * Converts a fixed point value to integer (removing the decimal part). * * Since: 0.6 */ #define EGG_FIXED_TO_INT(x) ((x) >> CFX_Q) #ifndef EGG_DISABLE_DEPRECATED /** * EGG_FIXED_INT: * @x: a fixed point value * * Convert a fixed point value to integer (removing decimal part). * * Deprecated:0.6: Use %EGG_FIXED_TO_INT instead */ #define EGG_FIXED_INT(x) EGG_FIXED_TO_INT((x)) #endif /* !EGG_DISABLE_DEPRECATED */ /** * EGG_FIXED_FRACTION: * @x: a fixed point value * * Retrieves the fractionary part of a fixed point value */ #define EGG_FIXED_FRACTION(x) ((x) & ((1 << CFX_Q) - 1)) /** * EGG_FIXED_FLOOR: * @x: a fixed point value * * Round down a fixed point value to an integer. */ #define EGG_FIXED_FLOOR(x) (((x) >= 0) ? ((x) >> CFX_Q) \ : ~((~(x)) >> CFX_Q)) /** * EGG_FIXED_CEIL: * @x: a fixed point value * * Round up a fixed point value to an integer. */ #define EGG_FIXED_CEIL(x) (EGG_FIXED_FLOOR (x + 0xffff)) /** * EGG_FIXED_MUL: * @x: a fixed point value * @y: a fixed point value * * Multiply two fixed point values */ #define EGG_FIXED_MUL(x,y) ((x) >> 8) * ((y) >> 8) /** * EGG_FIXED_DIV: * @x: a fixed point value * @y: a fixed point value * * Divide two fixed point values */ #define EGG_FIXED_DIV(x,y) ((((x) << 8)/(y)) << 8) /* Some handy fixed point short aliases to avoid exessively long lines */ /* FIXME: Remove from public API */ /*< private >*/ #define CFX_INT EGG_FIXED_INT #define CFX_MUL EGG_FIXED_MUL #define CFX_DIV EGG_FIXED_DIV #define CFX_QMUL(x,y) egg_qmulx (x,y) #define CFX_QDIV(x,y) egg_qdivx (x,y) /*< public >*/ /* Fixed point math routines */ G_INLINE_FUNC EggFixed egg_qmulx (EggFixed op1, EggFixed op2); #if defined (G_CAN_INLINE) G_INLINE_FUNC EggFixed egg_qmulx (EggFixed op1, EggFixed op2) { #ifdef __arm__ int res_low, res_hi; __asm__ ("smull %0, %1, %2, %3 \n" "mov %0, %0, lsr %4 \n" "add %1, %0, %1, lsl %5 \n" : "=r"(res_hi), "=r"(res_low)\ : "r"(op1), "r"(op2), "i"(CFX_Q), "i"(32-CFX_Q)); return (EggFixed) res_low; #else long long r = (long long) op1 * (long long) op2; return (unsigned int)(r >> CFX_Q); #endif } #endif G_INLINE_FUNC EggFixed egg_qdivx (EggFixed op1, EggFixed op2); #if defined (G_CAN_INLINE) G_INLINE_FUNC EggFixed egg_qdivx (EggFixed op1, EggFixed op2) { return (EggFixed) ((((gint64) op1) << CFX_Q) / op2); } #endif EggFixed egg_sinx (EggFixed angle); EggFixed egg_sini (EggAngle angle); EggFixed egg_tani (EggAngle angle); EggFixed egg_atani (EggFixed x); EggFixed egg_atan2i (EggFixed y, EggFixed x); /* convenience macros for the cos functions */ /** * egg_cosx: * @angle: a #EggFixed angle in radians * * Fixed point cosine function * * Return value: #EggFixed cosine value. * * Note: Implemneted as a macro. * * Since: 0.2 */ #define egg_cosx(angle) (egg_sinx((angle) + CFX_PI_2)) /** * egg_cosi: * @angle: a #EggAngle angle * * Very fast fixed point implementation of cosine function. * * EggAngle is an integer such that 1024 represents * full circle. * * Return value: #EggFixed cosine value. * * Note: Implemneted as a macro. * * Since: 0.2 */ #define egg_cosi(angle) (egg_sini ((angle) + 256)) /** * EGG_SQRTI_ARG_MAX * * Maximum argument that can be passed to #egg_sqrti function. * * Since: 0.6 */ #ifndef __SSE2__ #define EGG_SQRTI_ARG_MAX 0x3fffff #else #define EGG_SQRTI_ARG_MAX INT_MAX #endif /** * EGG_SQRTI_ARG_5_PERCENT * * Maximum argument that can be passed to #egg_sqrti for which the * resulting error is < 5% * * Since: 0.6 */ #ifndef __SSE2__ #define EGG_SQRTI_ARG_5_PERCENT 210 #else #define EGG_SQRTI_ARG_5_PERCENT INT_MAX #endif /** * EGG_SQRTI_ARG_10_PERCENT * * Maximum argument that can be passed to #egg_sqrti for which the * resulting error is < 10% * * Since: 0.6 */ #ifndef __SSE2__ #define EGG_SQRTI_ARG_10_PERCENT 5590 #else #define EGG_SQRTI_ARG_10_PERCENT INT_MAX #endif EggFixed egg_sqrtx (EggFixed x); gint egg_sqrti (gint x); EggFixed egg_log2x (guint x); guint egg_pow2x (EggFixed x); guint egg_powx (guint x, EggFixed y); #define EGG_TYPE_FIXED (egg_fixed_get_type ()) #define EGG_TYPE_PARAM_FIXED (egg_param_fixed_get_type ()) #define EGG_PARAM_SPEC_FIXED(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), EGG_TYPE_PARAM_FIXED, EggParamSpecFixed)) #define EGG_IS_PARAM_SPEC_FIXED(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), EGG_TYPE_PARAM_FIXED)) /** * EGG_VALUE_HOLDS_FIXED: * @x: a #GValue * * Evaluates to %TRUE if @x holds a #EggFixed. * * Since: 0.8 */ #define EGG_VALUE_HOLDS_FIXED(x) (G_VALUE_HOLDS ((x), EGG_TYPE_FIXED)) typedef struct _EggParamSpecFixed EggParamSpecFixed; /** * EGG_MAXFIXED: * * Higher boundary for #EggFixed * * Since: 0.8 */ #define EGG_MAXFIXED CFX_MAX /** * EGG_MINFIXED: * * Lower boundary for #EggFixed * * Since: 0.8 */ #define EGG_MINFIXED CFX_MIN /** * EggParamSpecFixed * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * * #GParamSpec subclass for fixed point based properties * * Since: 0.8 */ struct _EggParamSpecFixed { /*< private >*/ GParamSpec parent_instance; /*< public >*/ EggFixed minimum; EggFixed maximum; EggFixed default_value; }; GType egg_fixed_get_type (void) G_GNUC_CONST; GType egg_param_fixed_get_type (void) G_GNUC_CONST; void egg_value_set_fixed (GValue *value, EggFixed fixed_); EggFixed egg_value_get_fixed (const GValue *value); GParamSpec * egg_param_spec_fixed (const gchar *name, const gchar *nick, const gchar *blurb, EggFixed minimum, EggFixed maximum, EggFixed default_value, GParamFlags flags); /* <private> */ extern EggFixed egg_double_to_fixed (double value); extern gint egg_double_to_int (double value); extern guint egg_double_to_unit (double value); G_END_DECLS #endif /* _HAVE_EGG_FIXED_H */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������./egg/egg-alpha.c�����������������������������������������������������������������������������������0000644�0000156�0000165�00000055765�12704153542�013655� 0����������������������������������������������������������������������������������������������������ustar �jenkins�������������������������jenkins����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum <mallum@openedhand.com> * Jorn Baayen <jorn@openedhand.com> * Emmanuele Bassi <ebassi@openedhand.com> * Tomas Frydrych <tf@openedhand.com> * * Copyright (C) 2006, 2007 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:egg-alpha * @short_description: A class for calculating an alpha value as a function * of time. * * #EggAlpha is a class for calculating an integer value between * 0 and %EGG_ALPHA_MAX_ALPHA as a function of time. You should * provide a #EggTimeline and bind it to the #EggAlpha object; * you should also provide a function returning the alpha value depending * on the position inside the timeline; this function will be executed * each time a new frame in the #EggTimeline is reached. Since the * alpha function is controlled by the timeline instance, you can pause * or stop the #EggAlpha from calling the alpha function by controlling * the #EggTimeline object. * * #EggAlpha is used to "drive" a #EggBehaviour instance. * * <figure id="alpha-functions"> * <title>Graphic representation of some alpha functions * * * * Since: 0.2 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "egg-alpha.h" #include "egg-hack.h" // #include "egg-marshal.h" // #include "egg-private.h" #include "egg-debug.h" G_DEFINE_TYPE (EggAlpha, egg_alpha, G_TYPE_INITIALLY_UNOWNED); struct _EggAlphaPrivate { EggTimeline *timeline; guint timeline_new_frame_id; guint32 alpha; GClosure *closure; }; enum { PROP_0, PROP_TIMELINE, PROP_ALPHA }; static void timeline_new_frame_cb (EggTimeline *timeline, guint current_frame_num, EggAlpha *alpha) { EggAlphaPrivate *priv = alpha->priv; /* Update alpha value and notify */ priv->alpha = egg_alpha_get_alpha (alpha); g_object_notify (G_OBJECT (alpha), "alpha"); } static void egg_alpha_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EggAlpha *alpha; alpha = EGG_ALPHA (object); switch (prop_id) { case PROP_TIMELINE: egg_alpha_set_timeline (alpha, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_alpha_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggAlpha *alpha; EggAlphaPrivate *priv; alpha = EGG_ALPHA (object); priv = alpha->priv; switch (prop_id) { case PROP_TIMELINE: g_value_set_object (value, priv->timeline); break; case PROP_ALPHA: g_value_set_uint (value, priv->alpha); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_alpha_finalize (GObject *object) { EggAlphaPrivate *priv = EGG_ALPHA (object)->priv; if (priv->closure) g_closure_unref (priv->closure); G_OBJECT_CLASS (egg_alpha_parent_class)->finalize (object); } static void egg_alpha_dispose (GObject *object) { EggAlpha *self = EGG_ALPHA(object); egg_alpha_set_timeline (self, NULL); G_OBJECT_CLASS (egg_alpha_parent_class)->dispose (object); } static void egg_alpha_class_init (EggAlphaClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = egg_alpha_set_property; object_class->get_property = egg_alpha_get_property; object_class->finalize = egg_alpha_finalize; object_class->dispose = egg_alpha_dispose; g_type_class_add_private (klass, sizeof (EggAlphaPrivate)); /** * EggAlpha:timeline: * * A #EggTimeline instance used to drive the alpha function. * * Since: 0.2 */ g_object_class_install_property (object_class, PROP_TIMELINE, g_param_spec_object ("timeline", "Timeline", "Timeline", EGG_TYPE_TIMELINE, EGG_PARAM_READWRITE)); /** * EggAlpha:alpha: * * The alpha value as computed by the alpha function. * * Since: 0.2 */ g_object_class_install_property (object_class, PROP_ALPHA, g_param_spec_uint ("alpha", "Alpha value", "Alpha value", 0, EGG_ALPHA_MAX_ALPHA, 0, EGG_PARAM_READABLE)); } static void egg_alpha_init (EggAlpha *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EGG_TYPE_ALPHA, EggAlphaPrivate); } /** * egg_alpha_get_alpha: * @alpha: A #EggAlpha * * Query the current alpha value. * * Return Value: The current alpha value for the alpha * * Since: 0.2 */ guint32 egg_alpha_get_alpha (EggAlpha *alpha) { EggAlphaPrivate *priv; guint32 retval = 0; g_return_val_if_fail (EGG_IS_ALPHA (alpha), 0); priv = alpha->priv; if (G_LIKELY (priv->closure)) { GValue params = { 0, }; GValue result_value = { 0, }; g_object_ref (alpha); g_value_init (&result_value, G_TYPE_UINT); g_value_init (¶ms, EGG_TYPE_ALPHA); g_value_set_object (¶ms, alpha); g_closure_invoke (priv->closure, &result_value, 1, ¶ms, NULL); retval = g_value_get_uint (&result_value); g_value_unset (&result_value); g_value_unset (¶ms); g_object_unref (alpha); } return retval; } /** * egg_alpha_set_closure: * @alpha: A #EggAlpha * @closure: A #GClosure * * Sets the #GClosure used to compute * the alpha value at each frame of the #EggTimeline * bound to @alpha. * * Since: 0.8 */ void egg_alpha_set_closure (EggAlpha *alpha, GClosure *closure) { EggAlphaPrivate *priv; g_return_if_fail (EGG_IS_ALPHA (alpha)); g_return_if_fail (closure != NULL); priv = alpha->priv; if (priv->closure) g_closure_unref (priv->closure); priv->closure = g_closure_ref (closure); g_closure_sink (closure); if (G_CLOSURE_NEEDS_MARSHAL (closure)) { GClosureMarshal marshal = egg_marshal_UINT__VOID; g_closure_set_marshal (closure, marshal); } } /** * egg_alpha_set_func: * @alpha: A #EggAlpha * @func: A #EggAlphaAlphaFunc * @data: user data to be passed to the alpha function, or %NULL * @destroy: notify function used when disposing the alpha function * * Sets the #EggAlphaFunc function used to compute * the alpha value at each frame of the #EggTimeline * bound to @alpha. * * Since: 0.2 */ void egg_alpha_set_func (EggAlpha *alpha, EggAlphaFunc func, gpointer data, GDestroyNotify destroy) { GClosure *closure; g_return_if_fail (EGG_IS_ALPHA (alpha)); g_return_if_fail (func != NULL); closure = g_cclosure_new (G_CALLBACK (func), data, (GClosureNotify) destroy); egg_alpha_set_closure (alpha, closure); } /** * egg_alpha_set_timeline: * @alpha: A #EggAlpha * @timeline: A #EggTimeline * * Binds @alpha to @timeline. * * Since: 0.2 */ void egg_alpha_set_timeline (EggAlpha *alpha, EggTimeline *timeline) { EggAlphaPrivate *priv; g_return_if_fail (EGG_IS_ALPHA (alpha)); g_return_if_fail (timeline == NULL || EGG_IS_TIMELINE (timeline)); priv = alpha->priv; if (priv->timeline) { g_signal_handlers_disconnect_by_func (priv->timeline, timeline_new_frame_cb, alpha); g_object_unref (priv->timeline); priv->timeline = NULL; } if (timeline) { priv->timeline = g_object_ref (timeline); g_signal_connect (priv->timeline, "new-frame", G_CALLBACK (timeline_new_frame_cb), alpha); } } /** * egg_alpha_get_timeline: * @alpha: A #EggAlpha * * Gets the #EggTimeline bound to @alpha. * * Return value: a #EggTimeline instance * * Since: 0.2 */ EggTimeline * egg_alpha_get_timeline (EggAlpha *alpha) { g_return_val_if_fail (EGG_IS_ALPHA (alpha), NULL); return alpha->priv->timeline; } /** * egg_alpha_new: * * Creates a new #EggAlpha instance. You must set a function * to compute the alpha value using egg_alpha_set_func() and * bind a #EggTimeline object to the #EggAlpha instance * using egg_alpha_set_timeline(). * * You should use the newly created #EggAlpha instance inside * a #EggBehaviour object. * * Return value: the newly created empty #EggAlpha instance. * * Since: 0.2 */ EggAlpha * egg_alpha_new (void) { return g_object_new (EGG_TYPE_ALPHA, NULL); } /** * egg_alpha_new_full: * @timeline: #EggTimeline timeline * @func: #EggAlphaFunc alpha function * @data: data to be passed to the alpha function * @destroy: notify to be called when removing the alpha function * * Creates a new #EggAlpha instance and sets the timeline * and alpha function. * * Return Value: the newly created #EggAlpha * * Since: 0.2 */ EggAlpha * egg_alpha_new_full (EggTimeline *timeline, EggAlphaFunc func, gpointer data, GDestroyNotify destroy) { EggAlpha *retval; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), NULL); g_return_val_if_fail (func != NULL, NULL); retval = egg_alpha_new (); egg_alpha_set_timeline (retval, timeline); egg_alpha_set_func (retval, func, data, destroy); return retval; } /** * EGG_ALPHA_RAMP_INC: * * Convenience symbol for egg_ramp_inc_func(). * * Since: 0.2 */ /** * egg_ramp_inc_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a monotonic increasing ramp. You * can use this function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.2 */ guint32 egg_ramp_inc_func (EggAlpha *alpha, gpointer dummy) { EggTimeline *timeline; gint current_frame_num, n_frames; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); return (current_frame_num * EGG_ALPHA_MAX_ALPHA) / n_frames; } /** * EGG_ALPHA_RAMP_DEC: * * Convenience symbol for egg_ramp_dec_func(). * * Since: 0.2 */ /** * egg_ramp_dec_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a monotonic decreasing ramp. You * can use this function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.2 */ guint32 egg_ramp_dec_func (EggAlpha *alpha, gpointer dummy) { EggTimeline *timeline; gint current_frame_num, n_frames; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); return (n_frames - current_frame_num) * EGG_ALPHA_MAX_ALPHA / n_frames; } /** * EGG_ALPHA_RAMP: * * Convenience symbol for egg_ramp_func(). * * Since: 0.2 */ /** * egg_ramp_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a full ramp function (increase for * half the time, decrease for the remaining half). You can use this * function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.2 */ guint32 egg_ramp_func (EggAlpha *alpha, gpointer dummy) { EggTimeline *timeline; gint current_frame_num, n_frames; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); if (current_frame_num > (n_frames / 2)) { return (n_frames - current_frame_num) * EGG_ALPHA_MAX_ALPHA / (n_frames / 2); } else { return current_frame_num * EGG_ALPHA_MAX_ALPHA / (n_frames / 2); } } static guint32 sincx1024_func (EggAlpha *alpha, EggAngle angle, EggFixed offset) { EggTimeline *timeline; gint current_frame_num, n_frames; EggAngle x; unsigned int sine; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = angle * current_frame_num / n_frames; x -= (512 * 512 / angle); sine = ((egg_sini (x) + offset)/2) * EGG_ALPHA_MAX_ALPHA; sine = sine >> CFX_Q; return sine; } #if 0 /* * The following two functions are left in place for reference * purposes. */ static guint32 sincx_func (EggAlpha *alpha, EggFixed angle, EggFixed offset) { EggTimeline *timeline; gint current_frame_num, n_frames; EggFixed x, sine; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = angle * current_frame_num / n_frames; x = EGG_FIXED_MUL (x, CFX_PI) - EGG_FIXED_DIV (CFX_PI, angle); sine = (egg_fixed_sin (x) + offset)/2; EGG_NOTE (ALPHA, "sine: %2f\n", EGG_FIXED_TO_DOUBLE (sine)); return EGG_FIXED_TO_INT (sine * EGG_ALPHA_MAX_ALPHA); } /* NB: angle is not in radians but in muliples of PI, i.e., 2.0 * represents full circle. */ static guint32 sinc_func (EggAlpha *alpha, float angle, float offset) { EggTimeline *timeline; gint current_frame_num, n_frames; gdouble x, sine; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); /* FIXME: fixed point, and fixed point sine() */ x = (gdouble) (current_frame_num * angle * G_PI) / n_frames ; sine = (sin (x - (G_PI / angle)) + offset) * 0.5f; EGG_NOTE (ALPHA, "sine: %2f\n",sine); return EGG_FLOAT_TO_INT ((sine * (gdouble) EGG_ALPHA_MAX_ALPHA)); } #endif /** * EGG_ALPHA_SINE: * * Convenience symbol for egg_sine_func(). * * Since: 0.2 */ /** * egg_sine_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a sine wave. You can use this * function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.2 */ guint32 egg_sine_func (EggAlpha *alpha, gpointer dummy) { #if 0 return sinc_func (alpha, 2.0, 1.0); #else /* 2.0 above represents full circle */ return sincx1024_func (alpha, 1024, CFX_ONE); #endif } /** * EGG_ALPHA_SINE_INC: * * Convenience symbol for egg_sine_inc_func(). * * Since: 0.2 */ /** * egg_sine_inc_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a sine wave over interval [0, pi / 2]. * You can use this function as the alpha function for * egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.2 */ guint32 egg_sine_inc_func (EggAlpha *alpha, gpointer dummy) { EggTimeline * timeline; gint frame; gint n_frames; EggAngle x; EggFixed sine; timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = 256 * frame / n_frames; sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA; return ((guint32)sine) >> CFX_Q; } /** * EGG_ALPHA_SINE_DEC: * * Convenience symbol for egg_sine_dec_func(). * * Since: 0.2 */ /** * egg_sine_dec_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a sine wave over interval [pi / 2, pi]. * You can use this function as the alpha function for * egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.4 */ guint32 egg_sine_dec_func (EggAlpha *alpha, gpointer dummy) { EggTimeline * timeline; gint frame; gint n_frames; EggAngle x; EggFixed sine; timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = 256 * frame / n_frames + 256; sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA; return ((guint32)sine) >> CFX_Q; } /** * EGG_ALPHA_SINE_HALF: * * Convenience symbol for egg_sine_half_func(). * * Since: 0.4 */ /** * egg_sine_half_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a sine wave over interval [0, pi]. * You can use this function as the alpha function for * egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.4 */ guint32 egg_sine_half_func (EggAlpha *alpha, gpointer dummy) { EggTimeline * timeline; gint frame; gint n_frames; EggAngle x; EggFixed sine; timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = 512 * frame / n_frames; sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA; return ((guint32)sine) >> CFX_Q; } /** * EGG_ALPHA_SQUARE: * * Convenience symbol for egg_square_func(). * * Since: 0.4 */ /** * egg_square_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a square wave. You can use this * function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value * * Since: 0.4 */ guint32 egg_square_func (EggAlpha *alpha, gpointer dummy) { EggTimeline *timeline; gint current_frame_num, n_frames; timeline = egg_alpha_get_timeline (alpha); current_frame_num = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); return (current_frame_num > (n_frames / 2)) ? EGG_ALPHA_MAX_ALPHA : 0; } /** * EGG_ALPHA_SMOOTHSTEP_INC: * * Convenience symbol for egg_smoothstep_inc_func(). * * Since: 0.4 */ /** * egg_smoothstep_inc_func: * @alpha: a #EggAlpha * @dummy: unused * * Convenience alpha function for a smoothstep curve. You can use this * function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value * * Since: 0.4 */ guint32 egg_smoothstep_inc_func (EggAlpha *alpha, gpointer dummy) { EggTimeline *timeline; gint frame; gint n_frames; guint32 r; guint32 x; /* * The smoothstep function uses f(x) = -2x^3 + 3x^2 where x is from <0,1>, * and precission is critical -- we use 8.24 fixed format for this operation. * The earlier operations involve division, which we cannot do in 8.24 for * numbers in <0,1> we use EggFixed. */ timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); /* * Convert x to 8.24 for next step. */ x = CFX_DIV (frame, n_frames) << 8; /* * f(x) = -2x^3 + 3x^2 * * Convert result to EggFixed to avoid overflow in next step. */ r = ((x >> 12) * (x >> 12) * 3 - (x >> 15) * (x >> 16) * (x >> 16)) >> 8; return CFX_INT (r * EGG_ALPHA_MAX_ALPHA); } /** * EGG_ALPHA_SMOOTHSTEP_DEC: * * Convenience symbol for egg_smoothstep_dec_func(). * * Since: 0.4 */ /** * egg_smoothstep_dec_func: * @alpha: a #EggAlpha * @dummy: unused * * Convenience alpha function for a downward smoothstep curve. You can use * this function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value * * Since: 0.4 */ guint32 egg_smoothstep_dec_func (EggAlpha *alpha, gpointer dummy) { return EGG_ALPHA_MAX_ALPHA - egg_smoothstep_inc_func (alpha, dummy); } /** * EGG_ALPHA_EXP_INC: * * Convenience symbol for egg_exp_inc_func() * * Since: 0.4 */ /** * egg_exp_inc_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a 2^x curve. You can use this function as the * alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.4 */ guint32 egg_exp_inc_func (EggAlpha *alpha, gpointer dummy) { EggTimeline * timeline; gint frame; gint n_frames; EggFixed x; EggFixed x_alpha_max = 0x100000; guint32 result; /* * Choose x_alpha_max such that * * (2^x_alpha_max) - 1 == EGG_ALPHA_MAX_ALPHA */ #if EGG_ALPHA_MAX_ALPHA != 0xffff #error Adjust x_alpha_max to match EGG_ALPHA_MAX_ALPHA #endif timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = x_alpha_max * frame / n_frames; result = CLAMP (egg_pow2x (x) - 1, 0, EGG_ALPHA_MAX_ALPHA); return result; } /** * EGG_ALPHA_EXP_DEC: * * Convenience symbold for egg_exp_dec_func(). * * Since: 0.4 */ /** * egg_exp_dec_func: * @alpha: a #EggAlpha * @dummy: unused argument * * Convenience alpha function for a decreasing 2^x curve. You can use this * function as the alpha function for egg_alpha_set_func(). * * Return value: an alpha value. * * Since: 0.4 */ guint32 egg_exp_dec_func (EggAlpha *alpha, gpointer dummy) { EggTimeline * timeline; gint frame; gint n_frames; EggFixed x; EggFixed x_alpha_max = 0x100000; guint32 result; /* * Choose x_alpha_max such that * * (2^x_alpha_max) - 1 == EGG_ALPHA_MAX_ALPHA */ #if EGG_ALPHA_MAX_ALPHA != 0xffff #error Adjust x_alpha_max to match EGG_ALPHA_MAX_ALPHA #endif timeline = egg_alpha_get_timeline (alpha); frame = egg_timeline_get_current_frame (timeline); n_frames = egg_timeline_get_n_frames (timeline); x = (x_alpha_max * (n_frames - frame)) / n_frames; result = CLAMP (egg_pow2x (x) - 1, 0, EGG_ALPHA_MAX_ALPHA); return result; } ./egg/egg-timeline.c0000644000015600001650000013414012704153542014357 0ustar jenkinsjenkins/* * Clutter. * * An OpenGL based 'interactive canvas' library. * * Authored By Matthew Allum * * Copyright (C) 2006 OpenedHand * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:egg-timeline * @short_description: A class for time-based events * * #EggTimeline is a base class for managing time based events such * as animations. * * Every timeline shares the same #EggTimeoutPool to decrease the * possibility of starving the main loop when using many timelines * at the same time; this might cause problems if you are also using * a library making heavy use of threads with no GLib main loop integration. * * In that case you might disable the common timeline pool by setting * the %EGG_TIMELINE=no-pool environment variable prior to launching * your application. * * One way to visualise a timeline is as a path with marks along its length. * When creating a timeline of @n_frames via egg_timeline_new(), then the * number of frames can be seen as the paths length, and each unit of length * (each frame) is delimited by a mark. * * For a non looping timeline there will be (n_frames + 1) marks along its * length. For a looping timeline, the two ends are joined with one mark. * Technically this mark represents two discrete frame numbers, but for a * looping timeline the start and end frame numbers are considered equivalent. * * When you create a timeline it starts with * egg_timeline_get_current_frame() == 0. * * After starting a timeline, the first timeout is for current_frame_num == 1 * (Notably it isn't 0 since there is a delay before the first timeout signals * so re-asserting the starting frame (0) wouldn't make sense.) * Notably, this implies that actors you intend to be affected by the * timeline's progress, should be manually primed/positioned for frame 0 which * will be displayed before the first timeout. (If you are not careful about * this point you will likely see flashes of incorrect actor state in your * program) * * For a non looping timeline the last timeout would be for * current_frame_num == @n_frames * * For a looping timeline the timeout for current_frame_num == @n_frames would * be followed by a timeout for current_frame_num == 1 (remember frame 0 is * considered == frame (@n_frames)). * * There may be times when a system is not able to meet the frame rate * requested for a timeline, and in this case the frame number will be * interpolated at the next timeout event. The interpolation is calculated from * the time that the timeline was started, not from the time of the last * timeout, so a given timeline should basically elapse in the same - real * world - time on any given system. An invariable here though is that * current_frame_num == @n_frames will always be signaled, but notably frame 1 * can be interpolated past and so never signaled. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "egg-timeout-pool.h" #include "egg-timeline.h" // #include "egg-main.h" // #include "egg-marshal.h" // #include "egg-private.h" #include "egg-hack.h" #include "egg-debug.h" // #include "egg-enum-types.h" G_DEFINE_TYPE (EggTimeline, egg_timeline, G_TYPE_OBJECT); #define FPS_TO_INTERVAL(f) (1000 / (f)) struct _EggTimelinePrivate { EggTimelineDirection direction; guint timeout_id; guint delay_id; gint current_frame_num; guint fps; guint n_frames; guint delay; gint skipped_frames; GTimeVal prev_frame_timeval; guint msecs_delta; GHashTable *markers_by_frame; GHashTable *markers_by_name; guint loop : 1; }; typedef struct { gchar *name; guint frame_num; GQuark quark; } TimelineMarker; enum { PROP_0, PROP_FPS, PROP_NUM_FRAMES, PROP_LOOP, PROP_DELAY, PROP_DURATION, PROP_DIRECTION }; enum { NEW_FRAME, STARTED, PAUSED, COMPLETED, MARKER_REACHED, LAST_SIGNAL }; static guint timeline_signals[LAST_SIGNAL] = { 0 }; static gint timeline_use_pool = -1; static EggTimeoutPool *timeline_pool = NULL; static inline void timeline_pool_init (void) { if (timeline_use_pool == -1) { const gchar *timeline_env; timeline_env = g_getenv ("EGG_TIMELINE"); if (timeline_env && timeline_env[0] != '\0' && strcmp (timeline_env, "no-pool") == 0) { timeline_use_pool = FALSE; } else { timeline_pool = egg_timeout_pool_new (EGG_PRIORITY_TIMELINE); timeline_use_pool = TRUE; } } } static guint timeout_add (guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify) { guint res; if (G_LIKELY (timeline_use_pool)) { g_assert (timeline_pool != NULL); res = egg_timeout_pool_add (timeline_pool, interval, func, data, notify); } else { #if 0 res = egg_threads_add_frame_source_full (EGG_PRIORITY_TIMELINE, interval, func, data, notify); #endif g_assert (G_LIKELY (timeline_use_pool)); /* ie, FAIL */ } return res; } static void timeout_remove (guint tag) { if (G_LIKELY (timeline_use_pool)) { g_assert (timeline_pool != NULL); egg_timeout_pool_remove (timeline_pool, tag); } else g_source_remove (tag); } static TimelineMarker * timeline_marker_new (const gchar *name, guint frame_num) { TimelineMarker *marker = g_slice_new0 (TimelineMarker); marker->name = g_strdup (name); marker->quark = g_quark_from_string (marker->name); marker->frame_num = frame_num; return marker; } static void timeline_marker_free (gpointer data) { if (G_LIKELY (data)) { TimelineMarker *marker = data; g_free (marker->name); g_slice_free (TimelineMarker, marker); } } /* Object */ static void egg_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EggTimeline *timeline; EggTimelinePrivate *priv; timeline = EGG_TIMELINE(object); priv = timeline->priv; switch (prop_id) { case PROP_FPS: egg_timeline_set_speed (timeline, g_value_get_uint (value)); break; case PROP_NUM_FRAMES: egg_timeline_set_n_frames (timeline, g_value_get_uint (value)); break; case PROP_LOOP: priv->loop = g_value_get_boolean (value); break; case PROP_DELAY: priv->delay = g_value_get_uint (value); break; case PROP_DURATION: egg_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_DIRECTION: egg_timeline_set_direction (timeline, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggTimeline *timeline; EggTimelinePrivate *priv; timeline = EGG_TIMELINE(object); priv = timeline->priv; switch (prop_id) { case PROP_FPS: g_value_set_uint (value, priv->fps); break; case PROP_NUM_FRAMES: g_value_set_uint (value, priv->n_frames); break; case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; case PROP_DELAY: g_value_set_uint (value, priv->delay); break; case PROP_DURATION: g_value_set_uint (value, egg_timeline_get_duration (timeline)); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void egg_timeline_finalize (GObject *object) { EggTimelinePrivate *priv = EGG_TIMELINE (object)->priv; g_hash_table_destroy (priv->markers_by_frame); g_hash_table_destroy (priv->markers_by_name); G_OBJECT_CLASS (egg_timeline_parent_class)->finalize (object); } static void egg_timeline_dispose (GObject *object) { EggTimeline *self = EGG_TIMELINE(object); EggTimelinePrivate *priv; priv = self->priv; if (priv->delay_id) { timeout_remove (priv->delay_id); priv->delay_id = 0; } if (priv->timeout_id) { timeout_remove (priv->timeout_id); priv->timeout_id = 0; } G_OBJECT_CLASS (egg_timeline_parent_class)->dispose (object); } static void egg_timeline_class_init (EggTimelineClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); timeline_pool_init (); object_class->set_property = egg_timeline_set_property; object_class->get_property = egg_timeline_get_property; object_class->finalize = egg_timeline_finalize; object_class->dispose = egg_timeline_dispose; g_type_class_add_private (klass, sizeof (EggTimelinePrivate)); /** * EggTimeline:fps: * * Timeline frames per second. Because of the nature of the main * loop used by Egg this is to be considered a best approximation. */ g_object_class_install_property (object_class, PROP_FPS, g_param_spec_uint ("fps", "Frames Per Second", "Timeline frames per second", 1, 1000, 60, EGG_PARAM_READWRITE)); /** * EggTimeline:num-frames: * * Total number of frames for the timeline. */ g_object_class_install_property (object_class, PROP_NUM_FRAMES, g_param_spec_uint ("num-frames", "Total number of frames", "Timelines total number of frames", 1, G_MAXUINT, 1, EGG_PARAM_READWRITE)); /** * EggTimeline:loop: * * Whether the timeline should automatically rewind and restart. */ g_object_class_install_property (object_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Should the timeline automatically restart", FALSE, EGG_PARAM_READWRITE)); /** * EggTimeline:delay: * * A delay, in milliseconds, that should be observed by the * timeline before actually starting. * * Since: 0.4 */ g_object_class_install_property (object_class, PROP_DELAY, g_param_spec_uint ("delay", "Delay", "Delay before start", 0, G_MAXUINT, 0, EGG_PARAM_READWRITE)); /** * EggTimeline:duration: * * Duration of the timeline in milliseconds, depending on the * EggTimeline:fps value. * * Since: 0.6 */ g_object_class_install_property (object_class, PROP_DURATION, g_param_spec_uint ("duration", "Duration", "Duration of the timeline in milliseconds", 0, G_MAXUINT, 1000, EGG_PARAM_READWRITE)); /** * EggTimeline:direction: * * The direction of the timeline, either %EGG_TIMELINE_FORWARD or * %EGG_TIMELINE_BACKWARD. * * Since: 0.6 */ g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("direction", "Direction", "Direction of the timeline", EGG_TYPE_TIMELINE_DIRECTION, EGG_TIMELINE_FORWARD, EGG_PARAM_READWRITE)); /** * EggTimeline::new-frame: * @timeline: the timeline which received the signal * @frame_num: the number of the new frame between 0 and * EggTimeline:num-frames * * The ::new-frame signal is emitted each time a new frame in the * timeline is reached. */ timeline_signals[NEW_FRAME] = g_signal_new ("new-frame", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTimelineClass, new_frame), NULL, NULL, egg_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); /** * EggTimeline::completed: * @timeline: the #EggTimeline which received the signal * * The ::completed signal is emitted when the timeline reaches the * number of frames specified by the EggTimeline:num-frames property. */ timeline_signals[COMPLETED] = g_signal_new ("completed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTimelineClass, completed), NULL, NULL, egg_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * EggTimeline::started: * @timeline: the #EggTimeline which received the signal * * The ::started signal is emitted when the timeline starts its run. * This might be as soon as egg_timeline_start() is invoked or * after the delay set in the EggTimeline:delay property has * expired. */ timeline_signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTimelineClass, started), NULL, NULL, egg_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * EggTimeline::paused: * @timeline: the #EggTimeline which received the signal * * The ::paused signal is emitted when egg_timeline_pause() is invoked. */ timeline_signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggTimelineClass, paused), NULL, NULL, egg_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * EggTimeline::marker-reached: * @timeline: the #EggTimeline which received the signal * @marker_name: the name of the marker reached * @frame_num: the frame number * * The ::marker-reached signal is emitted each time a timeline * reaches a marker set with egg_timeline_add_marker_at_frame() * or egg_timeline_add_marker_at_time(). This signal is * detailed with the name of the marker as well, so it is * possible to connect a callback to the ::marker-reached signal * for a specific marker with: * * * egg_timeline_add_marker_at_frame (timeline, "foo", 24); * egg_timeline_add_marker_at_frame (timeline, "bar", 48); * * g_signal_connect (timeline, "marker-reached", * G_CALLBACK (each_marker_reached), NULL); * g_signal_connect (timeline, "marker-reached::foo", * G_CALLBACK (foo_marker_reached), NULL); * g_signal_connect (timeline, "marker-reached::bar", * G_CALLBACK (bar_marker_reached), NULL); * * * In the example, the first callback will be invoked for both * the "foo" and "bar" marker, while the second and third callbacks * will be invoked for the "foo" or "bar" markers, respectively. * * Since: 0.8 */ timeline_signals[MARKER_REACHED] = g_signal_new ("marker-reached", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET (EggTimelineClass, marker_reached), NULL, NULL, egg_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT); } static void egg_timeline_init (EggTimeline *self) { EggTimelinePrivate *priv; self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EGG_TYPE_TIMELINE, EggTimelinePrivate); priv->fps = egg_get_default_frame_rate (); priv->n_frames = 0; priv->msecs_delta = 0; priv->markers_by_frame = g_hash_table_new (NULL, NULL); priv->markers_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, timeline_marker_free); } static gboolean timeline_timeout_func (gpointer data) { EggTimeline *timeline = data; EggTimelinePrivate *priv; GTimeVal timeval; guint n_frames; gulong msecs; priv = timeline->priv; g_object_ref (timeline); /* Figure out potential frame skips */ g_get_current_time (&timeval); EGG_TIMESTAMP (SCHEDULER, "Timeline [%p] activated (cur: %d)\n", timeline, priv->current_frame_num); if (!priv->prev_frame_timeval.tv_sec) { EGG_NOTE (SCHEDULER, "Timeline [%p] recieved timeout before being initialised!", timeline); priv->prev_frame_timeval = timeval; } /* Interpolate the current frame based on the timeval of the * previous frame */ msecs = (timeval.tv_sec - priv->prev_frame_timeval.tv_sec) * 1000; msecs += (timeval.tv_usec - priv->prev_frame_timeval.tv_usec) / 1000; priv->msecs_delta = msecs; n_frames = msecs / (1000 / priv->fps); if (n_frames == 0) n_frames = 1; priv->skipped_frames = n_frames - 1; if (priv->skipped_frames) EGG_TIMESTAMP (SCHEDULER, "Timeline [%p], skipping %d frames\n", timeline, priv->skipped_frames); priv->prev_frame_timeval = timeval; /* Advance frames */ if (priv->direction == EGG_TIMELINE_FORWARD) priv->current_frame_num += n_frames; else priv->current_frame_num -= n_frames; /* If we have not reached the end of the timeline: */ if (!( ((priv->direction == EGG_TIMELINE_FORWARD) && (priv->current_frame_num >= priv->n_frames)) || ((priv->direction == EGG_TIMELINE_BACKWARD) && (priv->current_frame_num <= 0)) )) { gint i; /* Fire off signal */ g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0, priv->current_frame_num); for (i = priv->skipped_frames; i >= 0; i--) { gint frame_num = priv->current_frame_num - i; GSList *markers, *l; markers = g_hash_table_lookup (priv->markers_by_frame, GUINT_TO_POINTER (frame_num)); for (l = markers; l; l = l->next) { TimelineMarker *marker = l->data; EGG_NOTE (SCHEDULER, "Marker `%s' reached", marker->name); g_signal_emit (timeline, timeline_signals[MARKER_REACHED], marker->quark, marker->name, marker->frame_num); } } /* Signal pauses timeline ? */ if (!priv->timeout_id) { g_object_unref (timeline); return FALSE; } g_object_unref (timeline); return TRUE; } else { /* Handle loop or stop */ EggTimelineDirection saved_direction = priv->direction; guint overflow_frame_num = priv->current_frame_num; gint end_frame; /* In case the signal handlers want to take a peek... */ if (priv->direction == EGG_TIMELINE_FORWARD) priv->current_frame_num = priv->n_frames; else if (priv->direction == EGG_TIMELINE_BACKWARD) priv->current_frame_num = 0; end_frame = priv->current_frame_num; /* Fire off signal */ g_signal_emit (timeline, timeline_signals[NEW_FRAME], 0, priv->current_frame_num); /* Did the signal handler modify the current_frame_num */ if (priv->current_frame_num != end_frame) { g_object_unref (timeline); return TRUE; } /* Note: If the new-frame signal handler paused the timeline * on the last frame we will still go ahead and send the * completed signal */ EGG_NOTE (SCHEDULER, "Timeline [%p] completed (cur: %d, tot: %d, drop: %d)", timeline, priv->current_frame_num, priv->n_frames, n_frames - 1); if (!priv->loop && priv->timeout_id) { /* We remove the timeout now, so that the completed signal handler * may choose to re-start the timeline * * ** Perhaps we should remove this earlier, and regardless * of priv->loop. Are we limiting the things that could be done in * the above new-frame signal handler */ timeout_remove (priv->timeout_id); priv->timeout_id = 0; } g_signal_emit (timeline, timeline_signals[COMPLETED], 0); /* Again check to see if the user has manually played with * current_frame_num, before we finally stop or loop the timeline */ if (priv->current_frame_num != end_frame && !(/* Except allow moving from frame 0 -> n_frame (or vica-versa) since these are considered equivalent */ (priv->current_frame_num == 0 && end_frame == priv->n_frames) || (priv->current_frame_num == priv->n_frames && end_frame == 0) )) { g_object_unref (timeline); return TRUE; } if (priv->loop) { /* We try and interpolate smoothly around a loop */ if (saved_direction == EGG_TIMELINE_FORWARD) priv->current_frame_num = overflow_frame_num - priv->n_frames; else priv->current_frame_num = priv->n_frames + overflow_frame_num; /* Or if the direction changed, we try and bounce */ if (priv->direction != saved_direction) { priv->current_frame_num = priv->n_frames - priv->current_frame_num; } g_object_unref (timeline); return TRUE; } else { egg_timeline_rewind (timeline); priv->prev_frame_timeval.tv_sec = 0; priv->prev_frame_timeval.tv_usec = 0; g_object_unref (timeline); return FALSE; } } } static guint timeline_timeout_add (EggTimeline *timeline, guint interval, GSourceFunc func, gpointer data, GDestroyNotify notify) { EggTimelinePrivate *priv; GTimeVal timeval; priv = timeline->priv; if (priv->prev_frame_timeval.tv_sec == 0) { g_get_current_time (&timeval); priv->prev_frame_timeval = timeval; } priv->skipped_frames = 0; priv->msecs_delta = 0; return timeout_add (interval, func, data, notify); } static gboolean delay_timeout_func (gpointer data) { EggTimeline *timeline = data; EggTimelinePrivate *priv = timeline->priv; priv->delay_id = 0; priv->timeout_id = timeline_timeout_add (timeline, FPS_TO_INTERVAL (priv->fps), timeline_timeout_func, timeline, NULL); g_signal_emit (timeline, timeline_signals[STARTED], 0); return FALSE; } /** * egg_timeline_start: * @timeline: A #EggTimeline * * Starts the #EggTimeline playing. **/ void egg_timeline_start (EggTimeline *timeline) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay_id || priv->timeout_id) return; if (priv->n_frames == 0) return; if (priv->delay) { priv->delay_id = timeout_add (priv->delay, delay_timeout_func, timeline, NULL); } else { priv->timeout_id = timeline_timeout_add (timeline, FPS_TO_INTERVAL (priv->fps), timeline_timeout_func, timeline, NULL); g_signal_emit (timeline, timeline_signals[STARTED], 0); } } /** * egg_timeline_pause: * @timeline: A #EggTimeline * * Pauses the #EggTimeline on current frame **/ void egg_timeline_pause (EggTimeline *timeline) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay_id) { timeout_remove (priv->delay_id); priv->delay_id = 0; } if (priv->timeout_id) { timeout_remove (priv->timeout_id); priv->timeout_id = 0; } priv->prev_frame_timeval.tv_sec = 0; priv->prev_frame_timeval.tv_usec = 0; g_signal_emit (timeline, timeline_signals[PAUSED], 0); } /** * egg_timeline_stop: * @timeline: A #EggTimeline * * Stops the #EggTimeline and moves to frame 0 **/ void egg_timeline_stop (EggTimeline *timeline) { egg_timeline_pause (timeline); egg_timeline_rewind (timeline); } /** * egg_timeline_set_loop: * @timeline: a #EggTimeline * @loop: %TRUE for enable looping * * Sets whether @timeline should loop. */ void egg_timeline_set_loop (EggTimeline *timeline, gboolean loop) { g_return_if_fail (EGG_IS_TIMELINE (timeline)); if (timeline->priv->loop != loop) { timeline->priv->loop = loop; g_object_notify (G_OBJECT (timeline), "loop"); } } /** * egg_timeline_get_loop: * @timeline: a #EggTimeline * * Gets whether @timeline is looping * * Return value: %TRUE if the timeline is looping */ gboolean egg_timeline_get_loop (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), FALSE); return timeline->priv->loop; } /** * egg_timeline_rewind: * @timeline: A #EggTimeline * * Rewinds #EggTimeline to the first frame if its direction is * EGG_TIMELINE_FORWARD and the last frame if it is * EGG_TIMELINE_BACKWARD. **/ void egg_timeline_rewind (EggTimeline *timeline) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction == EGG_TIMELINE_FORWARD) egg_timeline_advance (timeline, 0); else if (priv->direction == EGG_TIMELINE_BACKWARD) egg_timeline_advance (timeline, priv->n_frames); } /** * egg_timeline_skip: * @timeline: A #EggTimeline * @n_frames: Number of frames to skip * * Advance timeline by requested number of frames. **/ void egg_timeline_skip (EggTimeline *timeline, guint n_frames) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction == EGG_TIMELINE_FORWARD) { priv->current_frame_num += n_frames; if (priv->current_frame_num > priv->n_frames) priv->current_frame_num = 1; } else if (priv->direction == EGG_TIMELINE_BACKWARD) { priv->current_frame_num -= n_frames; if (priv->current_frame_num < 1) priv->current_frame_num = priv->n_frames - 1; } } /** * egg_timeline_advance: * @timeline: A #EggTimeline * @frame_num: Frame number to advance to * * Advance timeline to requested frame number **/ void egg_timeline_advance (EggTimeline *timeline, guint frame_num) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; priv->current_frame_num = CLAMP (frame_num, 0, priv->n_frames); } /** * egg_timeline_get_current_frame: * @timeline: A #EggTimeline * * Request the current frame number of the timeline. * * Return Value: current frame number **/ gint egg_timeline_get_current_frame (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); return timeline->priv->current_frame_num; } /** * egg_timeline_get_n_frames: * @timeline: A #EggTimeline * * Request the total number of frames for the #EggTimeline. * * Return Value: Number of frames for this #EggTimeline. **/ guint egg_timeline_get_n_frames (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); return timeline->priv->n_frames; } /** * egg_timeline_set_n_frames: * @timeline: a #EggTimeline * @n_frames: the number of frames * * Sets the total number of frames for @timeline */ void egg_timeline_set_n_frames (EggTimeline *timeline, guint n_frames) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (n_frames > 0); priv = timeline->priv; if (priv->n_frames != n_frames) { g_object_ref (timeline); g_object_freeze_notify (G_OBJECT (timeline)); priv->n_frames = n_frames; g_object_notify (G_OBJECT (timeline), "num-frames"); g_object_notify (G_OBJECT (timeline), "duration"); g_object_thaw_notify (G_OBJECT (timeline)); g_object_unref (timeline); } } /** * egg_timeline_set_speed: * @timeline: A #EggTimeline * @fps: New speed of timeline as frames per second * * Set the speed in frames per second of the timeline. **/ void egg_timeline_set_speed (EggTimeline *timeline, guint fps) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (fps > 0); priv = timeline->priv; if (priv->fps != fps) { g_object_ref (timeline); priv->fps = fps; /* if the timeline is playing restart */ if (priv->timeout_id) { timeout_remove (priv->timeout_id); priv->timeout_id = timeline_timeout_add (timeline, FPS_TO_INTERVAL (priv->fps), timeline_timeout_func, timeline, NULL); } g_object_freeze_notify (G_OBJECT (timeline)); g_object_notify (G_OBJECT (timeline), "duration"); g_object_notify (G_OBJECT (timeline), "fps"); g_object_thaw_notify (G_OBJECT (timeline)); g_object_unref (timeline); } } /** * egg_timeline_get_speed: * @timeline: a #EggTimeline * * Gets the frames per second played by @timeline * * Return value: the number of frames per second. */ guint egg_timeline_get_speed (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); return timeline->priv->fps; } /** * egg_timeline_is_playing: * @timeline: A #EggTimeline * * Query state of a #EggTimeline instance. * * Return Value: TRUE if timeline is currently playing, FALSE if not. */ gboolean egg_timeline_is_playing (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), FALSE); return (timeline->priv->timeout_id != 0); } /** * egg_timeline_clone: * @timeline: #EggTimeline to duplicate. * * Create a new #EggTimeline instance which has property values * matching that of supplied timeline. The cloned timeline will not * be started and will not be positioned to the current position of * @timeline: you will have to start it with egg_timeline_start(). * * Return Value: a new #EggTimeline, cloned from @timeline * * Since 0.4 */ EggTimeline * egg_timeline_clone (EggTimeline *timeline) { EggTimeline *copy; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), NULL); copy = g_object_new (EGG_TYPE_TIMELINE, "fps", egg_timeline_get_speed (timeline), "num-frames", egg_timeline_get_n_frames (timeline), "loop", egg_timeline_get_loop (timeline), "delay", egg_timeline_get_delay (timeline), "direction", egg_timeline_get_direction (timeline), NULL); return copy; } /** * egg_timeline_new_for_duration: * @msecs: Duration of the timeline in milliseconds * * Creates a new #EggTimeline with a duration of @msecs using * the value of the EggTimeline:fps property to compute the * equivalent number of frames. * * Return value: the newly created #EggTimeline * * Since: 0.6 */ EggTimeline * egg_timeline_new_for_duration (guint msecs) { return g_object_new (EGG_TYPE_TIMELINE, "duration", msecs, NULL); } /** * egg_timeline_new: * @n_frames: the number of frames * @fps: the number of frames per second * * Create a new #EggTimeline instance. * * Return Value: a new #EggTimeline */ EggTimeline* egg_timeline_new (guint n_frames, guint fps) { g_return_val_if_fail (n_frames > 0, NULL); g_return_val_if_fail (fps > 0, NULL); return g_object_new (EGG_TYPE_TIMELINE, "fps", fps, "num-frames", n_frames, NULL); } /** * egg_timeline_get_delay: * @timeline: a #EggTimeline * * Retrieves the delay set using egg_timeline_set_delay(). * * Return value: the delay in milliseconds. * * Since: 0.4 */ guint egg_timeline_get_delay (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); return timeline->priv->delay; } /** * egg_timeline_set_delay: * @timeline: a #EggTimeline * @msecs: delay in milliseconds * * Sets the delay, in milliseconds, before @timeline should start. * * Since: 0.4 */ void egg_timeline_set_delay (EggTimeline *timeline, guint msecs) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->delay != msecs) { priv->delay = msecs; g_object_notify (G_OBJECT (timeline), "delay"); } } /** * egg_timeline_get_duration: * @timeline: a #EggTimeline * * Retrieves the duration of a #EggTimeline in milliseconds. * See egg_timeline_set_duration(). * * Return value: the duration of the timeline, in milliseconds. * * Since: 0.6 */ guint egg_timeline_get_duration (EggTimeline *timeline) { EggTimelinePrivate *priv; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); priv = timeline->priv; return priv->n_frames * 1000 / priv->fps; } /** * egg_timeline_set_duration: * @timeline: a #EggTimeline * @msecs: duration of the timeline in milliseconds * * Sets the duration of the timeline, in milliseconds. The speed * of the timeline depends on the EggTimeline:fps setting. * * Since: 0.6 */ void egg_timeline_set_duration (EggTimeline *timeline, guint msecs) { EggTimelinePrivate *priv; guint n_frames; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; n_frames = msecs * priv->fps / 1000; if (n_frames < 1) n_frames = 1; egg_timeline_set_n_frames (timeline, n_frames); } /** * egg_timeline_get_progress: * @timeline: a #EggTimeline * * The position of the timeline in a [0, 1] interval. * * Return value: the position of the timeline. * * Since: 0.6 */ gdouble egg_timeline_get_progress (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0.); return EGG_FIXED_TO_DOUBLE (egg_timeline_get_progressx (timeline)); } /** * egg_timeline_get_progressx: * @timeline: a #EggTimeline * * Fixed point version of egg_timeline_get_progress(). * * Return value: the position of the timeline as a fixed point value * * Since: 0.6 */ EggFixed egg_timeline_get_progressx (EggTimeline *timeline) { EggTimelinePrivate *priv; EggFixed progress; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); priv = timeline->priv; progress = egg_qdivx (EGG_INT_TO_FIXED (priv->current_frame_num), EGG_INT_TO_FIXED (priv->n_frames)); if (priv->direction == EGG_TIMELINE_BACKWARD) progress = CFX_ONE - progress; return progress; } /** * egg_timeline_get_direction: * @timeline: a #EggTimeline * * Retrieves the direction of the timeline set with * egg_timeline_set_direction(). * * Return value: the direction of the timeline * * Since: 0.6 */ EggTimelineDirection egg_timeline_get_direction (EggTimeline *timeline) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), EGG_TIMELINE_FORWARD); return timeline->priv->direction; } /** * egg_timeline_set_direction: * @timeline: a #EggTimeline * @direction: the direction of the timeline * * Sets the direction of @timeline, either %EGG_TIMELINE_FORWARD or * %EGG_TIMELINE_BACKWARD. * * Since: 0.6 */ void egg_timeline_set_direction (EggTimeline *timeline, EggTimelineDirection direction) { EggTimelinePrivate *priv; g_return_if_fail (EGG_IS_TIMELINE (timeline)); priv = timeline->priv; if (priv->direction != direction) { priv->direction = direction; if (priv->current_frame_num == 0) priv->current_frame_num = priv->n_frames; g_object_notify (G_OBJECT (timeline), "direction"); } } /** * egg_timeline_get_delta: * @timeline: a #EggTimeline * @msecs: return location for the milliseconds elapsed since the last * frame, or %NULL * * Retrieves the number of frames and the amount of time elapsed since * the last EggTimeline::new-frame signal. * * This function is only useful inside handlers for the ::new-frame * signal, and its behaviour is undefined if the timeline is not * playing. * * Return value: the amount of frames elapsed since the last one * * Since: 0.6 */ guint egg_timeline_get_delta (EggTimeline *timeline, guint *msecs) { EggTimelinePrivate *priv; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), 0); if (!egg_timeline_is_playing (timeline)) { if (msecs) *msecs = 0; return 0; } priv = timeline->priv; if (msecs) *msecs = timeline->priv->msecs_delta; return priv->skipped_frames + 1; } static inline void egg_timeline_add_marker_internal (EggTimeline *timeline, const gchar *marker_name, guint frame_num) { EggTimelinePrivate *priv = timeline->priv; TimelineMarker *marker; GSList *markers; marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (G_UNLIKELY (marker)) { g_warning ("A marker named `%s' already exists on frame %d", marker->name, marker->frame_num); return; } marker = timeline_marker_new (marker_name, frame_num); g_hash_table_insert (priv->markers_by_name, marker->name, marker); markers = g_hash_table_lookup (priv->markers_by_frame, GUINT_TO_POINTER (frame_num)); if (!markers) { markers = g_slist_prepend (NULL, marker); g_hash_table_insert (priv->markers_by_frame, GUINT_TO_POINTER (frame_num), markers); } else { markers = g_slist_prepend (markers, marker); g_hash_table_replace (priv->markers_by_frame, GUINT_TO_POINTER (frame_num), markers); } } /** * egg_timeline_add_marker_at_frame: * @timeline: a #EggTimeline * @marker_name: the unique name for this marker * @frame_num: the marker's frame * * Adds a named marker at @frame_num. Markers are unique string identifiers * for a specific frame. Once @timeline reaches @frame_num, it will emit * a ::marker-reached signal for each marker attached to that frame. * * A marker can be removed with egg_timeline_remove_marker(). The * timeline can be advanced to a marker using * egg_timeline_advance_to_marker(). * * Since: 0.8 */ void egg_timeline_add_marker_at_frame (EggTimeline *timeline, const gchar *marker_name, guint frame_num) { g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); g_return_if_fail (frame_num <= egg_timeline_get_n_frames (timeline)); egg_timeline_add_marker_internal (timeline, marker_name, frame_num); } /** * egg_timeline_add_marker_at_time: * @timeline: a #EggTimeline * @marker_name: the unique name for this marker * @msecs: position of the marker in milliseconds * * Time-based variant of egg_timeline_add_marker_at_frame(). * * Adds a named marker at @msecs. * * Since: 0.8 */ void egg_timeline_add_marker_at_time (EggTimeline *timeline, const gchar *marker_name, guint msecs) { guint frame_num; g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); g_return_if_fail (msecs <= egg_timeline_get_duration (timeline)); frame_num = msecs * timeline->priv->fps / 1000; egg_timeline_add_marker_internal (timeline, marker_name, frame_num); } /** * egg_timeline_list_markers: * @timeline: a #EggTimeline * @frame_num: the frame number to check, or -1 * @n_markers: the number of markers returned * * Retrieves the list of markers at @frame_num. If @frame_num is a * negative integer, all the markers attached to @timeline will be * returned. * * Return value: a newly allocated, %NULL terminated string array * containing the names of the markers. Use g_strfreev() when * done. * * Since: 0.8 */ gchar ** egg_timeline_list_markers (EggTimeline *timeline, gint frame_num, gsize *n_markers) { EggTimelinePrivate *priv; gchar **retval = NULL; gsize i; g_return_val_if_fail (EGG_IS_TIMELINE (timeline), NULL); priv = timeline->priv; if (frame_num < 0) { GList *markers, *l; markers = g_hash_table_get_keys (priv->markers_by_name); retval = g_new0 (gchar*, g_list_length (markers) + 1); for (i = 0, l = markers; l != NULL; i++, l = l->next) retval[i] = g_strdup (l->data); g_list_free (markers); } else { GSList *markers, *l; markers = g_hash_table_lookup (priv->markers_by_frame, GUINT_TO_POINTER (frame_num)); retval = g_new0 (gchar*, g_slist_length (markers) + 1); for (i = 0, l = markers; l != NULL; i++, l = l->next) retval[i] = g_strdup (((TimelineMarker *) l->data)->name); } if (n_markers) *n_markers = i; return retval; } /** * egg_timeline_advance_to_marker: * @timeline: a #EggTimeline * @marker_name: the name of the marker * * Advances @timeline to the frame of the given @marker_name. * * Since: 0.8 */ void egg_timeline_advance_to_marker (EggTimeline *timeline, const gchar *marker_name) { EggTimelinePrivate *priv; TimelineMarker *marker; g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); priv = timeline->priv; marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (!marker) { g_warning ("No marker named `%s' found.", marker_name); return; } egg_timeline_advance (timeline, marker->frame_num); } /** * egg_timeline_remove_marker: * @timeline: a #EggTimeline * @marker_name: the name of the marker to remove * * Removes @marker_name, if found, from @timeline. * * Since: 0.8 */ void egg_timeline_remove_marker (EggTimeline *timeline, const gchar *marker_name) { EggTimelinePrivate *priv; TimelineMarker *marker; GSList *markers; g_return_if_fail (EGG_IS_TIMELINE (timeline)); g_return_if_fail (marker_name != NULL); priv = timeline->priv; marker = g_hash_table_lookup (priv->markers_by_name, marker_name); if (!marker) { g_warning ("No marker named `%s' found.", marker_name); return; } /* remove from the list of markers at the same frame */ markers = g_hash_table_lookup (priv->markers_by_frame, GUINT_TO_POINTER (marker->frame_num)); if (G_LIKELY (markers)) { markers = g_slist_remove (markers, marker); if (!markers) { /* no markers left, remove the slot */ g_hash_table_remove (priv->markers_by_frame, GUINT_TO_POINTER (marker->frame_num)); } else g_hash_table_replace (priv->markers_by_frame, GUINT_TO_POINTER (marker->frame_num), markers); } else { /* uh-oh, dangling marker; this should never happen */ g_warning ("Dangling marker %s at frame %d", marker->name, marker->frame_num); } /* this will take care of freeing the marker as well */ g_hash_table_remove (priv->markers_by_name, marker_name); } /** * egg_timeline_has_marker: * @timeline: a #EggTimeline * @marker_name: the name of the marker * * Checks whether @timeline has a marker set with the given name. * * Return value: %TRUE if the marker was found * * Since: 0.8 */ gboolean egg_timeline_has_marker (EggTimeline *timeline, const gchar *marker_name) { g_return_val_if_fail (EGG_IS_TIMELINE (timeline), FALSE); g_return_val_if_fail (marker_name != NULL, FALSE); return NULL != g_hash_table_lookup (timeline->priv->markers_by_name, marker_name); } ./AUTHORS0000644000015600001650000000144712704153542012156 0ustar jenkinsjenkinsDevelopment lead: - Mirco "MacSlow" Mueller Additional development: - David Barth Contributors (in no particular order): - Frederic "fredp" Peters - Eitan Isaacson - Neil J. Patel - Chow Loong Jin - Abhishek Mukherjee - Aurélien Gâteau - Ted Gould - Bastian "hadess" Nocera - Alexander Sack - Karl Lattimer - Martin Pitt - Michael Terry - Tony Wang - Peter Clifton - John Ledbetter ./m4/0000755000015600001650000000000012704153542011420 5ustar jenkinsjenkins./m4/python.m40000644000015600001650000000345212704153542013207 0ustar jenkinsjenkins## this one is commonly used with AM_PATH_PYTHONDIR ... dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) dnl Check if a module containing a given symbol is visible to python. AC_DEFUN([AM_CHECK_PYMOD], [AC_REQUIRE([AM_PATH_PYTHON]) py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ ifelse([$2],[], [prog=" import sys try: import $1 except ImportError: sys.exit(1) except: sys.exit(0) sys.exit(0)"], [prog=" import $1 $1.$2"]) if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC then eval "py_cv_mod_$py_mod_var=yes" else eval "py_cv_mod_$py_mod_var=no" fi ]) py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` if test "x$py_val" != xno; then AC_MSG_RESULT(yes) ifelse([$3], [],, [$3 ])dnl else AC_MSG_RESULT(no) ifelse([$4], [],, [$4 ])dnl fi ]) dnl a macro to check for ability to create python extensions dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) dnl function also defines PYTHON_INCLUDES AC_DEFUN([AM_CHECK_PYTHON_HEADERS], [AC_REQUIRE([AM_PATH_PYTHON]) AC_MSG_CHECKING(for headers required to compile python extensions) dnl deduce PYTHON_INCLUDES py_prefix=`$PYTHON -c "import sys; print sys.prefix"` py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" if test "$py_prefix" != "$py_exec_prefix"; then PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" fi AC_SUBST(PYTHON_INCLUDES) dnl check if the headers exist: save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" AC_TRY_CPP([#include ],dnl [AC_MSG_RESULT(found) $1],dnl [AC_MSG_RESULT(not found) $2]) CPPFLAGS="$save_CPPFLAGS" ]) ./configure.in0000644000015600001650000001007412704153542013413 0ustar jenkinsjenkinsAC_INIT(notify-osd, 0.9.34, dx-team@canonical.com) AC_CONFIG_SRCDIR(src/main.c) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) GNOME_COMMON_INIT GNOME_COMPILE_WARNINGS(maximum) AM_MAINTAINER_MODE AM_DISABLE_STATIC AM_PROG_LIBTOOL AC_SUBST(ACLOCAL_AMFLAGS, "$ACLOCAL_FLAGS -I m4") AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_INSTALL # # pkg-config # PKG_PROG_PKG_CONFIG # # use all the GSettings-magic # GLIB_GSETTINGS # # glib, we need 2.16.0 for the unit-tests # PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.36.0 gthread-2.0 gio-2.0]) # # libwnck used by the dnd code # PKG_CHECK_MODULES([WNCK], [libwnck-3.0]) AC_CHECK_LIB(wnck-3,wnck_shutdown, have_wnck_shutdown=yes,) if test "$have_wnck_shutdown" = "yes"; then AC_DEFINE(HAVE_WNCK_SHUTDOWN, 1, [Define to 1 if libwnck provides wnck_shutdown()]) fi # # libnotify, used unit-tests # PKG_CHECK_MODULES([LIBNOTIFY], [libnotify >= 0.4.5]) # # dbus # PKG_CHECK_MODULES([DBUS], [dbus-glib-1 >= 0.76]) DBUS_GLIB_BIN="`$PKG_CONFIG --variable=exec_prefix dbus-glib-1`/bin" AC_SUBST(DBUS_GLIB_BIN) # # libX11 # # # Gnome/GTK checks # PKG_CHECK_MODULES([X], [x11]) AC_SUBST(X_CFLAGS) AC_SUBST(X_LIBS) AM_PATH_GTK_3_0 PKG_CHECK_MODULES([NOTIFY_OSD], [pixman-1 gtk+-3.0 >= 3.8.0]) AC_SUBST(NOTIFY_OSD_CFLAGS) AC_SUBST(NOTIFY_OSD_LIBS) # # libm # AC_CHECK_LIBM AC_SUBST(LIBM) # # checks for building C- or C#-examples # AC_DEFUN([CHECK_FOR_MONO_STUFF], [ NAME="gmcs" AC_PATH_PROG(GMCS, $NAME, no) AC_SUBST(GMCS) if test "x$GMCS" = "xno"; then AC_MSG_ERROR([You need to install '$NAME']) fi NAME="Mono.Posix" AC_MSG_CHECKING([for Mono 2.0 GAC $NAME.dll]) if test -e "$(pkg-config --variable=libdir mono)/mono/2.0/$NAME.dll"; then AC_MSG_RESULT([found]) else AC_MSG_RESULT([not found]) AC_MSG_ERROR([missing reqired Mono 2.0 assembly $NAME.dll]) fi NAME="notify-sharp" AC_MSG_CHECKING([for Mono 2.0 CIL $NAME]) pkg-config --exists $NAME if test "$?" == "0" then AC_MSG_RESULT([found]) else AC_MSG_RESULT([not found]) AC_MSG_ERROR([missing reqired Mono 2.0 CIL $NAME]) fi ]) AC_ARG_WITH(examples, [ --with-examples=[[all/c/mono]] build C or C#-examples using libnotify demonstrating special features of notify-osd there are Python-examples too, but they don't need to be build]) c_examples=no csharp_examples=no if test "x$with_examples" = "xc"; then c_examples=yes AC_MSG_NOTICE([Build with ANSI-C examples]) fi if test "x$with_examples" = "xmono"; then CHECK_FOR_MONO_STUFF csharp_examples=yes AC_MSG_NOTICE([Build with C-sharp examples]) fi if test "x$with_examples" = "xall"; then CHECK_FOR_MONO_STUFF c_examples=yes csharp_examples=yes AC_MSG_NOTICE([Build with ANSI-C examples]) AC_MSG_NOTICE([Build with C-sharp examples]) fi AM_CONDITIONAL(BUILD_C_EXAMPLES, test "x$c_examples" != "xno") AM_CONDITIONAL(BUILD_MONO_EXAMPLES, test "x$csharp_examples" != "xno") dnl CFLAGS CFLAGS="$CFLAGS -Wall" AC_ARG_ENABLE([deprecations], [AS_HELP_STRING([--enable-deprecations], [allow deprecated API usage @<:@default=yes@:>@])], [], [enable_deprecations=yes]) AS_IF([test "x$enable_deprecations" = xno], [CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE"] ) AC_OUTPUT([ Makefile src/Makefile tests/Makefile examples/Makefile data/Makefile data/icons/Makefile data/icons/scalable/Makefile ]) echo "" echo " Notify OSD $VERSION" echo " ============================" echo "" echo " prefix: ${prefix}" echo "" echo " Build C Examples: ${c_examples}" echo "" echo " Build C# Examples: ${csharp_examples}" echo "" ./icons/0000755000015600001650000000000012704153542012213 5ustar jenkinsjenkins./icons/wifi-100.svg0000644000015600001650000000703412704153542014174 0ustar jenkinsjenkins ./icons/chat.svg0000644000015600001650000000277312704153542013664 0ustar jenkinsjenkins ./icons/avatar.png0000644000015600001650000003626412704153542014212 0ustar jenkinsjenkinsPNG  IHDR>asRGBbKGD pHYs$$P$tIME 01 IDATx}Ys$uw2k߫5fIS(/'Y Wu<>%c78t`8<{3 R/lzq$ +'Xdd2Q{5=σrr(XZZMH&Hyh4d2roab8b<OExnd+++z"na"L`A~LmJl{} fvL$k(e|0$Br35q1:;T*9J%A\.L&qP(p,h4prYbD' 5ړ&Nv?P p @jqqѸUcg@Jz.8Fvj̧d2JjL&D"\.7%ݣFx\HRr' 1*y_A"@VC^s駟 O~[10 ]cD&X* F#b1y1nE @~w5H$P,rT*%.z٬J1h6<$f!3yl 7Zod\ױF!ē;5gc6(,UL&eQ|Y64ɞGRA"@2Dzb;8XX NGl yNNv{ N0 nP^x<3.9g 7YP@.t)aRp]W~An=jV_rBNnW oggDT .\h4yz8<4 `0@&A>p8dYrv-^6~n;xR)d2Z-)" nyf9iO;gLf\ L&}z= CلT*%&#cx7O-u5'}opZyh Ҟon) T* /` 'y{{zHJD,I&n1?'^wE AtT'x;jc4h~!S>FřLF<_z`< RFLK 0@:[s&0D"Ϧv>6QJi:WTg2 2ln<Lfrit2X,\.'$Aj(edZ-r9  ) 0+#8K AX9tu<K?L#|0 v-P%S@UȃڋΒ6_f́)@;Iϣ(n;k^Z-i&fXUd2A*B>GՒ0Z0[=(sY>m^'B$,$ah`4IHw" tӳkyтgqsFbZeݞJTF0 Q.y@Ǿ|1̔y?:@xxx<~/euH$du~|< 8CJg T*Pq~ t^#`} ^kh4AaXXX@|> lYȬaT2D.y7WqTnipwQM$J'4>^,RR^z b}zvwwQ,DZCAdYdYaii |^ID&P:pxxFx[nl ynn 5v]h˵wW͜r3y6S_["pfqUF^z X^^FA\HڵkGZEX<:Q0pbyY$2aR-LT*ի_V ᥗ^B,~3lmm{HHa7_}nx5!kO* X^^VVVPT!*jX\\ҥKIt<\ETBXD*77"sp &P(`www:^{5 TU?\~BFqBDT%Dy'&}y:vNuBa8zJ&u666pcV~~ F?=Bmh7.Y(ޙ~3m3\]]wy_W1uEaE TU+`*BXD. %dql!|##Ub}}X]]͛7m,..&>s3çM'&6ծ3xwyyT NG6}ee.\0 Q<& 6660 UWt 9]hZ>@mjP,ӟV rDT*XYYo lnn (4}9ǑlV (^uJ%QϤask.]&"ժtE:FT^;6JCWD}xݮf!kH$իrRn޼[nagg\V;Q/\+++xʼn[]]ƍ8<իWܫP(ѣG(A"W,h&Ѭ%!vp}!չ~uJp%d28 looÇz= )HiۈzCĥK} ޹hHGG+[O7 clFuϣŋG 7 Nc/_^#͢~P~}tZ*iBM`k##_"B\6ũB 2G^Sj< (%"0,qyb1ܸq.ug X\FZl8A"nߺ|!]eimx'$M)XIBNa/$.s}dY C=!* \d2f|>^t:\.'9:677jJ"ahzm^ 0 ŋF6ORI8LTe0;8F4ʊl?>=zNd"\6 N:}]>Mj.2͛X____?0777PT"M>Nc0drxWu϶P KP( H&$Ft:HRlq/X__Zk׮!NVRbggG0p0/RPb`{"6<Cu7MܻwHP2 Jy!,♚jEdS{_#ŨT*x嗑5p8DA,;͢V!ckk DV 8<;0`Ck׮X,JU@\.p]W:vA=V!aeejUu@^!0\Z@R#pa' 2 P%zܫT*I˨VVK6{FC==S800zjxJ& :2 >Cuz=L&$IZ$\h^ҲV%xB2DX&L hr2XY4zT`4X(w~wynݺ~xVA(-h! .Dm?/E@;E~ww ˡ!O?qt rT~xx>aJO"zl)J&X@dm5Os!cyo&*~W~o4R0"zY!=x0L• KȣGey `yyz]N#9ED"!.=wn4O@X8%|}F\N>`0H|_#, =_*h4yaA\xAQٿ' !tvx@9 Z Z  q-,,)/ S0TX ^C܋Ɠ|խnt$!m_VprG$ xyQs/׸`0ޝ4o%P(S(t: 7JlMJmìTИNL%qO$V-x,|xRRH~~ >Q['yB0ڥv4V0Q(:{.!=z$%8 0u 0qN6T9Feӧv, T*SEhEԧI OaߨQ$b_2DݻwaQ% 8rĜ+Ev Q 5uZa k DH`0Ǣ Gп@{]dz./^͝qyZ@' KuӜzۮB!MT H9G@ouSMQ/kgML,13Qs=a!ѣGE,C& >ә׌rғpCE:~OKy& gn+ӷ`cy1Bs$fzvN  ]O>n~;;;݅(JX\\bTXΟ聘z:F}!g.e#RòGΣ`8NuDב | c00 ` 5891l6n?>O8єe;-\?`kJ {* ^:T*uB1j۶4-H'g6 $9C&.q<:Q#'_G 80,BO%:>>Cz=át#GU@*5zB*K؂;7F#LGBFM i;#ElmmM5p{}Qk|L&_r34!JZ&dnD6J/å!"pJ]m0#KЖt7W^+I%xfst(D qBan<w20>~$QF:kXajI%I#LF`<Ox{j&I&((͛7o %dp4bg=X4e@2(Nυad2y>zhT/|2pppz.|:~IؼSqn\3Ǡcqܼyo">S<|ZM\.'tPO ?j eEajU?q>XDApnnjesl5 ҳ XlLTJjh&~!Q9v卮.Y?7| |2qvTS(7*_M)\xE >+7DPヒ>,2aï? vdd6S=g2i2)cޟv 5Zo"/?$I,S8JşfOKMBqm{b)yi.$h$œ7V< ~:^~ecR}Zg_.KXj=N\n$l|q+++(Rڦɝb#q>ꞅDUI~KR\i{wss3r5?dVVVg Ō?p8q:F.G7e naMlooc4!NiF"0F5,ej [У~>Du5m꼣;Υid2d2X[[Ly)%cm=I؄ CN6kt:hH*~moo#K:v"u]*ޟH!ScO:)ۓv,CRAP.aXu i + `0Vtdmx_ M"aJah"ԏ8@*P7*ޏJ G 'ɓvi'i^`/C:pRMtmoߖz1*eXH,& wFTZu{]䣊Rfx0p }t0ga< =sF@ӑ177'*ݻsZ677tc$l:b 5m>}Z677vίti4I}ϖC'{7LK7NQ* ښl lBOlm`VjdmRT!XNI CqLTͪ4JH48gTieHxe)rT*0sii oFٔ09R_?Aׂ-hݮ<:z й|M0фNm.1F&dRH/ib6)ػOXO+vyRt+aii :~ӟJ-Br]}f^ygJ|>/ :~յDb-}O?~.ãVE|^ںF<>jnDQۋfrzppbEk4W(Uk687jw{|P˜8IS} Cae<|p1#ȍci?(<=ժ^|7zߗI<ܜhH3}~\N込ړeYU>Dž p) څ)'tf )X,J*Y Q]7qD"B˗/cccCm4{VK$b :gΚgJP˥R)a04 M&9giIgNK'+*G&=@~.v󩨖4v,sZtnϴȱ/k i}]E. 5vg6\gNu>6Ԯ4PD;҈b )+?I3'j) F2" aUM!*?$"AY>6FFBmF`d0'5(Aj.Gg|zir X\\ܜ@=lDU{v'Ww86a<4٫O %k6UȱԌY~-ۡZ7IPWUlooKgYyx".^B ݦ慎ݎ] zCIa$ 5Z@DkF~} 2 NS*MfQ3N sf,ÍJNڵkX]]1맲n%yT*1Ngq4m5(044Q: d]E4tmon9K_x]Ѽ*^}H4 *14juF7f7nP('?вVq\"^gw-djj<$#}Y:h4Nvw j;ӽ5oO B4Oi:wj Fm,b%l%K/!G}$r dX#k8ܘ1/ J''$FGsSCPaBv50 4zMPDDav/4|VqYD" P*0??/-666p]ܽ{W]t kkkrt5}v l6.R*%s(QK]^٪T+Oy(=% miTS RT`3h6dH0o4akkKl&3xd\gsŘqQmS&T1>5t4U 4 6CWPpUݖpv0d̵iycG=c@S3}gsl`VYwTo#dZvZsbr(ooOBxmjTYA>—d|>?E2dB1驨ZV3 D) XSlTkdVϺlFczyR54knչu=B]fNlC?v-`ZS& 4c3+ AꫂeQZV6JHAoM%Ӭ{g%#@M \O8SWɤ%j!M(eHUJ}_0&D1>@L@0 |acJ-6'Qstj[w "I]׿uy]8C`8`c>V juJd/"&zޔ_j]8rEܻwoJD0 }ć1f8 00iAs)ID.%u\thlIwimBL&nOP!,̦qʦruɸ֩QVζv^H$pxx(#uΗΎZ*l6ELM&uoaӿsN(A{0=BW9DFt }l&|/dr}<zIp/Lĥc:FRۨjS]ENcΪ lb<cnnNhoDTwP1I($9T .{ҙf^'Ys*MZkz?0XvןƘƘa8^PatzW<^ƴ,\?rƍc YÎ{ Rj^ 9A\tZ{%Hwm6yP*P,Q(P(ҥKSq<`8@E&{ćx8EO9Ǫ? L&0 \y6|vTe???xA|s7abq$b8N j[x t,~:ƷAѭg`j3EOSR~y?c u]TUG?^ .$Kյ&h$Hȴ'81c7?6;@?aĜX* Co<ʭMzyS xH8CqL$1d{FD!5 .jGF>Gј*Hq q@4gJ͛wvvv5P(`ggr ;x5h<+ 00c:a#3_3!ÿ˿2  hؘGtR.ԑO5LHW)gjVeCtȥBP(t8 bדY,fwuhZR bnnnvjQ*s"oQ' Ya0[̺y0ZIENDB`./icons/wifi-lost.svg0000644000015600001650000000657012704153542014661 0ustar jenkinsjenkins ./icons/wifi-75.svg0000644000015600001650000000714612704153542014133 0ustar jenkinsjenkins ./icons/avatar.svg0000644000015600001650000000422312704153542014213 0ustar jenkinsjenkins image/svg+xml ./TODO0000644000015600001650000000014112704153542011564 0ustar jenkinsjenkinsTODO * remove the bubble->visible attribute and turn the method calls into gdk_window_is_visible./data/0000755000015600001650000000000012704153542012011 5ustar jenkinsjenkins./data/com.canonical.NotifyOSD.gschema.xml0000644000015600001650000000124212704153542020461 0ustar jenkinsjenkins 'focus-follow' Multihead position behaviour Should the notification position follow the mouse-focus or not in multi-screen environments. Use values "dont-focus-follow" or "focus-follow". 1 Gravity Position of notifications on screen. Supported values are 1 (top-right) and 2 (vert. centered on the right). ./data/Makefile.am0000644000015600001650000000105612704153542014047 0ustar jenkinsjenkins SUBDIRS = icons servicedir=$(datadir)/dbus-1/services service_DATA=org.freedesktop.Notifications.service gsettings_SCHEMAS=com.canonical.NotifyOSD.gschema.xml @GSETTINGS_RULES@ EXTRA_DIST=org.freedesktop.Notifications.service.in \ com.canonical.NotifyOSD.gschema.xml convertdir = $(datadir)/GConf/gsettings convert_DATA = notify-osd.convert EXTRA_DIST += $(convert_DATA) org.freedesktop.Notifications.service: org.freedesktop.Notifications.service.in sed "s,@LIBEXECDIR@,$(libexecdir)," $< > $@ CLEANFILES = org.freedesktop.Notifications.service ./data/icons/0000755000015600001650000000000012704153542013124 5ustar jenkinsjenkins./data/icons/Makefile.am0000644000015600001650000000070012704153542015155 0ustar jenkinsjenkinsSUBDIRS = scalable # 16x16 22x22 24x24 32x32 48x48 gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: update-icon-cache uninstall-hook: update-icon-cache update-icon-cache: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After (un)install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi ./data/icons/scalable/0000755000015600001650000000000012704153542014672 5ustar jenkinsjenkins./data/icons/scalable/notification-display-brightness.svg0000644000015600001650000002647712704153542023732 0ustar jenkinsjenkins image/svg+xml Video display Luca Ferretti <elle.uca@libero.it> monitor display video screen LCD CRT ./data/icons/scalable/notification-audio-volume-medium.svg0000644000015600001650000010472312704153542023772 0ustar jenkinsjenkins image/svg+xml Ulisse Perusin Audio Volume High Lapo Calamandrei ./data/icons/scalable/notification-audio-play.svg0000644000015600001650000002336412704153542022153 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Play play playback start begin ./data/icons/scalable/notification-audio-volume-low.svg0000644000015600001650000010301112704153542023300 0ustar jenkinsjenkins image/svg+xml Ulisse Perusin Audio Volume High Lapo Calamandrei ./data/icons/scalable/notification-audio-volume-high.svg0000644000015600001650000010740712704153542023433 0ustar jenkinsjenkins image/svg+xml Ulisse Perusin Audio Volume High Lapo Calamandrei ./data/icons/scalable/notification-audio-volume-off.svg0000644000015600001650000010257012704153542023262 0ustar jenkinsjenkins image/svg+xml Ulisse Perusin Audio Volume High Lapo Calamandrei ./data/icons/scalable/notification-network-wireless.svg0000644000015600001650000004041112704153542023423 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Network Wireless ./data/icons/scalable/notification-device-eject.svg0000644000015600001650000003266712704153542022444 0ustar jenkinsjenkins image/svg+xml Jakub Steiner http://jimmac.musichall.cz Eject media eject unmount Lapo Calamandrei ./data/icons/scalable/notification-audio-next.svg0000644000015600001650000003352312704153542022162 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Next Song skip forward next ./data/icons/scalable/README0000644000015600001650000000013012704153542015544 0ustar jenkinsjenkinsThis is a set of fallback icons for Gnome. Canonical icons are in the Human icon theme. ./data/icons/scalable/Makefile.am0000644000015600001650000000143012704153542016724 0ustar jenkinsjenkinsiconsdir = $(pkgdatadir)/icons/hicolor/scalable/status icons_DATA = \ README \ notification-audio-next.svg \ notification-audio-play.svg \ notification-audio-previous.svg \ notification-audio-volume-high.svg \ notification-audio-volume-low.svg \ notification-audio-volume-medium.svg \ notification-audio-volume-muted.svg \ notification-audio-volume-off.svg \ notification-battery-low.svg \ notification-device-eject.svg \ notification-device.svg \ notification-display-brightness.svg \ notification-keyboard-brightness.svg \ notification-message-email.svg \ notification-message-im.svg \ notification-network-ethernet-connected.svg \ notification-network-ethernet-diconnected.svg \ notification-network-wireless.svg \ notification-power.svg EXTRA_DIST = $(icons_DATA) ./data/icons/scalable/notification-power.svg0000644000015600001650000007435112704153542021245 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Battery Critical battery power acpi apm warning critical ./data/icons/scalable/notification-audio-previous.svg0000644000015600001650000003363712704153542023066 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Previous Song skip backward previous media ./data/icons/scalable/notification-message-im.svg0000644000015600001650000003400412704153542022127 0ustar jenkinsjenkins image/svg+xml Person Jakub Steiner http://jimmac.musichall.cz user person ./data/icons/scalable/notification-message-email.svg0000644000015600001650000004060312704153542022613 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Mail stuff ./data/icons/scalable/notification-device.svg0000644000015600001650000004535512704153542021352 0ustar jenkinsjenkins image/svg+xml Drive Removable Media Lapo Calamandrei http://www.gnome.org Jakub Steiner 2006 drive removable media ./data/icons/scalable/notification-network-ethernet-connected.svg0000644000015600001650000010166312704153542025353 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei ./data/icons/scalable/notification-audio-volume-muted.svg0000644000015600001650000010362312704153542023626 0ustar jenkinsjenkins image/svg+xml Ulisse Perusin Audio Volume High Lapo Calamandrei ./data/icons/scalable/notification-network-ethernet-diconnected.svg0000644000015600001650000010166312704153542025670 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei ./data/icons/scalable/notification-battery-low.svg0000644000015600001650000005574712704153542022372 0ustar jenkinsjenkins image/svg+xml Lapo Calamandrei Battery battery recharge power acpi apm ./data/icons/scalable/notification-keyboard-brightness.svg0000644000015600001650000021070712704153542024054 0ustar jenkinsjenkins image/svg+xml Keyboard Lapo Calamandrei Jakub Steiner ./data/org.freedesktop.Notifications.service.in0000644000015600001650000000012012704153542021702 0ustar jenkinsjenkins[D-BUS Service] Name=org.freedesktop.Notifications Exec=@LIBEXECDIR@/notify-osd ./data/notify-osd.convert0000644000015600001650000000015712704153542015511 0ustar jenkinsjenkins[com.canonical.notify-osd] multihead-mode = /apps/notify-osd/multihead_mode gravity = /apps/notify-osd/gravity ./NEWS0000644000015600001650000000216512704153542011603 0ustar jenkinsjenkinsNoteworthy changes since last release (0.9.30): * Mono-example don't compile (under Oneiric Ocelot) * ported to gtk+ 3.x * ported to libnotify 0.7.x * updated C- and Python-examples ---- This is the inital version of the new notification daemon "notify osd" developed by Canonical's dx- and design-teams. It follows the freedesktop notification specification and introduces some new policies for streamlining the user- experience by discouraging the use of actions and timeouts. C-, Python- and C#-examples demonstrating correct usage of notifications have been added. Have a look at the examples-directory. This accompanies the devel- oper guidelines availabled under: https://wiki.ubuntu.com/NotificationDevelopmentGuidelines Noteworthy changes since last release (0.9.22): * updating NEWS file now, fixes LP: #432486 * no long using hard-coded -Werror, fixes LP: #361788 * solved regression regarding throbbing-animation for value-indicator, fixes LP: #435116 * looking up gravity-gconf-key upon startup, fixes LP: #431200 * convert newline characters to spaces, fixes LP: #402247 ./manual-tests/0000755000015600001650000000000012704153542013515 5ustar jenkinsjenkins./manual-tests/avoid-position-in-invisible-area.txt0000644000015600001650000000222312704153542022515 0ustar jenkinsjenkins1.) Have a two-monitor setup and configure the displays in such a way that the vertical resolution between the two monitors differs by at least 100 pixels. Align the displays at the bottom edge! Make the monitor with the lower vertical resolution the primary display. Depending on your GPU/driver combination, you can use the GNOME display-settings for setting this up or you have to use a tool like nvidia-settings. 2.) Kill and restart notify-osd by doing... killall -15 notify-osd /usr/lib/notify-osd/notify-osd 2.) Set focus-follow off and gravity to 1 with... gsettings set com.canonical.notify-osd multihead-mode "dont-focus-follow" gsettings set com.canonical.notify-osd gravity 1 4.) Trigger two notifications (a synchronous one and a regular one) with these commands... notify-send "Test bubble" "A regular notification used for testing." -i info notify-send " " " " -i info -h string:"x-canonical-private-icon-only":1 -h string:"x-canonical-private-synchronous":1 -i info 5.) You should now see both notifications fully at the visible top-right corner of the whole screen area. 6.) For RTL-locales you have to flip 1.) - 5.) side-ways of course. ./manual-tests/average-background-color.txt0000644000015600001650000000144112704153542021121 0ustar jenkinsjenkins1.) Verify that the correct X11-property is available with: xlsatoms -name _GNOME_BACKGROUND_REPRESENTATIVE_COLORS If you don't get a reply from that command (it just returns to the prompt) any notification you trigger (step 3.) will have a dark grey background. 2.) Right-click on the desktop to bring up the context-menu and select the change wallpaper menu-item. 3.) Trigger a dummy notification with: notify-send "Test" "This is just a simple test." -i info Note the tint of the notifications background and wait for the notification to close (don't keep the mouse-pointer hovering over the notification). 4.) Change the wallpaper to an image with an overall different tint as the current one. 5.) Repeat step 3.) 6.) The tint of the notifications background should now be different. ./examples/0000755000015600001650000000000012704153542012716 5ustar jenkinsjenkins./examples/icon-summary.cs0000644000015600001650000000340412704153542015671 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs icon-summary.cs \ // -out:icon-summary.exe // mono icon-summary.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class IconSummary { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-summary case Notification n = new Notification ("WiFi connection lost", "", // this needs to be empty "notification-network-wireless-disconnected"); n.Show (); } } ./examples/sync-icon-only.c0000644000015600001650000000527512704153542015754 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` sync-icon-only.c example-util.c -o sync-icon-only ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("sync-icon-only")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the sync. icon-only case */ if (has_cap (CAP_LAYOUT_ICON_ONLY) && has_cap (CAP_SYNCHRONOUS)) { notification = notify_notification_new ( "Eject", /* for a11y-reasons put something meaningfull here */ NULL, "notification-device-eject"); notify_notification_set_hint_string (notification, "x-canonical-private-icon-only", "true"); notify_notification_set_hint_string (notification, "x-canonical-private-synchronous", "true"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); } else { g_print ("The daemon does not support the x-canonical-private-icon-only hint!\n"); g_print ("The daemon does not support the x-canonical-private-synchronous hint!\n"); } notify_uninit (); return 0; } ./examples/normal-urgency.py0000755000015600001650000000774412704153542016251 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x normal-urgency.py ## ./normal-urgency.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("normal-urgency"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary-body case n = pynotify.Notification ("Cole Raby", "Hey pal, what's up with the party " "next weekend? Will you join me " "and Anna?", "notification-message-im") n.set_urgency (pynotify.URGENCY_NORMAL) n.show () ./examples/append-hint-example.py0000755000015600001650000001206712704153542017141 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x append-hint-example.py ## ./append-hint-example.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import time import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" def pushNotification (title, body, icon): n = pynotify.Notification (title, body, icon); n.set_hint_string ("x-canonical-append", "true"); n.show () time.sleep (3) # simulate a user typing if __name__ == '__main__': if not pynotify.init ("append-hint-example"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the append-hint if capabilities['x-canonical-append']: pushNotification ("Cole Raby", "Hey Bro Coly!", "notification-message-im"); pushNotification ("Cole Raby", "What's up dude?", "notification-message-im"); pushNotification ("Cole Raby", "Did you watch the air-race in Oshkosh last week?", "notification-message-im"); pushNotification ("Cole Raby", "Phil owned the place like no one before him!", "notification-message-im"); pushNotification ("Cole Raby", "Did really everything in the race work according to regulations?", "notification-message-im"); pushNotification ("Cole Raby", "Somehow I think to remember Burt Williams did cut corners and was not punished for this.", "notification-message-im"); pushNotification ("Cole Raby", "Hopefully the referees will watch the videos of the race.", "notification-message-im"); pushNotification ("Cole Raby", "Burt could get fined with US$ 50000 for that rule-violation :)", "notification-message-im"); else: print "The daemon does not support the x-canonical-append hint!" ./examples/icon-summary-body.py0000755000015600001650000000770312704153542016660 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x icon-summary-body.py ## ./icon-summary-body.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("icon-summary-body"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary-body case n = pynotify.Notification ("Cole Raby", "Hey pal, what's up with the party " "next weekend? Will you join me " "and Anna?", "notification-message-im") n.show () ./examples/icon-value.py0000755000015600001650000001162512704153542015342 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x icon-value.py ## ./icon-value.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import time import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" def pushNotification (icon, value): n = pynotify.Notification ("Brightness", # for a11y-reasons supply something meaning full "", # this needs to be empty! icon); n.set_hint_int32 ("value", value); n.set_hint_string ("x-canonical-private-synchronous", "true"); n.show () time.sleep (1) if __name__ == '__main__': if not pynotify.init ("icon-value"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-value case if capabilities['x-canonical-private-icon-only']: pushNotification ("notification-keyboard-brightness-low", 25); pushNotification ("notification-keyboard-brightness-medium", 50); pushNotification ("notification-keyboard-brightness-high", 75); pushNotification ("notification-keyboard-brightness-full", 100); # trigger "overshoot"-effect pushNotification ("notification-keyboard-brightness-full", 101); pushNotification ("notification-keyboard-brightness-high", 75); pushNotification ("notification-keyboard-brightness-medium", 50); pushNotification ("notification-keyboard-brightness-low", 25); pushNotification ("notification-keyboard-brightness-off", 0); # trigger "undershoot"-effect pushNotification ("notification-keyboard-brightness-off", -1); else: print "The daemon does not support the x-canonical-private-icon-only hint!" ./examples/low-urgency.py0000755000015600001650000000764712704153542015564 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x low-urgency.py ## ./low-urgency.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("low-urgency"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary-body case n = pynotify.Notification ("Gerhard Gepard", "No, I'd rather see paint dry, pal *yawn*", "notification-message-im") n.set_urgency (pynotify.URGENCY_LOW) n.show () ./examples/icon-only.py0000755000015600001650000001015512704153542015204 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x icon-only.py ## ./icon-only.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("icon-only"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-only case if capabilities['x-canonical-private-icon-only']: n = pynotify.Notification ("", # for a11y-reasons put something meaningfull here "", # for a11y-reasons put something meaningfull here "notification-device-eject") n.set_hint_string ("x-canonical-private-icon-only", "true"); n.show () else: print "The daemon does not support the x-canonical-private-icon-only hint!" ./examples/icon-updating.c0000644000015600001650000000717112704153542015631 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` icon-updating.c example-util.c -o icon-updating ** ** Copyright 2010 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification = NULL; gboolean success; GError* error = NULL; GdkPixbuf* pixbuf = NULL; if (!notify_init ("icon-updating")) return 1; // call this so we can savely use has_cap(CAP_SOMETHING) later init_caps (); // show what's supported print_caps (); // create new notification, set icon using hint "image_path" notification = notify_notification_new ( "Test 1/3", "Set icon via hint \"image_path\" to logo-icon.", NULL); notify_notification_set_hint_string ( notification, "image_path", "/usr/share/icons/Humanity/places/64/distributor-logo.svg"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("Could not show notification: \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); sleep (4); // wait a bit // update notification using hint image_data notify_notification_clear_hints (notification); success = notify_notification_update ( notification, "Test 2/3", "Set icon via hint \"image_data\" to avatar-photo.", NULL); error = NULL; pixbuf = gdk_pixbuf_new_from_file ("../icons/avatar.png", &error); if (!pixbuf) { g_print ("Could not load image: \"%s\".\n", error->message); g_error_free (error); } notify_notification_set_icon_from_pixbuf (notification, pixbuf); g_object_unref (pixbuf); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("Could not show notification: \"%s\".\n", error->message); g_error_free (error); } sleep (4); // wait a bit // update notification using icon-parameter directly notify_notification_clear_hints (notification); success = notify_notification_update ( notification, "Test 3/3", "Set icon via icon-parameter directly to totem-icon.", "totem"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("Could not show notification: \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/icon-only.cs0000644000015600001650000000376312704153542015165 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs icon-only.cs -out:icon-only.exe // mono icon-only.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class IconOnly { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-sonly case if (ExampleUtil.HasCap (ExampleUtil.Capability.CAP_LAYOUT_ICON_ONLY)) { Notification n = new Notification ("Eject", // for a11y-reasons supply something meaning full "", // this needs to be empty! "notification-device-eject"); n.AddHint ("x-canonical-private-icon-only", ""); n.Show (); } else Console.WriteLine ("The daemon does not support the x-canonical-private-icon-only hint!"); } } ./examples/Makefile.am0000644000015600001650000001166112704153542014757 0ustar jenkinsjenkinsEXTRA_DIST = append-hint-example.py \ icon-only.py \ icon-summary-body.py \ icon-summary.py \ icon-value.py \ low-urgency.py \ normal-urgency.py \ summary-body.py \ summary-only.py \ sync-icon-only.py \ update-notifications.py \ urgent-urgency.py if BUILD_C_EXAMPLES noinst_PROGRAMS = icon-only \ sync-icon-only \ icon-summary-body \ icon-summary \ icon-value \ summary-body \ summary-only \ append-hint-example \ update-notifications \ icon-updating icon_only_SOURCES = example-util.c example-util.h icon-only.c sync_icon_only_SOURCES = sync-icon-only.c example-util.h example-util.c icon_summary_body_SOURCES = icon-summary-body.c example-util.h example-util.c icon_summary_SOURCES = icon-summary.c example-util.c example-util.h icon_value_SOURCES = icon-value.c example-util.c example-util.h summary_body_SOURCES = summary-body.c example-util.c example-util.h summary_only_SOURCES = summary-only.c example-util.c example-util.h append_hint_example_SOURCES = append-hint-example.c example-util.c example-util.h update_notifications_SOURCES = update-notifications.c example-util.c example-util.h icon_updating_SOURCES = icon-updating.c example-util.c example-util.h icon_only_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` sync_icon_only_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` icon_summary_body_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` icon_summary_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` icon_value_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` summary_body_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` summary_only_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` append_hint_example_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` update_notifications_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` icon_updating_CFLAGS = -I. -O0 -ggdb -Wall -Werror `pkg-config --cflags libnotify glib-2.0` icon_only_LDFLAGS = `pkg-config --libs libnotify glib-2.0` sync_icon_only_LDFLAGS = `pkg-config --libs libnotify glib-2.0` icon_summary_body_LDFLAGS = `pkg-config --libs libnotify glib-2.0` icon_summary_LDFLAGS = `pkg-config --libs libnotify glib-2.0` icon_value_LDFLAGS = `pkg-config --libs libnotify glib-2.0` summary_body_LDFLAGS = `pkg-config --libs libnotify glib-2.0` summary_only_LDFLAGS = `pkg-config --libs libnotify glib-2.0` append_hint_example_LDFLAGS = `pkg-config --libs libnotify glib-2.0` update_notifications_LDFLAGS = `pkg-config --libs libnotify glib-2.0` icon_updating_LDFLAGS = `pkg-config --libs libnotify glib-2.0` endif if BUILD_MONO_EXAMPLES noinst_PROGRAMS = icon-only.exe \ sync-icon-only.exe \ icon-summary-body.exe \ icon-summary.exe \ icon-value.exe \ summary-body.exe \ summary-only.exe \ append-hint-example.exe \ update-notifications.exe icon_only_exe_SOURCES = example-util.cs icon-only.cs sync_icon_only_exe_SOURCES = sync-icon-only.cs example-util.cs icon_summary_body_exe_SOURCES = icon-summary-body.cs example-util.cs icon_summary_exe_SOURCES = icon-summary.cs example-util.cs icon_value_exe_SOURCES = icon-value.cs example-util.cs summary_body_exe_SOURCES = summary-body.cs example-util.cs summary_only_exe_SOURCES = summary-only.cs example-util.cs append_hint_example_exe_SOURCES = append-hint-example.cs example-util.cs update_notifications_exe_SOURCES = update-notifications.cs example-util.cs icon-only.exe: $(icon_only_exe_SOURCES) gmcs -pkg:notify-sharp $(icon_only_exe_SOURCES) -out:icon-only.exe sync-icon-only.exe: $(sync_icon_only_exe_SOURCES) gmcs -pkg:notify-sharp $(sync_icon_only_exe_SOURCES) -out:sync-icon-only.exe icon-summary-body.exe: $(icon_summary_body_exe_SOURCES) gmcs -pkg:notify-sharp $(icon_summary_body_exe_SOURCES) -out:icon-summary-body.exe icon-summary.exe: $(icon_summary_exe_SOURCES) gmcs -pkg:notify-sharp $(icon_summary_exe_SOURCES) -out:icon-summary.exe icon-value.exe: $(icon_value_exe_SOURCES) gmcs -pkg:notify-sharp -r:Mono.Posix.dll $(icon_value_exe_SOURCES) -out:icon-value.exe summary-body.exe: $(summary_body_exe_SOURCES) gmcs -pkg:notify-sharp $(summary_body_exe_SOURCES) -out:summary-body.exe summary-only.exe: $(summary_only_exe_SOURCES) gmcs -pkg:notify-sharp $(summary_only_exe_SOURCES) -out:summary-only.exe append-hint-example.exe: $(append_hint_example_exe_SOURCES) gmcs -pkg:notify-sharp -r:Mono.Posix.dll $(append_hint_example_exe_SOURCES) -out:append-hint-example.exe update-notifications.exe: $(update_notifications_exe_SOURCES) gmcs -pkg:notify-sharp -r:Mono.Posix.dll $(update_notifications_exe_SOURCES) -out:update-notifications.exe endif ./examples/update-notifications.c0000644000015600001650000000770512704153542017224 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` update-notifications.c example-util.c -o update-notifications ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("update-notifications")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the icon-summary-body case */ notification = notify_notification_new ( "Inital notification", "This is the original content of " "this notification-bubble.", "notification-message-im"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); sleep (3); /* simulate some app activity */ /* update the current notification with new content */ success = notify_notification_update (notification, "Updated notification", "Here the same bubble with new " "title- and body-text, even the " "icon can be changed on the update.", "notification-message-email"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); sleep (6); /* wait long enough to have the current bubble expire */ /* create a new bubble using the icon-summary-body layout */ notification = notify_notification_new ( "Initial layout", "This bubble uses the icon-title-body " "layout.", "notification-message-im"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); sleep (3); /* again simulate some app activity */ /* now update current bubble again, but change the layout */ success = notify_notification_update (notification, "Updated layout", "After the update we now have a " "bubble using the title-body layout.", " "); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/append-hint-example.c0000644000015600001650000000701012704153542016720 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` append-hint-example.c example-util.c -o append-hint-example ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" void push_notification (gchar* title, gchar* body, gchar* icon) { NotifyNotification* notification; gboolean success; GError* error = NULL; /* initial notification */ notification = notify_notification_new (title, body, icon); notify_notification_set_hint_string (notification, "x-canonical-append", "true"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); g_object_unref (G_OBJECT (notification)); sleep (3); /* simulate a user typing */ } int main (int argc, char** argv) { if (!notify_init ("append-hint-example")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the append-hint */ if (has_cap (CAP_APPEND)) { push_notification ("Cole Raby", "Hey Bro Coly!", "notification-message-im"); push_notification ("Cole Raby", "What's up dude?", "notification-message-im"); push_notification ("Cole Raby", "Did you watch the air-race in Oshkosh last week?", "notification-message-im"); push_notification ("Cole Raby", "Phil owned the place like no one before him!", "notification-message-im"); push_notification ("Cole Raby", "Did really everything in the race work according to regulations?", "notification-message-im"); push_notification ("Cole Raby", "Somehow I think to remember Burt Williams did cut corners and was not punished for this.", "notification-message-im"); push_notification ("Cole Raby", "Hopefully the referees will watch the videos of the race.", "notification-message-im"); push_notification ("Cole Raby", "Burt could get fined with US$ 50000 for that rule-violation :)", "notification-message-im"); } else { g_print ("The daemon does not support the x-canonical-append hint!"); } notify_uninit (); return 0; } ./examples/icon-summary.c0000644000015600001650000000422212704153542015505 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` icon-summary.c example-util.c -o icon-summary ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("icon-summary")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the icon-summary case */ notification = notify_notification_new ( "WiFi connection lost", NULL, "notification-network-wireless-disconnected"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/icon-value.c0000644000015600001650000000665712704153542015142 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` icon-value.c example-util.c -o icon-value ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" void push_notification (gchar* icon, gint value) { NotifyNotification* notification; gboolean success; GError* error = NULL; notification = notify_notification_new ( "Brightness", /* for a11y-reasons put something meaningfull here */ NULL, icon); notify_notification_set_hint_int32 (notification, "value", value); notify_notification_set_hint_string (notification, "x-canonical-private-synchronous", "true"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); g_object_unref (G_OBJECT (notification)); sleep (1); } int main (int argc, char** argv) { if (!notify_init ("icon-value")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the value-icon case, usually used for synchronous bubbles */ if (has_cap (CAP_SYNCHRONOUS)) { push_notification ("notification-keyboard-brightness-low", 25); push_notification ("notification-keyboard-brightness-medium", 50); push_notification ("notification-keyboard-brightness-high", 75); push_notification ("notification-keyboard-brightness-full", 100); /* trigger "overshoot"-effect */ push_notification ("notification-keyboard-brightness-full", 101); push_notification ("notification-keyboard-brightness-high", 75); push_notification ("notification-keyboard-brightness-medium", 50); push_notification ("notification-keyboard-brightness-low", 25); push_notification ("notification-keyboard-brightness-off", 0); /* trigger "undershoot"-effect */ push_notification ("notification-keyboard-brightness-off", -1); } else g_print ("The daemon does not support the x-canonical-private-synchronous hint!\n"); notify_uninit (); return 0; } ./examples/summary-body.py0000755000015600001650000000751512704153542015733 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x summary-body.py ## ./summary-body.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("summary-body"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the summary-body case n = pynotify.Notification ("Totem", "This is a superfluous notification") n.show () ./examples/append-hint-example.cs0000644000015600001650000000610012704153542017102 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp -r:Mono.Posix.dll example-util.cs \ // append-hint-example.cs -out:append-hint-example.exe // mono append-hint-example.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class AppendHintExample { public static void pushNotification (String title, String body, String icon) { Notification n = new Notification (title, body, icon); n.AddHint ("x-canonical-append", ""); n.Show (); Mono.Unix.Native.Syscall.sleep (3); // simulate typing } public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the append-hint if (ExampleUtil.HasCap (ExampleUtil.Capability.CAP_APPEND)) { pushNotification ("Cole Raby", "Hey Bro Coly!", "notification-message-im"); pushNotification ("Cole Raby", "What's up dude?", "notification-message-im"); pushNotification ("Cole Raby", "Did you watch the air-race in Oshkosh last week?", "notification-message-im"); pushNotification ("Cole Raby", "Phil owned the place like no one before him!", "notification-message-im"); pushNotification ("Cole Raby", "Did really everything in the race work according to regulations?", "notification-message-im"); pushNotification ("Cole Raby", "Somehow I think to remember Burt Williams did cut corners and was not punished for this.", "notification-message-im"); pushNotification ("Cole Raby", "Hopefully the referees will watch the videos of the race.", "notification-message-im"); pushNotification ("Cole Raby", "Burt could get fined with US$ 50000 for that rule-violation :)", "notification-message-im"); } else Console.WriteLine ("The daemon does not support the x-canonical-append hint!"); } } ./examples/update-notifications.py0000755000015600001650000001134412704153542017427 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x update-notifications.py ## ./update-notifications.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import time import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("update-notifications"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary-body case n = pynotify.Notification ( "Inital notification (1. notification)", "This is the original content of this notification-bubble.", "notification-message-im") n.show () time.sleep (4); # simulate app activity # update the current notification with new content n.update ("Updated notification (1. notification)", "Here the same bubble with new title- and body-text, even the icon can be changed on the update.", "notification-message-email") n.show (); time.sleep (10); # wait longer now # create a new bubble using the icon-summary-body layout n = pynotify.Notification ( "Initial layout (2. notification)", "This bubble uses the icon-title-body layout.", "notification-message-im"); n.show () time.sleep (4); # simulate app activity # now update current bubble again, but change the layout n.update ("Updated layout (2. notification)", "After the update we now have a bubble using the title-body layout.", " ") n.show () ./examples/example-util.c0000644000015600001650000001271312704153542015474 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Implementation for some utility-functions for notification examples ** demonstrating how to use libnotify correctly and at the same time comply ** to the new jaunty notification spec (read: visual guidelines) ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" /* this is globally nasty :), do something nicer in your own code */ gboolean g_capabilities[CAP_MAX] = {FALSE, /* actions */ FALSE, /* body */ FALSE, /* body-hyperlinks */ FALSE, /* body-imges */ FALSE, /* body-markup */ FALSE, /* icon-multi */ FALSE, /* icon-static */ FALSE, /* sound */ FALSE, /* image/svg+xml */ FALSE, /* synchronous-hint */ FALSE, /* append-hint */ FALSE, /* icon-only-hint */ FALSE /* truncation-hint */}; void closed_handler (NotifyNotification* notification, gpointer data) { g_print ("closed_handler() called"); return; } void set_cap (gpointer data, gpointer user_data) { /* test for "actions" */ if (!g_strcmp0 (ACTIONS, (gchar*) data)) g_capabilities[CAP_ACTIONS] = TRUE; /* test for "body" */ if (!g_strcmp0 (BODY, (gchar*) data)) g_capabilities[CAP_BODY] = TRUE; /* test for "body-hyperlinks" */ if (!g_strcmp0 (BODY_HYPERLINKS, (gchar*) data)) g_capabilities[CAP_BODY_HYPERLINKS] = TRUE; /* test for "body-images" */ if (!g_strcmp0 (BODY_IMAGES, (gchar*) data)) g_capabilities[CAP_BODY_IMAGES] = TRUE; /* test for "body-markup" */ if (!g_strcmp0 (BODY_MARKUP, (gchar*) data)) g_capabilities[CAP_BODY_MARKUP] = TRUE; /* test for "icon-multi" */ if (!g_strcmp0 (ICON_MULTI, (gchar*) data)) g_capabilities[CAP_ICON_MULTI] = TRUE; /* test for "icon-static" */ if (!g_strcmp0 (ICON_STATIC, (gchar*) data)) g_capabilities[CAP_ICON_STATIC] = TRUE; /* test for "sound" */ if (!g_strcmp0 (SOUND, (gchar*) data)) g_capabilities[CAP_SOUND] = TRUE; /* test for "image/svg+xml" */ if (!g_strcmp0 (IMAGE_SVG, (gchar*) data)) g_capabilities[CAP_IMAGE_SVG] = TRUE; /* test for "x-canonical-private-synchronous" */ if (!g_strcmp0 (SYNCHRONOUS, (gchar*) data)) g_capabilities[CAP_SYNCHRONOUS] = TRUE; /* test for "x-canonical-append" */ if (!g_strcmp0 (APPEND, (gchar*) data)) g_capabilities[CAP_APPEND] = TRUE; /* test for "x-canonical-private-icon-only" */ if (!g_strcmp0 (LAYOUT_ICON_ONLY, (gchar*) data)) g_capabilities[CAP_LAYOUT_ICON_ONLY] = TRUE; /* test for "x-canonical-truncation" */ if (!g_strcmp0 (TRUNCATION, (gchar*) data)) g_capabilities[CAP_TRUNCATION] = TRUE; } void init_caps (void) { GList* caps_list; caps_list = notify_get_server_caps (); if (caps_list) { g_list_foreach (caps_list, set_cap, NULL); g_list_foreach (caps_list, (GFunc) g_free, NULL); g_list_free (caps_list); } } gboolean has_cap (Capability cap) { return g_capabilities[cap]; } void print_caps (void) { gchar* name; gchar* vendor; gchar* version; gchar* spec_version; notify_get_server_info (&name, &vendor, &version, &spec_version); g_print ("Name: %s\n" "Vendor: %s\n" "Version: %s\n" "Spec. Version: %s\n", name, vendor, version, spec_version); g_print ("Supported capabilities/hints:\n"); if (has_cap (CAP_ACTIONS)) g_print ("\tactions\n"); if (has_cap (CAP_BODY)) g_print ("\tbody\n"); if (has_cap (CAP_BODY_HYPERLINKS)) g_print ("\tbody-hyperlinks\n"); if (has_cap (CAP_BODY_IMAGES)) g_print ("\tbody-images\n"); if (has_cap (CAP_BODY_MARKUP)) g_print ("\tbody-markup\n"); if (has_cap (CAP_ICON_MULTI)) g_print ("\ticon-multi\n"); if (has_cap (CAP_ICON_STATIC)) g_print ("\ticon-static\n"); if (has_cap (CAP_SOUND)) g_print ("\tsound\n"); if (has_cap (CAP_IMAGE_SVG)) g_print ("\timage/svg+xml\n"); if (has_cap (CAP_SYNCHRONOUS)) g_print ("\tx-canonical-private-synchronous\n"); if (has_cap (CAP_APPEND)) g_print ("\tx-canonical-append\n"); if (has_cap (CAP_LAYOUT_ICON_ONLY)) g_print ("\tx-canonical-private-icon-only\n"); if (has_cap (CAP_TRUNCATION)) g_print ("\tx-canonical-truncation\n"); g_print ("Notes:\n"); if (!g_strcmp0 ("notify-osd", name)) { g_print ("\tx- and y-coordinates hints are ignored\n"); g_print ("\texpire-timeout is ignored\n"); g_print ("\tbody-markup is accepted but filtered\n"); } else g_print ("\tnone"); g_free ((gpointer) name); g_free ((gpointer) vendor); g_free ((gpointer) version); g_free ((gpointer) spec_version); } ./examples/summary-body.c0000644000015600001650000000417312704153542015517 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` summary-body.c example-util.c -o summary-body ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("summary-body")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the summary-body case */ notification = notify_notification_new ( "Totem", "This is a superfluous notification", NULL); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/summary-only.py0000755000015600001650000000746212704153542015760 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x summary-only.py ## ./summary-only.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("summary-only"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the summary-only case n = pynotify.Notification ("Summary-only", "") n.show () ./examples/urgent-urgency.py0000755000015600001650000000766312704153542016265 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x urgent-urgency.py ## ./urgent-urgency.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("urgent-urgency"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary-body case n = pynotify.Notification ("Cole Raby", "Dude, this is so urgent you have no idea :)", "notification-message-im") n.set_urgency (pynotify.URGENCY_CRITICAL) n.show () ./examples/icon-summary-body.cs0000644000015600001650000000354612704153542016633 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs icon-summary-body.cs \ // -out:icon-summary-body.exe // mono icon-summary-body.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class IconSummaryBody { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-summary-body case Notification n = new Notification ("Cole Raby", "Hey pal, what's up with the party next weekend? Will you join me and Anna?", "notification-message-im"); n.Show (); } } ./examples/summary-body.cs0000644000015600001650000000334312704153542015700 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs summary-body.cs \ // -out:summary-body.exe // mono summary-body.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class SummaryBody { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the summary-body case Notification n = new Notification ("Totem", "This is a superfluous notification."); n.Show (); } } ./examples/summary-only.cs0000644000015600001650000000324212704153542015722 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs summary-only.cs \ // -out:summary-only.exe // mono summary-only.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class SummaryOnly { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the summary-only case Notification n = new Notification ("Summary-only", ""); n.Show (); } } ./examples/icon-value.cs0000644000015600001650000000571612704153542015320 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs icon-value.cs -out:icon-value.exe // mono icon-value.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class IconValue { public static void pushNotification (String icon, int val) { Notification n = new Notification ("Brightness", // for a11y-reasons supply something meaning full "", // this needs to be empty! icon); n.AddHint ("value", val); n.AddHint ("x-canonical-private-synchronous", ""); n.Show (); Mono.Unix.Native.Syscall.sleep (1); } public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-value case, usually used for synchronous bubbles if (ExampleUtil.HasCap (ExampleUtil.Capability.CAP_SYNCHRONOUS)) { pushNotification ("notification-keyboard-brightness-low", 25); pushNotification ("notification-keyboard-brightness-medium", 50); pushNotification ("notification-keyboard-brightness-high", 75); pushNotification ("notification-keyboard-brightness-full", 100); // trigger "overshoot"-effect pushNotification ("notification-keyboard-brightness-full", 101); pushNotification ("notification-keyboard-brightness-high", 75); pushNotification ("notification-keyboard-brightness-medium", 50); pushNotification ("notification-keyboard-brightness-low", 25); pushNotification ("notification-keyboard-brightness-off", 0); // trigger "undershoot"-effect pushNotification ("notification-keyboard-brightness-off", -1); } else Console.WriteLine ("The daemon does not support the x-canonical-private-synchronous hint!"); } } ./examples/example-util.h0000644000015600001650000000464712704153542015510 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Header for some utility-functions for notification examples demonstrating ** how to use libnotify correctly and at the same time comply to the new ** jaunty notification spec (read: visual guidelines) ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 __EXAMPLE_UTIL_H #define __EXAMPLE_UTIL_H #include #include #include typedef enum _Capability { CAP_ACTIONS = 0, CAP_BODY, CAP_BODY_HYPERLINKS, CAP_BODY_IMAGES, CAP_BODY_MARKUP, CAP_ICON_MULTI, CAP_ICON_STATIC, CAP_SOUND, CAP_IMAGE_SVG, CAP_SYNCHRONOUS, CAP_APPEND, CAP_LAYOUT_ICON_ONLY, CAP_TRUNCATION, CAP_MAX } Capability; #define ACTIONS "actions" #define BODY "body" #define BODY_HYPERLINKS "body-hyperlinks" #define BODY_IMAGES "body-images" #define BODY_MARKUP "body-markup" #define ICON_MULTI "icon-multi" #define ICON_STATIC "icon-static" #define SOUND "sound" #define IMAGE_SVG "image/svg+xml" #define SYNCHRONOUS "x-canonical-private-synchronous" #define APPEND "x-canonical-append" #define LAYOUT_ICON_ONLY "x-canonical-private-icon-only" #define TRUNCATION "x-canonical-truncation" void closed_handler (NotifyNotification* notification, gpointer data); void set_cap (gpointer data, gpointer user_data); void init_caps (void); gboolean has_cap (Capability cap); void print_caps (void); #endif /* __EXAMPLE_UTIL_H */ ./examples/icon-only.c0000644000015600001650000000465312704153542015001 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` icon-only.c example-util.c -o icon-only ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("icon-only")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the icon-only case */ if (has_cap (CAP_LAYOUT_ICON_ONLY)) { notification = notify_notification_new ( "Eject", /* for a11y-reasons put something meaningfull here */ NULL, "notification-device-eject"); notify_notification_set_hint_string (notification, "x-canonical-private-icon-only", "true"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); } else g_print ("The daemon does not support the x-canonical-private-icon-only hint!\n"); notify_uninit (); return 0; } ./examples/summary-only.c0000644000015600001650000000414312704153542015540 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` summary-only.c example-util.c -o summary-only ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("summary-only")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the summary-only case */ notification = notify_notification_new ( "Summary-only", NULL, NULL); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/sync-icon-only.cs0000644000015600001650000000416212704153542016131 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp example-util.cs sync-icon-only.cs \ // -out:sync-icon-only.exe // mono sync-icon-only.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class SyncIconOnly { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-sonly case if (ExampleUtil.HasCap (ExampleUtil.Capability.CAP_LAYOUT_ICON_ONLY) && ExampleUtil.HasCap (ExampleUtil.Capability.CAP_SYNCHRONOUS)) { Notification n = new Notification ("Eject", // for a11y-reasons supply something meaning full "", // this needs to be empty! "notification-device-eject"); n.AddHint ("x-canonical-private-icon-only", ""); n.AddHint ("x-canonical-private-synchronous", ""); n.Show (); } else Console.WriteLine ("The daemon does not support sync. icon-only!"); } } ./examples/icon-summary-body.c0000644000015600001650000000433612704153542016446 0ustar jenkinsjenkins/******************************************************************************* **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ** 10 20 30 40 50 60 70 80 ** ** Info: ** Example of how to use libnotify correctly and at the same time comply to ** the new jaunty notification spec (read: visual guidelines) ** ** Compile: ** gcc -O0 -ggdb -Wall -Werror `pkg-config --cflags --libs libnotify \ ** glib-2.0` icon-summary-body.c example-util.c -o icon-summary-body ** ** Copyright 2009 Canonical Ltd. ** ** Author: ** 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 "example-util.h" int main (int argc, char** argv) { NotifyNotification* notification; gboolean success; GError* error = NULL; if (!notify_init ("icon-summary-body")) return 1; /* call this so we can savely use has_cap(CAP_SOMETHING) later */ init_caps (); /* show what's supported */ print_caps (); /* try the icon-summary-body case */ notification = notify_notification_new ( "Cole Raby", "Hey pal, what's up with the party " "next weekend? Will you join me " "and Anna?", "notification-message-im"); error = NULL; success = notify_notification_show (notification, &error); if (!success) { g_print ("That did not work ... \"%s\".\n", error->message); g_error_free (error); } g_signal_connect (G_OBJECT (notification), "closed", G_CALLBACK (closed_handler), NULL); notify_uninit (); return 0; } ./examples/icon-summary.py0000755000015600001650000000755712704153542015734 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x icon-summary.py ## ./icon-summary.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("icon-summary"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try the icon-summary case n = pynotify.Notification ("WiFi connection lost", "", "notification-network-wireless-disconnected") n.show () ./examples/example-util.cs0000644000015600001650000001372212704153542015660 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp -r:Mono.Posix.dll append-hint-example.cs \ // -out:append-hint-example.exe // mono append-hint-example.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; static class ExampleUtil { public enum Capability { CAP_ACTIONS = 0, CAP_BODY, CAP_BODY_HYPERLINKS, CAP_BODY_IMAGES, CAP_BODY_MARKUP, CAP_ICON_MULTI, CAP_ICON_STATIC, CAP_SOUND, CAP_IMAGE_SVG, CAP_SYNCHRONOUS, CAP_APPEND, CAP_LAYOUT_ICON_ONLY, CAP_TRUNCATION, CAP_MAX} static bool[] m_capabilities = {false, // actions false, // body false, // body-hyperlinks false, // body-imges false, // body-markup false, // icon-multi false, // icon-static false, // sound false, // image/svg+xml false, // synchronous-hint false, // append-hint false, // icon-only-hint false}; // truncation-hint public static void InitCaps () { if (Global.Capabilities == null) return; if (Array.IndexOf (Global.Capabilities, "actions") > -1) m_capabilities[(int) Capability.CAP_ACTIONS] = true; if (Array.IndexOf (Global.Capabilities, "body") > -1) m_capabilities[(int) Capability.CAP_BODY] = true; if (Array.IndexOf (Global.Capabilities, "body-hyperlinks") > -1) m_capabilities[(int) Capability.CAP_BODY_HYPERLINKS] = true; if (Array.IndexOf (Global.Capabilities, "body-images") > -1) m_capabilities[(int) Capability.CAP_BODY_IMAGES] = true; if (Array.IndexOf (Global.Capabilities, "body-markup") > -1) m_capabilities[(int) Capability.CAP_BODY_MARKUP] = true; if (Array.IndexOf (Global.Capabilities, "icon-multi") > -1) m_capabilities[(int) Capability.CAP_ICON_MULTI] = true; if (Array.IndexOf (Global.Capabilities, "icon-static") > -1) m_capabilities[(int) Capability.CAP_ICON_STATIC] = true; if (Array.IndexOf (Global.Capabilities, "sound") > -1) m_capabilities[(int) Capability.CAP_SOUND] = true; if (Array.IndexOf (Global.Capabilities, "image/svg+xml") > -1) m_capabilities[(int) Capability.CAP_IMAGE_SVG] = true; if (Array.IndexOf (Global.Capabilities, "x-canonical-private-synchronous") > -1) m_capabilities[(int) Capability.CAP_SYNCHRONOUS] = true; if (Array.IndexOf (Global.Capabilities, "x-canonical-append") > -1) m_capabilities[(int) Capability.CAP_APPEND] = true; if (Array.IndexOf (Global.Capabilities, "x-canonical-private-icon-only") > -1) m_capabilities[(int) Capability.CAP_LAYOUT_ICON_ONLY] = true; if (Array.IndexOf (Global.Capabilities, "x-canonical-truncation") > -1) m_capabilities[(int) Capability.CAP_TRUNCATION] = true; } public static bool HasCap (Capability capability) { return m_capabilities[(int) capability]; } public static void PrintCaps () { Console.WriteLine ("Name: " + Global.ServerInformation.Name); Console.WriteLine ("Vendor: " + Global.ServerInformation.Vendor); Console.WriteLine ("Version: " + Global.ServerInformation.Version); Console.WriteLine ("Spec. Version: " + Global.ServerInformation.SpecVersion); Console.WriteLine ("Supported capabilities/hints:"); if (m_capabilities[(int) Capability.CAP_ACTIONS]) Console.WriteLine ("\tactions"); if (m_capabilities[(int) Capability.CAP_BODY]) Console.WriteLine ("\tbody"); if (m_capabilities[(int) Capability.CAP_BODY_HYPERLINKS]) Console.WriteLine ("\tbody-hyperlinks"); if (m_capabilities[(int) Capability.CAP_BODY_IMAGES]) Console.WriteLine ("\tbody-images"); if (m_capabilities[(int) Capability.CAP_BODY_MARKUP]) Console.WriteLine ("\tbody-markup"); if (m_capabilities[(int) Capability.CAP_ICON_MULTI]) Console.WriteLine ("\ticon-multi"); if (m_capabilities[(int) Capability.CAP_ICON_STATIC]) Console.WriteLine ("\ticon-static"); if (m_capabilities[(int) Capability.CAP_SOUND]) Console.WriteLine ("\tsound"); if (m_capabilities[(int) Capability.CAP_IMAGE_SVG]) Console.WriteLine ("\timage/svg+xml"); if (m_capabilities[(int) Capability.CAP_SYNCHRONOUS]) Console.WriteLine ("\tx-canonical-private-synchronous"); if (m_capabilities[(int) Capability.CAP_APPEND]) Console.WriteLine ("\tx-canonical-append"); if (m_capabilities[(int) Capability.CAP_LAYOUT_ICON_ONLY]) Console.WriteLine ("\tx-canonical-private-icon-only"); if (m_capabilities[(int) Capability.CAP_TRUNCATION]) Console.WriteLine ("\tx-canonical-truncation"); Console.WriteLine ("Notes:"); if (Global.ServerInformation.Name == "notify-osd") { Console.WriteLine ("\tx- and y-coordinates hints are ignored"); Console.WriteLine ("\texpire-timeout is ignored"); Console.WriteLine ("\tbody-markup is accepted but filtered"); } else Console.WriteLine ("\tnone"); } } // ExampleUtil.InitCaps () // ExampleUtil.HasCaps (capability) // ExampleUtil.PrintCaps () ./examples/sync-icon-only.py0000755000015600001650000001025212704153542016154 0ustar jenkinsjenkins#!/usr/bin/python ################################################################################ ##3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ## 10 20 30 40 50 60 70 80 ## ## Info: ## Example of how to use libnotify correctly and at the same time comply to ## the new jaunty notification spec (read: visual guidelines) ## ## Run: ## chmod +x sync-icon-only.py ## ./sync-icon-only.py ## ## Copyright 2009 Canonical Ltd. ## ## Author: ## 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 . ## ################################################################################ import sys import pynotify # even in Python this is globally nasty :), do something nicer in your own code capabilities = {'actions': False, 'body': False, 'body-hyperlinks': False, 'body-images': False, 'body-markup': False, 'icon-multi': False, 'icon-static': False, 'sound': False, 'image/svg+xml': False, 'x-canonical-private-synchronous': False, 'x-canonical-append': False, 'x-canonical-private-icon-only': False, 'x-canonical-truncation': False} def initCaps (): caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) for cap in caps: capabilities[cap] = True def printCaps (): info = pynotify.get_server_info () print "Name: " + info["name"] print "Vendor: " + info["vendor"] print "Version: " + info["version"] print "Spec. Version: " + info["spec-version"] caps = pynotify.get_server_caps () if caps is None: print "Failed to receive server caps." sys.exit (1) print "Supported capabilities/hints:" if capabilities['actions']: print "\tactions" if capabilities['body']: print "\tbody" if capabilities['body-hyperlinks']: print "\tbody-hyperlinks" if capabilities['body-images']: print "\tbody-images" if capabilities['body-markup']: print "\tbody-markup" if capabilities['icon-multi']: print "\ticon-multi" if capabilities['icon-static']: print "\ticon-static" if capabilities['sound']: print "\tsound" if capabilities['image/svg+xml']: print "\timage/svg+xml" if capabilities['x-canonical-private-synchronous']: print "\tx-canonical-private-synchronous" if capabilities['x-canonical-append']: print "\tx-canonical-append" if capabilities['x-canonical-private-icon-only']: print "\tx-canonical-private-icon-only" if capabilities['x-canonical-truncation']: print "\tx-canonical-truncation" print "Notes:" if info["name"] == "notify-osd": print "\tx- and y-coordinates hints are ignored" print "\texpire-timeout is ignored" print "\tbody-markup is accepted but filtered" else: print "\tnone" if __name__ == '__main__': if not pynotify.init ("sync-icon-only"): sys.exit (1) # call this so we can savely use capabilities dictionary later initCaps () # show what's supported printCaps () # try sync. icon-only if capabilities['x-canonical-private-icon-only'] and capabilities['x-canonical-private-synchronous']: n = pynotify.Notification ("Eject", # for a11y-reasons put something meaningfull here "", "notification-device-eject") n.set_hint_string ("x-canonical-private-icon-only", "true"); n.set_hint_string ("x-canonical-private-synchronous", "true"); n.show () else: print "The daemon does not support sync. icon-only!" ./examples/update-notifications.cs0000644000015600001650000000524412704153542017403 0ustar jenkinsjenkins//////////////////////////////////////////////////////////////////////////////// //3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 // 10 20 30 40 50 60 70 80 // // Info: // Example of how to use libnotify correctly and at the same time comply to // the new jaunty notification spec (read: visual guidelines) // // Compile and run: // gmcs -pkg:notify-sharp -r:Mono.Posix.dll example-util.cs \ // update-notifications.cs -out:update-notifications.exe // mono update-notifications.exe // // Copyright 2009 Canonical Ltd. // // Author: // 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 . // //////////////////////////////////////////////////////////////////////////////// using System; using Notifications; public class UpdateNotifications { public static void Main () { // call this so we can savely use the m_capabilities array later ExampleUtil.InitCaps (); // show what's supported ExampleUtil.PrintCaps (); // try the icon-summary-body case Notification n = new Notification ( "Inital notification", "This is the original content of this notification-bubble.", "notification-message-im"); n.Show (); Mono.Unix.Native.Syscall.sleep (3); // simulate app activity // update the current notification with new content n.Summary = "Updated notification"; n.Body = "Here the same bubble with new title- and body-text, even the icon can be changed on the update."; n.IconName = "notification-message-email"; n.Show (); Mono.Unix.Native.Syscall.sleep (6); // wait longer now // create a new bubble using the icon-summary-body layout n = new Notification ( "Initial layout", "This bubble uses the icon-title-body layout.", "notification-message-im"); n.Show (); Mono.Unix.Native.Syscall.sleep (3); // simulate app activity // now update current bubble again, but change the layout n.Summary = "Updated layout"; n.Body = "After the update we now have a bubble using the title-body layout."; n.IconName = " "; n.Show (); } } ./ChangeLog0000644000015600001650000000003012704153542012643 0ustar jenkinsjenkinsuse: bzr log | less