merge notification module into core e!

SVN revision: 64475
This commit is contained in:
Mike Blumenkrantz 2011-10-28 02:49:24 +00:00
parent 71fcdc6428
commit f373243dc5
58 changed files with 8781 additions and 0 deletions

View File

@ -635,6 +635,13 @@ fi
AC_SUBST([ENOTIFY_CFLAGS])
AC_SUBST([ENOTIFY_LIBS])
AM_CONDITIONAL(HAVE_NOTIFICATION, false)
define([CHECK_MODULE_NOTIFICATION],
[
if test "x$e_cv_want_enotify" = "xno" ; then
NOTIFICATION=false
fi
])
AM_CONDITIONAL(HAVE_ALSA, false)
define([CHECK_MODULE_MIXER],
@ -695,6 +702,7 @@ AC_E_OPTIONAL_MODULE([clock], true)
AC_E_OPTIONAL_MODULE([pager], true)
AC_E_OPTIONAL_MODULE([battery], true, [CHECK_MODULE_BATTERY])
AC_E_OPTIONAL_MODULE([temperature], true, [CHECK_MODULE_TEMPERATURE])
AC_E_OPTIONAL_MODULE([notification], true, [CHECK_MODULE_NOTIFICATION])
AC_E_OPTIONAL_MODULE([cpufreq], true)
AC_E_OPTIONAL_MODULE([ibox], true)
AC_E_OPTIONAL_MODULE([start], true)
@ -780,6 +788,8 @@ src/modules/battery/Makefile
src/modules/battery/module.desktop
src/modules/temperature/Makefile
src/modules/temperature/module.desktop
src/modules/notification/Makefile
src/modules/notification/module.desktop
src/modules/cpufreq/Makefile
src/modules/cpufreq/module.desktop
src/modules/ibox/Makefile

View File

@ -26,6 +26,10 @@ if USE_MODULE_TEMPERATURE
SUBDIRS += temperature
endif
if USE_MODULE_NOTIFICATION
SUBDIRS += notification
endif
if USE_MODULE_CPUFREQ
SUBDIRS += cpufreq
endif

View File

@ -0,0 +1,3 @@
Brian Mattern <rephorm@rephorm.com>
Samuel Mendes <heka.lok@gmail.com>
Mike Blumenkrantz <mike@zentific.com>

View File

@ -0,0 +1,32 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies of the Software and its Copyright notices. In addition publicly
documented acknowledgment must be given that this software has been used if no
source code of this software is made available publicly. Making the source
available publicly means including the source for this software with the
distribution, or a method to get this software via some reasonable mechanism
(electronic transfer via a network or media) as well as making an offer to
supply the source on request. This Copyright notice serves as an offer to
supply the source on on request as well. Instead of this, supplying
acknowledgments of use of this software in either Copyright notices, Manuals,
Publicity and Marketing documents or any documentation provided with any
product containing this software. This License does not apply to any software
that links to the libraries provided by this software (statically or
dynamically), but only to the software provided.
Please see the COPYING-PLAIN for a plain-english explanation of this notice
and its intent.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,33 @@
Plain English Copyright Notice
This file is not intended to be the actual License. The reason this file
exists is that we here are programmers and engineers. We aren't lawyers. We
provide licenses that we THINK say the right things, but we have our own
intentions at heart. This is a plain-english explanation of what those
intentions are, and if you follow them you will be within the "spirit" of
the license.
The intent is for us to enjoy writing software that is useful to us (the
AUTHORS) and allow others to use it freely and also benefit from the work we
put into making it. We don't want to restrict others using it. They should
not *HAVE* to make the source code of the applications they write that
simply link to these libraries (be that statically or dynamically), or for
them to be limited as to what license they choose to use (be it open, closed
or anything else). But we would like to know you are using these libraries.
We simply would like to know that it has been useful to someone. This is why
we ask for acknowledgement of some sort.
You can do what you want with the source of this software - it doesn't
matter. We still have it here for ourselves and it is open and free to use
and download and play with. It can't be taken away. We don't really mind what
you do with the source to your software. We would simply like to know that
you are using it - especially if it makes it to a commerical product. If you
simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and
then make sure you include a paragraph or page in the manual for the product
with the copyright notice and state that you used this software, we will be
very happy. If you want to contribute back modifications and fixes you may have
made we will welcome those too with open arms (generally). If you want help
with changes needed, ports needed or features to be added, arrangements can
be easily made with some dialogue.
Samuel Mendes <heka.lok@gmail.com>

View File

@ -0,0 +1,33 @@
MAINTAINERCLEANFILES = Makefile.in
MODULE = notification
# data files for the module
filesdir = $(libdir)/enlightenment/modules/$(MODULE)
files_DATA = \
e-module-$(MODULE).edj module.desktop
EXTRA_DIST = $(files_DATA)
# the module .so file
INCLUDES = -I. \
-I$(top_srcdir) \
-I$(top_srcdir)/src/modules/$(MODULE) \
-I$(top_srcdir)/src/bin \
-I$(top_builddir)/src/bin \
-I$(top_srcdir)/src/modules \
@e_cflags@ @ENOTIFY_CFLAGS@
pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
pkg_LTLIBRARIES = module.la
module_la_SOURCES = e_mod_main.h \
e_mod_main.c \
e_mod_config.c
module_la_LIBADD = @e_libs@ @dlopen_libs@ @ENOTIFY_LIBS@
module_la_LDFLAGS = -module -avoid-version
module_la_DEPENDENCIES = $(top_builddir)/config.h
uninstall:
rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)

View File

@ -0,0 +1,28 @@
Notification
This module provide a notification daemon for E.
It implements the galago specification :
http://www.galago-project.org/specs/notification/0.9/index.html
You can be notified in two ways, by popups or by icons. Popups are the usual way
of notifying, you can configure where they should appear and some other options
in E's configuration panel -> extensions -> notification. Notification box is a
gadget with the same style as ibox and go into a shelf. If an event occur the
image associated with the event (or this modules's logo if none) will appear
inside the box. A click on it will try to focus the source application of the
event, by matching the "application name" field with any windows class/name.
Configure a notification box is done by right clicking on it and selecting
"configuration".
By configuring which level of urgency popups and box should show, you can avoid
having both showing up everytime.
The icon displayed in the box may be ugly and aliased. It's due to the fact that
some apps use really small icons. An easy way to fix this is to make sure that
the application doesn't send a pixbuf but a path to the icon instead. And if this
icon is too small, replace it by a bigger one.
If you want to fire up a notification and make the module focus an application,
the easiest way is to use e-notify-send (in e_dbus if built with enotify) like
in this example:
e-notify-send -n classname_of_your_app -i "file:///path/to/an/icon" "foo" "bar"

View File

@ -0,0 +1,358 @@
/* Guidelines for a notification theme.
*
* Groups needed :
* - modules/notification/logo : Logo for the module and it must contain at least one part named image.
* - modules/notification/main : Main theme for the popup
* The theme must contains two parts :
* - notification.swallow.app_icon : Contains the notification icon
* - notification.textblock.message : Contains the notification message
* The module can send those signals to the theme :
* - notification,new : A new notification occured
* - notification,del : The notification is to be deleted
* A notification theme must send those signals to the module :
* - notification,deleted : The notification is ready to be deleted
* Optionally those signals can be used to add some features :
* - notification,close : Close the popup
* - notification,find : Find the source application of the event
*/
images {
image: "module_icon.png" COMP;
image: "e17_menu_bg_border.png" COMP;
image: "base_bg.png" COMP;
image: "base_bg_alpha.png" COMP;
image: "bd_top_hilight.png" COMP;
image: "bd_button_close_shadow.png" COMP;
image: "bd_button_close_focused.png" COMP;
image: "bd_title_bg.png" COMP;
image: "bd_title_over.png" COMP;
}
styles {
style {
name: "notification_style";
base: "font=Sans font_size=10 align=left color=#fcfcfc outline_color=#000 wrap=word text_class=module_normal";
tag: "subject" "+ text_class=module_large font_size=10";
tag: "body" "+ text_class=module_normal font_size=10";
tag: "br" "\n";
tag: "b" "+ font=Sans:style=Bold text_class=module_bold";
tag: "i" "+ font=Sans:style=Oblique text_class=module_bold";
tag: "u" "+ underline=on";
tag: "img" ""; /* images not supported */
tag: "a" ""; /* links not supported */
}
}
collections {
/* Module icon */
group {
name: "icon";
max: 24 24;
parts {
part {
name: "image";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
aspect: 1 1;
image.normal: "module_icon.png";
}
}
}
}
/* Module Logo */
group {
name: "modules/notification/logo";
parts {
part {
name: "image";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
aspect: 1 1;
image.normal: "module_icon.png";
}
}
}
}
group {
name: "modules/notification/main";
data {
item: "app_icon_max" "48 48";
item: "shaped" "1";
}
parts {
part {
name: "clipper";
type: RECT;
mouse_events: 0;
description {
state: "default" 0.0;
color: 255 255 255 255;
rel1 {
relative: 0.0 0.0;
offset: 0 0;
}
rel2 {
relative: 1.0 1.0;
offset: -1 -1;
}
}
description {
state: "mouse_over" 0.0;
inherit: "default" 0.0;
color: 255 255 255 128;
}
description {
state: "hidden" 0.0;
inherit: "default" 0.0;
color: 255 255 255 0;
visible: 0;
}
}
programs {
program {
signal: "mouse,in";
source: "base";
action: STATE_SET "mouse_over" 0.0;
transition: ACCELERATE 0.2;
target: "clipper";
after: "show_base";
}
program {
name: "show_base";
in: 1.5 0.0;
action: STATE_SET "default" 0.0;
transition: ACCELERATE 0.5;
target: "clipper";
}
}
part {
name: "base";
type: IMAGE;
mouse_events: 1;
clip_to: "clipper";
description {
state: "default" 0.0;
color: 255 255 255 210;
image {
normal: "base_bg_alpha.png";
border: 4 4 4 4;
}
}
}
part {
name: "notification.text.title";
type: TEXT;
mouse_events: 0;
scale: 1;
effect: SOFT_SHADOW;
clip_to: "clipper";
description {
state: "default" 0.0;
fixed: 1 1;
visible: 1;
min: 250 0;
max: 250 9999;
align: 0.0 0.0;
rel1 {
to_x: "notification.swallow.app_icon";
relative: 1.0 0.0;
offset: 4 5;
}
rel2 {
relative: 1.0 0.0;
offset: -20 15;
}
color: 224 224 224 255;
color3: 0 0 0 64;
color_class: "menu_title_active";
text {
/* text_source: "notification.text.title"; */
font: "Sans:style=Bold";
size: 10;
align: 0.0 0.0;
min: 0 1;
text_class: "menu_title";
}
}
}
/* Close Button */
part {
name: "bt_close_shadow";
mouse_events: 0;
clip_to: "clipper";
description { state: "default" 0.0;
align: 1.0 0.5;
min: 22 22;
max: 22 22;
fixed: 1 1;
aspect: 1.0 1.0;
aspect_preference: VERTICAL;
rel1 {
relative: 1 0;
offset: -15 5;
}
rel2 {
relative: 1 0;
offset: -2 15;
}
image.normal: "bd_button_close_shadow.png";
}
}
part {
name: "notification.close_btn";
clip_to: "clipper";
description { state: "default" 0.0;
rel1.to: "bt_close_shadow";
rel2.to: "bt_close_shadow";
image.normal: "bd_button_close_focused.png";
}
description { state: "active" 0.0;
inherit: "default" 0.0;
rel1.offset: 0 1;
rel2.offset: -1 0;
}
}
part {
name: "clipper_app_icon";
type: RECT;
mouse_events: 0;
clip_to: "clipper";
description {
state: "default" 0.0;
visible: 1;
color: 255 255 255 255;
rel1 {
relative: 0.0 0.0;
offset: 0 0;
}
rel2 {
relative: 1.0 1.0;
offset: -1 -1;
}
}
description {
state: "hidden" 0.0;
inherit: "default" 0.0;
color: 255 255 255 0;
visible: 0;
}
}
part {
name: "notification.swallow.app_icon";
type: SWALLOW;
mouse_events: 0;
clip_to: "clipper_app_icon";
description {
state: "default" 0.0;
align: 0.0 0.0;
aspect: 1 1;
aspect_preference: BOTH;
rel1 {
/* to_y: "notification.text.title"; */
relative: 0.0 0.0;
offset: 5 5;
}
rel2 {
/* to_y: "notification.text.title"; */
relative: 0.0 1.0;
offset: 52 -9;
}
}
}
/* Message text */
part {
name: "notification.textblock.message";
type: TEXTBLOCK;
mouse_events: 0;
clip_to: "clipper";
description {
state: "default" 0.0;
align: 0.0 0.5;
min: 220 0;
max: 220 9999;
rel1 {
to_x: "notification.swallow.app_icon";
/* to_y: "notification.text.title"; */
relative: 1.0 0.0;
offset: 8 22;
}
rel2 {
relative: 1.0 1.0;
offset: -10 -10;
}
text {
style: "notification_style";
min: 0 1;
}
}
}
}
programs {
program {
name: "notification,new";
signal: "notification,new";
source: "notification";
action: STATE_SET "hidden" 0.0;
target: "clipper_app_icon";
target: "base";
after: "notification,new,2";
}
program {
name: "notification,new,2";
action: STATE_SET "default" 0.0;
transition: SINUSOIDAL 0.5;
target: "clipper_app_icon";
target: "base";
}
program {
name: "notification,del";
signal: "notification,del";
source: "notification";
action: STATE_SET "hidden" 0.0;
transition: ACCELERATE 0.4;
target: "clipper_app_icon";
}
program {
name: "close";
signal: "mouse,down,1";
source: "notification.close_btn";
action: SIGNAL_EMIT "notification,close" "theme";
after: "close_aft";
}
program {
name: "close_aft";
action: STATE_SET "active" 0.0;
target: "notification.close_btn";
}
program { name: "bt_close_up";
signal: "mouse,up,*";
source: "notification.close_btn";
action: STATE_SET "default" 0.0;
target: "notification.close_btn";
}
program {
name: "find";
signal: "mouse,down,1";
source: "base";
action: SIGNAL_EMIT "notification,find" "theme";
}
}
}
}

View File

@ -0,0 +1,748 @@
#include "e_mod_main.h"
/* Notification box protos */
static Notification_Box *_notification_box_new(const char *id,
Evas *evas);
static void _notification_box_free(Notification_Box *b);
static void _notification_box_evas_set(Notification_Box *b,
Evas *evas);
static void _notification_box_empty(Notification_Box *b);
static void _notification_box_resize_handle(Notification_Box *b);
static void _notification_box_empty_handle(Notification_Box *b);
static Eina_List *_notification_box_find(E_Notification_Urgency urgency);
/* Notification box icons protos */
static Notification_Box_Icon *_notification_box_icon_new(Notification_Box *b,
E_Notification *n,
E_Border *bd,
unsigned int id);
static void _notification_box_icon_free(Notification_Box_Icon *ic);
static void _notification_box_icon_fill(Notification_Box_Icon *ic,
E_Notification *n);
static void _notification_box_icon_fill_label(Notification_Box_Icon *ic);
static void _notification_box_icon_empty(Notification_Box_Icon *ic);
static Notification_Box_Icon *_notification_box_icon_find(Notification_Box *b,
E_Border *bd,
unsigned int n_id);
static void _notification_box_icon_signal_emit(Notification_Box_Icon *ic,
char *sig,
char *src);
/* Utils */
static E_Border *_notification_find_source_border(E_Notification *n);
/* Notification box callbacks */
static void _notification_box_cb_menu_post(void *data,
E_Menu *m);
void
notification_box_notify(E_Notification *n,
unsigned int replaces_id,
unsigned int id)
{
Eina_List *n_box;
E_Border *bd;
Notification_Box *b;
Notification_Box_Icon *ic = NULL;
bd = _notification_find_source_border(n);
n_box = _notification_box_find(e_notification_hint_urgency_get(n));
EINA_LIST_FREE(n_box, b)
{
if (bd || replaces_id)
ic = _notification_box_icon_find(b, bd, replaces_id);
if (ic)
{
e_notification_unref(ic->notif);
e_notification_ref(n);
ic->notif = n;
ic->n_id = id;
_notification_box_icon_empty(ic);
_notification_box_icon_fill(ic, n);
}
else
{
ic = _notification_box_icon_new(b, n, bd, id);
if (!ic) continue;
b->icons = eina_list_append(b->icons, ic);
e_box_pack_end(b->o_box, ic->o_holder);
}
_notification_box_empty_handle(b);
_notification_box_resize_handle(b);
_gc_orient(b->inst->gcc, b->inst->gcc->gadcon->orient);
}
}
void
notification_box_shutdown(void)
{
Notification_Box *b;
EINA_LIST_FREE(notification_cfg->n_box, b)
{
if (b) _notification_box_free(b);
}
}
void
notification_box_del(const char *id)
{
Eina_List *l;
Notification_Box *b;
/* Find old config */
EINA_LIST_FOREACH(notification_cfg->n_box, l, b)
{
if (b->id == id)
{
_notification_box_free(b);
notification_cfg->n_box = eina_list_remove(notification_cfg->n_box, b);
return;
}
}
}
void
notification_box_visible_set(Notification_Box *b, Eina_Bool visible)
{
Eina_List *l;
Notification_Box_Icon *ic;
Ecore_Cb cb = (Ecore_Cb)(visible ? evas_object_show : evas_object_hide);
cb(b->o_box);
if (b->o_empty) cb(b->o_empty);
EINA_LIST_FOREACH(b->icons, l, ic)
{
if (!ic) continue;
cb(ic->o_holder);
cb(ic->o_holder2);
cb(ic->o_icon);
cb(ic->o_icon2);
}
}
Notification_Box *
notification_box_get(const char *id,
Evas *evas)
{
Eina_List *l;
Notification_Box *b;
/* Find old config */
EINA_LIST_FOREACH(notification_cfg->n_box, l, b)
{
if (b->id == id)
{
_notification_box_evas_set(b, evas);
notification_box_visible_set(b, EINA_TRUE);
return b;
}
}
b = _notification_box_new(id, evas);
notification_cfg->n_box = eina_list_append(notification_cfg->n_box, b);
return b;
}
Config_Item *
notification_box_config_item_get(const char *id)
{
Config_Item *ci;
GADCON_CLIENT_CONFIG_GET(Config_Item, notification_cfg->items, _gc_class, id);
ci = E_NEW(Config_Item, 1);
ci->id = eina_stringshare_ref(id);
ci->show_label = 1;
ci->show_popup = 1;
ci->focus_window = 1;
ci->store_low = 1;
ci->store_normal = 1;
ci->store_critical = 0;
notification_cfg->items = eina_list_append(notification_cfg->items, ci);
return ci;
}
void
notification_box_orient_set(Notification_Box *b,
int horizontal)
{
e_box_orientation_set(b->o_box, horizontal);
e_box_align_set(b->o_box, 0.5, 0.5);
}
void
notification_box_cb_obj_moveresize(void *data,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
Instance *inst;
inst = data;
_notification_box_resize_handle(inst->n_box);
}
Eina_Bool
notification_box_cb_border_remove(void *data __UNUSED__,
int type __UNUSED__,
E_Event_Border_Remove *ev)
{
Notification_Box_Icon *ic;
Eina_List *l;
Instance *inst;
EINA_LIST_FOREACH(notification_cfg->instances, l, inst)
{
Notification_Box *b;
if (!inst) continue;
b = inst->n_box;
ic = _notification_box_icon_find(b, ev->border, 0);
if (!ic) continue;
b->icons = eina_list_remove(b->icons, ic);
_notification_box_icon_free(ic);
_notification_box_empty_handle(b);
_notification_box_resize_handle(b);
_gc_orient(inst->gcc, inst->gcc->gadcon->orient);
}
return ECORE_CALLBACK_RENEW;
}
static Notification_Box *
_notification_box_new(const char *id,
Evas *evas)
{
Notification_Box *b;
b = E_NEW(Notification_Box, 1);
b->id = eina_stringshare_ref(id);
b->o_box = e_box_add(evas);
e_box_homogenous_set(b->o_box, 1);
e_box_orientation_set(b->o_box, 1);
e_box_align_set(b->o_box, 0.5, 0.5);
_notification_box_empty(b);
return b;
}
static void
_notification_box_free(Notification_Box *b)
{
_notification_box_empty(b);
eina_stringshare_del(b->id);
evas_object_del(b->o_box);
if (b->o_empty) evas_object_del(b->o_empty);
b->o_empty = NULL;
free(b);
}
static void
_notification_box_evas_set(Notification_Box *b,
Evas *evas)
{
Eina_List *new_icons = NULL;
Notification_Box_Icon *ic, *new_ic;
evas_object_del(b->o_box);
if (b->o_empty) evas_object_del(b->o_empty);
b->o_empty = NULL;
b->o_box = e_box_add(evas);
e_box_homogenous_set(b->o_box, 1);
e_box_orientation_set(b->o_box, 1);
e_box_align_set(b->o_box, 0.5, 0.5);
EINA_LIST_FREE(b->icons, ic)
{
if (!ic) continue;
new_ic = _notification_box_icon_new(b, ic->notif, ic->border, ic->n_id);
_notification_box_icon_free(ic);
new_icons = eina_list_append(new_icons, new_ic);
e_box_pack_end(b->o_box, new_ic->o_holder);
}
b->icons = new_icons;
_notification_box_empty_handle(b);
_notification_box_resize_handle(b);
}
static void
_notification_box_empty(Notification_Box *b)
{
Notification_Box_Icon *ic;
EINA_LIST_FREE(b->icons, ic)
_notification_box_icon_free(b->icons->data);
_notification_box_empty_handle(b);
}
static void
_notification_box_resize_handle(Notification_Box *b)
{
Notification_Box_Icon *ic;
Evas_Coord w, h;
evas_object_geometry_get(b->o_box, NULL, NULL, &w, &h);
if (e_box_orientation_get(b->o_box))
w = h;
else
h = w;
e_box_freeze(b->o_box);
EINA_LIST_FREE(b->icons, ic)
e_box_pack_options_set(ic->o_holder, 1, 1, 0, 0, 0.5, 0.5, w, h, w, h);
e_box_thaw(b->o_box);
}
static Eina_List *
_notification_box_find(E_Notification_Urgency urgency)
{
Eina_List *l, *n_box = NULL;
Instance *inst;
EINA_LIST_FOREACH(notification_cfg->instances, l, inst)
{
if ((urgency == E_NOTIFICATION_URGENCY_LOW) && (!inst->ci->store_low))
continue;
if ((urgency == E_NOTIFICATION_URGENCY_NORMAL) && (!inst->ci->store_normal))
continue;
if ((urgency == E_NOTIFICATION_URGENCY_CRITICAL) && (!inst->ci->store_critical))
continue;
n_box = eina_list_append(n_box, inst->n_box);
}
return n_box;
}
static void
_notification_box_icon_free(Notification_Box_Icon *ic)
{
if (notification_cfg->menu)
{
e_menu_post_deactivate_callback_set(notification_cfg->menu, NULL, NULL);
e_object_del(E_OBJECT(notification_cfg->menu));
notification_cfg->menu = NULL;
}
_notification_box_icon_empty(ic);
evas_object_del(ic->o_holder);
evas_object_del(ic->o_holder2);
if (ic->border) e_object_unref(E_OBJECT(ic->border));
if (ic->notif) e_notification_unref(ic->notif);
free(ic);
}
static void
_notification_box_icon_fill(Notification_Box_Icon *ic,
E_Notification *n)
{
void *img;
const char *icon_path;
Evas_Object *app_icon;
Evas_Object *dummy = NULL;
int w, h = 0;
if ((icon_path = e_notification_app_icon_get(n)) && *icon_path)
{
if (!memcmp(icon_path, "file://", 7)) icon_path += 7;
app_icon = evas_object_image_add(evas_object_evas_get(ic->n_box->o_box));
evas_object_image_load_scale_down_set(app_icon, 1);
evas_object_image_load_size_set(app_icon, 80, 80);
evas_object_image_file_set(app_icon, icon_path, NULL);
evas_object_image_fill_set(app_icon, 0, 0, 80, 80);
}
else if ((img = e_notification_hint_icon_data_get(n)))
{
app_icon = e_notification_image_evas_object_add(evas_object_evas_get(ic->n_box->o_box), img);
}
else
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/e-module-notification.edj", notification_mod->dir);
dummy = edje_object_add(evas_object_evas_get(ic->n_box->o_box));
if (!e_theme_edje_object_set(dummy, "base/theme/modules/notification",
"modules/notification/logo"))
edje_object_file_set(dummy, buf, "modules/notification/logo");
evas_object_resize(dummy, 80, 80);
app_icon = (Evas_Object*)edje_object_part_object_get(dummy, "image");
}
evas_object_image_size_get(app_icon, &w, &h);
ic->o_icon = e_icon_add(evas_object_evas_get(ic->n_box->o_box));
e_icon_alpha_set(ic->o_icon, 1);
e_icon_data_set(ic->o_icon, evas_object_image_data_get(app_icon, 0), w, h);
edje_object_part_swallow(ic->o_holder, "e.swallow.content", ic->o_icon);
evas_object_pass_events_set(ic->o_icon, 1);
evas_object_show(ic->o_icon);
ic->o_icon2 = e_icon_add(evas_object_evas_get(ic->n_box->o_box));
e_icon_alpha_set(ic->o_icon2, 1);
e_icon_data_set(ic->o_icon2, evas_object_image_data_get(app_icon, 0), w, h);
edje_object_part_swallow(ic->o_holder2, "e.swallow.content", ic->o_icon2);
evas_object_pass_events_set(ic->o_icon2, 1);
evas_object_show(ic->o_icon2);
if (dummy) evas_object_del(dummy);
evas_object_del(app_icon);
_notification_box_icon_fill_label(ic);
}
static void
_notification_box_icon_fill_label(Notification_Box_Icon *ic)
{
const char *label = NULL;
if (ic->border)
label = ic->border->client.netwm.name;
if (!label) label = e_notification_app_name_get(ic->notif);
edje_object_part_text_set(ic->o_holder, "e.text.label", label);
edje_object_part_text_set(ic->o_holder2, "e.text.label", label);
}
static void
_notification_box_icon_empty(Notification_Box_Icon *ic)
{
if (ic->o_icon) evas_object_del(ic->o_icon);
if (ic->o_icon2) evas_object_del(ic->o_icon2);
ic->o_icon2 = ic->o_icon = NULL;
}
static Notification_Box_Icon *
_notification_box_icon_find(Notification_Box *b,
E_Border *bd,
unsigned int n_id)
{
Eina_List *l;
Notification_Box_Icon *ic;
EINA_LIST_FOREACH(b->icons, l, ic)
{
if (!ic) continue;
if ((ic->border == bd) || (ic->n_id == n_id))
return ic;
}
return NULL;
}
static void
_notification_box_icon_signal_emit(Notification_Box_Icon *ic,
char *sig,
char *src)
{
if (ic->o_holder)
edje_object_signal_emit(ic->o_holder, sig, src);
if (ic->o_icon)
edje_object_signal_emit(ic->o_icon, sig, src);
if (ic->o_holder2)
edje_object_signal_emit(ic->o_holder2, sig, src);
if (ic->o_icon2)
edje_object_signal_emit(ic->o_icon2, sig, src);
}
static E_Border *
_notification_find_source_border(E_Notification *n)
{
const char *app_name;
Eina_List *l;
E_Border *bd;
if (!(app_name = e_notification_app_name_get(n))) return NULL;
EINA_LIST_FOREACH(e_border_client_list(), l, bd)
{
size_t app, test;
if ((!bd) || ((!bd->client.icccm.name) && (!bd->client.icccm.class))) continue;
/* We can't be sure that the app_name really match the application name.
* Some plugin put their name instead. But this search gives some good
* results.
*/
app = strlen(app_name);
if (bd->client.icccm.name)
{
test = eina_strlen_bounded(bd->client.icccm.name, app + 1);
if (!strncasecmp(bd->client.icccm.name, app_name, (app < test) ? app : test))
return bd;
}
if (bd->client.icccm.class)
{
test = eina_strlen_bounded(bd->client.icccm.class, app + 1);
if (!strncasecmp(bd->client.icccm.class, app_name, (app < test) ? app : test))
return bd;
}
}
return NULL;
}
static void
_notification_box_cb_menu_post(void *data __UNUSED__,
E_Menu *m __UNUSED__)
{
if (!notification_cfg->menu) return;
e_object_del(E_OBJECT(notification_cfg->menu));
notification_cfg->menu = NULL;
}
static void
_notification_box_cb_menu_configuration(Notification_Box *b,
E_Menu *m __UNUSED__,
E_Menu_Item *mi __UNUSED__)
{
Eina_List *l;
E_Config_Dialog *cfd;
EINA_LIST_FOREACH(notification_cfg->config_dialog, l, cfd)
{
if (cfd->data == b->inst->ci) return;
}
config_notification_box_module(b->inst->ci);
}
static void
_notification_box_cb_empty_mouse_down(Notification_Box *b,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
Evas_Event_Mouse_Down *ev)
{
E_Menu *m;
E_Menu_Item *mi;
int cx, cy, cw, ch;
if (notification_cfg->menu) return;
m = e_menu_new();
mi = e_menu_item_new(m);
e_menu_item_label_set(mi, D_("Settings"));
e_util_menu_item_theme_icon_set(mi, "preferences-system");
e_menu_item_callback_set(mi, (E_Menu_Cb)_notification_box_cb_menu_configuration, b);
notification_cfg->menu = m = e_gadcon_client_util_menu_items_append(b->inst->gcc, m, 0);
e_menu_post_deactivate_callback_set(m, _notification_box_cb_menu_post, NULL);
e_gadcon_canvas_zone_geometry_get(b->inst->gcc->gadcon,
&cx, &cy, &cw, &ch);
e_menu_activate_mouse(m,
e_util_zone_current_get(e_manager_current_get()),
cx + ev->output.x, cy + ev->output.y, 1, 1,
E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
}
static void
_notification_box_cb_icon_move(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
Evas_Coord x, y;
evas_object_geometry_get(ic->o_holder, &x, &y, NULL, NULL);
evas_object_move(ic->o_holder2, x, y);
evas_object_raise(ic->o_holder2);
}
static void
_notification_box_cb_icon_resize(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
Evas_Coord w, h;
evas_object_geometry_get(ic->o_holder, NULL, NULL, &w, &h);
evas_object_resize(ic->o_holder2, w, h);
evas_object_raise(ic->o_holder2);
}
static Eina_Bool
_notification_box_cb_icon_mouse_still_in(Notification_Box_Icon *ic)
{
e_notification_timeout_set(ic->notif, 0);
e_notification_hint_urgency_set(ic->notif, 4);
ic->popup = notification_popup_notify(ic->notif,
e_notification_id_get(ic->notif),
e_notification_app_name_get(ic->notif));
ecore_timer_del(ic->mouse_in_timer);
ic->mouse_in_timer = NULL;
return EINA_FALSE;
}
static void
_notification_box_cb_icon_mouse_in(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
Config_Item *ci;
if ((!ic) || !ic->n_box || !ic->n_box->inst) return;
if (!(ci = ic->n_box->inst->ci)) return;
_notification_box_icon_signal_emit(ic, "e,state,focused", "e");
if (ci->show_label)
{
_notification_box_icon_fill_label(ic);
_notification_box_icon_signal_emit(ic, "e,action,show,label", "e");
}
if (ci->show_popup && !ic->popup && !ic->mouse_in_timer)
ic->mouse_in_timer = ecore_timer_add(0.5, (Ecore_Task_Cb)_notification_box_cb_icon_mouse_still_in, ic);
}
static void
_notification_box_cb_icon_mouse_out(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
void *event_info __UNUSED__)
{
_notification_box_icon_signal_emit(ic, "e,state,unfocused", "e");
if (ic->n_box->inst->ci->show_label)
_notification_box_icon_signal_emit(ic, "e,action,hide,label", "e");
if (ic->mouse_in_timer)
{
ecore_timer_del(ic->mouse_in_timer);
ic->mouse_in_timer = NULL;
}
if (ic->popup)
{
notification_popup_close(e_notification_id_get(ic->notif));
ic->popup = 0;
}
}
static void
_notification_box_cb_icon_mouse_up(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
Evas_Event_Mouse_Up *ev)
{
Notification_Box *b;
b = ic->n_box;
if (ev->button != 1) return;
if (b->inst->ci->focus_window && ic->border)
{
e_border_uniconify(ic->border);
e_desk_show(ic->border->desk);
e_border_show(ic->border);
e_border_raise(ic->border);
e_border_focus_set(ic->border, 1, 1);
}
b->icons = eina_list_remove(b->icons, ic);
_notification_box_icon_free(ic);
_notification_box_empty_handle(b);
_notification_box_resize_handle(b);
_gc_orient(b->inst->gcc, b->inst->gcc->gadcon->orient);
}
static void
_notification_box_cb_icon_mouse_down(Notification_Box_Icon *ic,
Evas *e __UNUSED__,
Evas_Object *obj __UNUSED__,
Evas_Event_Mouse_Down *ev)
{
E_Menu *m;
E_Menu_Item *mi;
int cx, cy, cw, ch;
if (notification_cfg->menu || (ev->button != 3)) return;
m = e_menu_new();
mi = e_menu_item_new(m);
e_menu_item_label_set(mi, D_("Settings"));
e_util_menu_item_theme_icon_set(mi, "preferences-system");
e_menu_item_callback_set(mi, (E_Menu_Cb)_notification_box_cb_menu_configuration, ic->n_box);
m = e_gadcon_client_util_menu_items_append(ic->n_box->inst->gcc, m, 0);
e_menu_post_deactivate_callback_set(m, _notification_box_cb_menu_post, NULL);
notification_cfg->menu = m;
e_gadcon_canvas_zone_geometry_get(ic->n_box->inst->gcc->gadcon,
&cx, &cy, &cw, &ch);
e_menu_activate_mouse(m,
e_util_zone_current_get(e_manager_current_get()),
cx + ev->output.x, cy + ev->output.y, 1, 1,
E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
}
static void
_notification_box_empty_handle(Notification_Box *b)
{
if (!b->icons)
{
Evas_Coord w, h;
if (b->o_empty) return;
b->o_empty = evas_object_rectangle_add(evas_object_evas_get(b->o_box));
evas_object_event_callback_add(b->o_empty, EVAS_CALLBACK_MOUSE_DOWN,
(Evas_Object_Event_Cb)_notification_box_cb_empty_mouse_down, b);
evas_object_color_set(b->o_empty, 0, 0, 0, 0);
evas_object_show(b->o_empty);
e_box_pack_end(b->o_box, b->o_empty);
evas_object_geometry_get(b->o_box, NULL, NULL, &w, &h);
if (e_box_orientation_get(b->o_box))
w = h;
else
h = w;
e_box_pack_options_set(b->o_empty,
1, 1, /* fill */
1, 1, /* expand */
0.5, 0.5, /* align */
w, h, /* min */
9999, 9999 /* max */
);
}
else if (b->o_empty)
{
evas_object_del(b->o_empty);
b->o_empty = NULL;
}
}
static Notification_Box_Icon *
_notification_box_icon_new(Notification_Box *b,
E_Notification *n,
E_Border *bd,
unsigned int id)
{
Notification_Box_Icon *ic;
ic = E_NEW(Notification_Box_Icon, 1);
if (bd) e_object_ref(E_OBJECT(bd));
e_notification_ref(n);
ic->label = e_notification_app_name_get(n);
ic->n_box = b;
ic->n_id = id;
ic->border = bd;
ic->notif = n;
ic->o_holder = edje_object_add(evas_object_evas_get(b->o_box));
e_theme_edje_object_set(ic->o_holder, "base/theme/modules/ibox",
"e/modules/ibox/icon");
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_MOUSE_IN,
(Evas_Object_Event_Cb)_notification_box_cb_icon_mouse_in, ic);
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_MOUSE_OUT,
(Evas_Object_Event_Cb)_notification_box_cb_icon_mouse_out, ic);
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_MOUSE_DOWN,
(Evas_Object_Event_Cb)_notification_box_cb_icon_mouse_down, ic);
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_MOUSE_UP,
(Evas_Object_Event_Cb)_notification_box_cb_icon_mouse_up, ic);
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_MOVE,
(Evas_Object_Event_Cb)_notification_box_cb_icon_move, ic);
evas_object_event_callback_add(ic->o_holder, EVAS_CALLBACK_RESIZE,
(Evas_Object_Event_Cb)_notification_box_cb_icon_resize, ic);
evas_object_show(ic->o_holder);
ic->o_holder2 = edje_object_add(evas_object_evas_get(b->o_box));
e_theme_edje_object_set(ic->o_holder2, "base/theme/modules/ibox",
"e/modules/ibox/icon_overlay");
evas_object_layer_set(ic->o_holder2, 9999);
evas_object_pass_events_set(ic->o_holder2, 1);
evas_object_show(ic->o_holder2);
_notification_box_icon_fill(ic, n);
return ic;
}

View File

@ -0,0 +1,163 @@
#include "e_mod_main.h"
struct _E_Config_Dialog_Data
{
int show_low;
int show_normal;
int show_critical;
int force_timeout;
int ignore_replacement;
double timeout;
int corner;
};
/* local function protos */
static void *_create_data(E_Config_Dialog *cfd);
static void _free_data(E_Config_Dialog *cfd,
E_Config_Dialog_Data *cfdata);
static void _fill_data(E_Config_Dialog_Data *cfdata);
static Evas_Object *_basic_create(E_Config_Dialog *cfd,
Evas *evas,
E_Config_Dialog_Data *cfdata);
static int _basic_apply(E_Config_Dialog *cfd,
E_Config_Dialog_Data *cfdata);
E_Config_Dialog *
e_int_config_notification_module(E_Container *con,
const char *params __UNUSED__)
{
E_Config_Dialog *cfd = NULL;
E_Config_Dialog_View *v = NULL;
char buf[4096];
if (e_config_dialog_find("Notification", "extensions/notification")) return NULL;
v = E_NEW(E_Config_Dialog_View, 1);
if (!v) return NULL;
v->create_cfdata = _create_data;
v->free_cfdata = _free_data;
v->basic.create_widgets = _basic_create;
v->basic.apply_cfdata = _basic_apply;
snprintf(buf, sizeof(buf), "%s/e-module-notification.edj", notification_mod->dir);
cfd = e_config_dialog_new(con, D_("Notification Settings"), "Notification",
"extensions/notification", buf, 0, v, NULL);
notification_cfg->cfd = cfd;
return cfd;
}
/* local functions */
static void *
_create_data(E_Config_Dialog *cfd __UNUSED__)
{
E_Config_Dialog_Data *cfdata = NULL;
cfdata = E_NEW(E_Config_Dialog_Data, 1);
_fill_data(cfdata);
return cfdata;
}
static void
_free_data(E_Config_Dialog *cfd __UNUSED__,
E_Config_Dialog_Data *cfdata)
{
notification_cfg->cfd = NULL;
E_FREE(cfdata);
}
static void
_fill_data(E_Config_Dialog_Data *cfdata)
{
cfdata->show_low = notification_cfg->show_low;
cfdata->show_normal = notification_cfg->show_normal;
cfdata->show_critical = notification_cfg->show_critical;
cfdata->timeout = notification_cfg->timeout;
cfdata->corner = notification_cfg->corner;
cfdata->force_timeout = notification_cfg->force_timeout;
cfdata->ignore_replacement = notification_cfg->ignore_replacement;
}
static Evas_Object *
_basic_create(E_Config_Dialog *cfd __UNUSED__,
Evas *evas,
E_Config_Dialog_Data *cfdata)
{
Evas_Object *o = NULL, *of = NULL, *ow = NULL;
E_Radio_Group *rg;
// E_Manager *man;
o = e_widget_list_add(evas, 0, 0);
of = e_widget_framelist_add(evas, D_("Urgency"), 0);
ow = e_widget_label_add(evas, D_("Levels of urgency to display:"));
e_widget_framelist_object_append(of, ow);
ow = e_widget_check_add(evas, D_("Low"), &(cfdata->show_low));
e_widget_framelist_object_append(of, ow);
ow = e_widget_check_add(evas, D_("Normal"), &(cfdata->show_normal));
e_widget_framelist_object_append(of, ow);
ow = e_widget_check_add(evas, D_("Critical"), &(cfdata->show_critical));
e_widget_framelist_object_append(of, ow);
e_widget_list_object_append(o, of, 1, 1, 0.5);
of = e_widget_framelist_add(evas, D_("Default Timeout"), 0);
ow = e_widget_check_add(evas, D_("Force timeout for all notifications"), &(cfdata->force_timeout));
e_widget_framelist_object_append(of, ow);
ow = e_widget_slider_add(evas, 1, 0, D_("%.1f seconds"), 0.0, 15.0, 0.1, 0,
&(cfdata->timeout), NULL, 200);
e_widget_framelist_object_append(of, ow);
e_widget_list_object_append(o, of, 1, 1, 0.5);
/* man = e_manager_current_get();
* of = e_widget_framelist_add(evas, D_("Placement"), 0);
* ow = e_widget_slider_add(evas, 1, 0, D_("%2.0f x"), 0.0, man->w, 1.0, 0,
* NULL, &(cfdata->placement.x), 200);
* e_widget_framelist_object_append(of, ow);
* ow = e_widget_slider_add(evas, 1, 0, D_("%2.0f y"), 0.0, man->h, 1.0, 0,
* NULL, &(cfdata->placement.y), 200);
* e_widget_framelist_object_append(of, ow);
* e_widget_list_object_append(o, of, 1, 1, 0.5); */
of = e_widget_framelist_add(evas, D_("Popup Corner"), 0);
rg = e_widget_radio_group_new(&(cfdata->corner));
ow = e_widget_radio_add(evas, "Top left", CORNER_TL, rg);
e_widget_framelist_object_append(of, ow);
ow = e_widget_radio_add(evas, "Top right", CORNER_TR, rg);
e_widget_framelist_object_append(of, ow);
ow = e_widget_radio_add(evas, "Botton left", CORNER_BL, rg);
e_widget_framelist_object_append(of, ow);
ow = e_widget_radio_add(evas, "Bottom right", CORNER_BR, rg);
e_widget_framelist_object_append(of, ow);
e_widget_list_object_append(o, of, 1, 1, 0.5);
/* of = e_widget_framelist_add(evas, D_("Gap"), 0);
* ow = e_widget_label_add(evas, D_("Size of the gap between two popups : "));
* e_widget_framelist_object_append(of, ow);
* ow = e_widget_slider_add(evas, 1, 0, D_("%2.0f pixels"), 0.0, 50, 1.0, 0,
* NULL, &(cfdata->gap), 200);
* e_widget_framelist_object_append(of, ow);
* e_widget_list_object_append(o, of, 1, 1, 0.5); */
of = e_widget_framelist_add(evas, D_("Miscellaneous"), 0);
ow = e_widget_check_add(evas, D_("Ignore replace ID"), &(cfdata->ignore_replacement));
e_widget_framelist_object_append(of, ow);
e_widget_list_object_append(o, of, 1, 1, 0.5);
return o;
}
static int
_basic_apply(E_Config_Dialog *cfd __UNUSED__,
E_Config_Dialog_Data *cfdata)
{
notification_cfg->show_low = cfdata->show_low;
notification_cfg->show_normal = cfdata->show_normal;
notification_cfg->show_critical = cfdata->show_critical;
notification_cfg->timeout = cfdata->timeout;
notification_cfg->corner = cfdata->corner;
notification_cfg->force_timeout = cfdata->force_timeout;
notification_cfg->ignore_replacement = cfdata->ignore_replacement;
e_modapi_save(notification_mod);
return 1;
}

View File

@ -0,0 +1,129 @@
#include "e_mod_main.h"
struct _E_Config_Dialog_Data
{
int show_label;
int show_popup;
int focus_window;
int store_low;
int store_normal;
int store_critical;
};
static void _ci_fill_data(Config_Item *ci,
E_Config_Dialog_Data *cfdata);
static void *_ci_create_data(E_Config_Dialog *cfd);
static void _ci_free_data(E_Config_Dialog *cfd,
E_Config_Dialog_Data *cfdata);
static Evas_Object *_ci_basic_create_widgets(E_Config_Dialog *cfd,
Evas *evas,
E_Config_Dialog_Data *cfdata);
static int _ci_basic_apply_data(E_Config_Dialog *cfd,
E_Config_Dialog_Data *cfdata);
void
config_notification_box_module(Config_Item *ci)
{
E_Config_Dialog *cfd;
E_Config_Dialog_View *v;
char buf[4096];
v = E_NEW(E_Config_Dialog_View, 1);
/* Dialog Methods */
v->create_cfdata = _ci_create_data;
v->free_cfdata = _ci_free_data;
v->basic.apply_cfdata = _ci_basic_apply_data;
v->basic.create_widgets = _ci_basic_create_widgets;
/* Create The Dialog */
snprintf(buf, sizeof(buf), "%s/e-module-notification.edj", e_module_dir_get(notification_mod));
cfd = e_config_dialog_new(e_container_current_get(e_manager_current_get()),
D_("Notification Box Configuration"),
"E", "_e_mod_notification_box_config_dialog",
buf, 0, v, ci);
notification_cfg->config_dialog = eina_list_append(notification_cfg->config_dialog, cfd);
}
static void
_ci_fill_data(Config_Item *ci,
E_Config_Dialog_Data *cfdata)
{
cfdata->show_label = ci->show_label;
cfdata->show_popup = ci->show_popup;
cfdata->focus_window = ci->focus_window;
cfdata->store_low = ci->store_low;
cfdata->store_normal = ci->store_normal;
cfdata->store_critical = ci->store_critical;
}
static void *
_ci_create_data(E_Config_Dialog *cfd)
{
E_Config_Dialog_Data *cfdata;
Config_Item *ci;
ci = cfd->data;
cfdata = E_NEW(E_Config_Dialog_Data, 1);
_ci_fill_data(ci, cfdata);
return cfdata;
}
static void
_ci_free_data(E_Config_Dialog *cfd,
E_Config_Dialog_Data *cfdata)
{
notification_cfg->config_dialog = eina_list_remove(notification_cfg->config_dialog, cfd);
free(cfdata);
}
static Evas_Object *
_ci_basic_create_widgets(E_Config_Dialog *cfd __UNUSED__,
Evas *evas,