1 #include "e_mod_main.h"
3 /* Popup function protos */
4 static Popup_Data *_notification_popup_new(E_Notification *n);
5 static Popup_Data *_notification_popup_find(unsigned int id);
6 static Popup_Data *_notification_popup_merge(E_Notification *n);
8 static int _notification_popup_place(Popup_Data *popup,
10 static void _notification_popup_refresh(Popup_Data *popup);
11 static void _notification_popup_del(unsigned int id,
12 E_Notification_Closed_Reason reason);
13 static void _notification_popdown(Popup_Data *popup,
14 E_Notification_Closed_Reason reason);
17 static int popups_displayed = 0;
19 /* Util function protos */
20 static void _notification_format_message(Popup_Data *popup);
22 static int next_pos = 0;
25 _notification_timer_cb(Popup_Data *popup)
27 _notification_popup_del(e_notification_id_get(popup->notif),
28 E_NOTIFICATION_CLOSED_EXPIRED);
33 notification_popup_notify(E_Notification *n,
34 unsigned int replaces_id,
35 const char *appname __UNUSED__)
38 Popup_Data *popup = NULL;
41 urgency = e_notification_hint_urgency_get(n);
45 case E_NOTIFICATION_URGENCY_LOW:
46 if (!notification_cfg->show_low) return 0;
48 case E_NOTIFICATION_URGENCY_NORMAL:
49 if (!notification_cfg->show_normal) return 0;
51 case E_NOTIFICATION_URGENCY_CRITICAL:
52 if (!notification_cfg->show_critical) return 0;
58 if (notification_cfg->ignore_replacement) replaces_id = 0;
59 if (replaces_id && (popup = _notification_popup_find(replaces_id)))
61 e_notification_ref(n);
64 e_notification_unref(popup->notif);
67 _notification_popup_refresh(popup);
69 else if (!replaces_id)
71 if ((popup = _notification_popup_merge(n)))
72 _notification_popup_refresh(popup);
77 popup = _notification_popup_new(n);
79 notification_cfg->popups = eina_list_append(notification_cfg->popups, popup);
80 edje_object_signal_emit(popup->theme, "notification,new", "notification");
85 ecore_timer_del(popup->timer);
89 timeout = e_notification_timeout_get(popup->notif);
91 if (timeout < 0 || notification_cfg->force_timeout)
92 timeout = notification_cfg->timeout;
93 else timeout = (double)timeout / 1000.0;
96 popup->timer = ecore_timer_add(timeout, (Ecore_Task_Cb)_notification_timer_cb, popup);
102 notification_popup_shutdown(void)
106 EINA_LIST_FREE(notification_cfg->popups, popup)
107 _notification_popdown(popup, E_NOTIFICATION_CLOSED_REQUESTED);
111 notification_popup_close(unsigned int id)
113 _notification_popup_del(id, E_NOTIFICATION_CLOSED_REQUESTED);
117 _notification_popup_merge(E_Notification *n)
121 E_Notification_Action *a, *a2;
123 const char *str1, *str2;
124 const char *body_old;
125 const char *body_new;
129 str1 = e_notification_app_name_get(n);
130 if (!str1) return NULL;
132 EINA_LIST_FOREACH(notification_cfg->popups, l, popup)
134 if (!popup->notif) continue;
135 if (!(str2 = e_notification_app_name_get(popup->notif)))
137 if (str1 == str2) break;
142 /* printf("- no poup to merge\n"); */
146 str1 = e_notification_summary_get(n);
147 str2 = e_notification_summary_get(popup->notif);
149 if (str1 && str2 && (str1 != str2))
151 /* printf("- summary doesn match, %s, %s\n", str1, str2); */
155 l = e_notification_actions_get(popup->notif);
156 l2 = e_notification_actions_get(n);
157 if ((!!l) + (!!l2) == 1)
159 /* printf("- actions dont match\n"); */
162 for (i = l, i2 = l2; i && i2; i = i->next, i2 = i2->next)
164 if ((!!i) + (!!i2) == 1) return NULL;
165 a = i->data, a2 = i2->data;
166 if ((!!a) + (!!a2) == 1) return NULL;
167 if (e_notification_action_id_get(a) !=
168 e_notification_action_id_get(a2)) return NULL;
169 if (e_notification_action_name_get(a) !=
170 e_notification_action_name_get(a2)) return NULL;
173 /* TODO p->n is not fallback alert..*/
174 /* TODO both allow merging */
176 body_old = e_notification_body_get(popup->notif);
177 body_new = e_notification_body_get(n);
179 len = strlen(body_old);
180 len += strlen(body_new);
181 len += 4; /* "<ps>" */
182 if (len < 65536) body_final = alloca(len + 1);
183 else body_final = malloc(len + 1);
184 snprintf(body_final, len + 1, "%s<ps>%s", body_old, body_new);
185 /* printf("set body %s\n", body_final); */
187 e_notification_body_set(n, body_final);
189 e_notification_unref(popup->notif);
191 e_notification_ref(popup->notif);
192 if (len >= 65536) free(body_final);
199 _notification_theme_cb_deleted(Popup_Data *popup,
200 Evas_Object *obj __UNUSED__,
201 const char *emission __UNUSED__,
202 const char *source __UNUSED__)
204 _notification_popup_refresh(popup);
205 edje_object_signal_emit(popup->theme, "notification,new", "notification");
209 _notification_theme_cb_close(Popup_Data *popup,
210 Evas_Object *obj __UNUSED__,
211 const char *emission __UNUSED__,
212 const char *source __UNUSED__)
214 _notification_popup_del(e_notification_id_get(popup->notif),
215 E_NOTIFICATION_CLOSED_DISMISSED);
219 _notification_theme_cb_find(Popup_Data *popup,
220 Evas_Object *obj __UNUSED__,
221 const char *emission __UNUSED__,
222 const char *source __UNUSED__)
227 if (!popup->app_name) return;
229 EINA_LIST_FOREACH(e_border_client_list(), l, bd)
233 len = strlen(popup->app_name);
234 test = eina_strlen_bounded(bd->client.icccm.name, len + 1);
236 /* We can't be sure that the app_name really match the application name.
237 * Some plugin put their name instead. But this search gives some good
240 if (strncasecmp(bd->client.icccm.name, popup->app_name, (test < len) ? test : len))
243 e_desk_show(bd->desk);
246 e_border_focus_set_with_pointer(bd);
252 _notification_popup_new(E_Notification *n)
257 const Eina_List *l, *screens;
261 if (popups_displayed > POPUP_LIMIT) return 0;
262 popup = E_NEW(Popup_Data, 1);
263 if (!popup) return NULL;
264 e_notification_ref(n);
267 con = e_container_current_get(e_manager_current_get());
268 screens = e_xinerama_screens_get();
269 if (notification_cfg->dual_screen &&
270 ((notification_cfg->corner == CORNER_BR) ||
271 (notification_cfg->corner == CORNER_TR)))
272 l = eina_list_last(screens);
277 scr = eina_list_data_get(l);
278 EINA_SAFETY_ON_NULL_GOTO(scr, error);
279 EINA_LIST_FOREACH(con->zones, l, zone)
280 if ((int)zone->num == scr->screen) break;
281 if ((int)zone->num != scr->screen) goto error;
284 zone = e_zone_current_get(con);
287 /* Create the popup window */
288 popup->win = e_popup_new(zone, 0, 0, 0, 0);
289 popup->e = popup->win->evas;
291 /* Setup the theme */
292 snprintf(buf, sizeof(buf), "%s/e-module-notification.edj",
293 notification_mod->dir);
294 popup->theme = edje_object_add(popup->e);
296 if (!e_theme_edje_object_set(popup->theme,
297 "base/theme/modules/notification",
298 "modules/notification/main"))
299 edje_object_file_set(popup->theme, buf, "modules/notification/main");
301 e_popup_edje_bg_object_set(popup->win, popup->theme);
303 evas_object_show(popup->theme);
304 edje_object_signal_callback_add
305 (popup->theme, "notification,deleted", "theme",
306 (Edje_Signal_Cb)_notification_theme_cb_deleted, popup);
307 edje_object_signal_callback_add
308 (popup->theme, "notification,close", "theme",
309 (Edje_Signal_Cb)_notification_theme_cb_close, popup);
310 edje_object_signal_callback_add
311 (popup->theme, "notification,find", "theme",
312 (Edje_Signal_Cb)_notification_theme_cb_find, popup);
314 _notification_popup_refresh(popup);
315 next_pos = _notification_popup_place(popup, next_pos);
316 e_popup_show(popup->win);
317 e_popup_layer_set(popup->win, 999);
323 e_notification_unref(n);
328 _notification_popup_place(Popup_Data *popup,
337 evas_object_geometry_get(popup->theme, NULL, NULL, &w, &h);
339 /* XXX for now ignore placement requests */
341 switch (notification_cfg->corner)
344 e_popup_move(popup->win,
345 to_edge, to_edge + pos);
348 e_popup_move(popup->win,
353 e_popup_move(popup->win,
355 (sh - h) - (to_edge + pos));
358 e_popup_move(popup->win,
360 (sh - h) - (to_edge + pos));
365 return pos + h + gap;
369 _notification_popups_place()
375 EINA_LIST_FOREACH(notification_cfg->popups, l, popup)
377 pos = _notification_popup_place(popup, pos);
384 _notification_popup_refresh(Popup_Data *popup)
386 const char *icon_path;
387 const char *app_icon_max;
389 int w, h, width = 80, height = 80;
393 popup->app_name = e_notification_app_name_get(popup->notif);
397 evas_object_del(popup->app_icon);
398 popup->app_icon = NULL;
401 app_icon_max = edje_object_data_get(popup->theme, "app_icon_max");
407 width = strtol(app_icon_max, &endptr, 10);
408 if (errno || (width < 1) || (endptr == app_icon_max))
418 height = strtol(endptr, NULL, 10);
419 if (errno || (height < 1)) height = 80;
425 /* Check if the app specify an icon either by a path or by a hint */
426 img = e_notification_hint_image_data_get(popup->notif);
429 icon_path = e_notification_hint_image_path_get(popup->notif);
430 if ((!icon_path) || (!icon_path[0]))
431 icon_path = e_notification_app_icon_get(popup->notif);
434 if (!strncmp(icon_path, "file://", 7)) icon_path += 7;
435 if (!ecore_file_exists(icon_path))
437 const char *new_path;
440 size = e_util_icon_size_normalize(width * e_scale);
441 new_path = efreet_icon_path_find(e_config->icon_theme,
444 icon_path = new_path;
447 Evas_Object *o = e_icon_add(popup->e);
448 if (!e_util_icon_theme_set(o, icon_path)) evas_object_del(o);
458 if (!popup->app_icon)
460 popup->app_icon = e_icon_add(popup->e);
461 if (!e_icon_file_set(popup->app_icon, icon_path))
463 evas_object_del(popup->app_icon);
464 popup->app_icon = NULL;
466 else e_icon_size_get(popup->app_icon, &w, &h);
470 if ((!img) && (!popup->app_icon))
471 img = e_notification_hint_icon_data_get(popup->notif);
474 popup->app_icon = e_notification_image_evas_object_add(popup->e, img);
475 evas_object_image_filled_set(popup->app_icon, EINA_TRUE);
476 evas_object_image_alpha_set(popup->app_icon, EINA_TRUE);
477 evas_object_image_size_get(popup->app_icon, &w, &h);
480 if (!popup->app_icon)
484 snprintf(buf, sizeof(buf), "%s/e-module-notification.edj",
485 notification_mod->dir);
486 popup->app_icon = edje_object_add(popup->e);
487 if (!e_theme_edje_object_set(popup->app_icon,
488 "base/theme/modules/notification",
489 "modules/notification/logo"))
490 edje_object_file_set(popup->app_icon, buf,
491 "modules/notification/logo");
496 if ((w > width) || (h > height))
503 edje_extern_object_min_size_set(popup->app_icon, w, h);
504 edje_extern_object_max_size_set(popup->app_icon, w, h);
506 edje_object_calc_force(popup->theme);
507 edje_object_part_swallow(popup->theme, "notification.swallow.app_icon",
509 edje_object_signal_emit(popup->theme, "notification,icon", "notification");
511 /* Fill up the event message */
512 _notification_format_message(popup);
514 /* Compute the new size of the popup */
515 edje_object_calc_force(popup->theme);
516 edje_object_size_min_calc(popup->theme, &w, &h);
517 e_popup_resize(popup->win, w, h);
518 evas_object_resize(popup->theme, w, h);
520 _notification_popups_place();
524 _notification_popup_find(unsigned int id)
529 if (!id) return NULL;
530 EINA_LIST_FOREACH(notification_cfg->popups, l, popup)
532 if (e_notification_id_get(popup->notif) == id) return popup;
538 _notification_popup_del(unsigned int id,
539 E_Notification_Closed_Reason reason)
545 EINA_LIST_FOREACH_SAFE(notification_cfg->popups, l, l2, popup)
547 if (e_notification_id_get(popup->notif) == id)
549 _notification_popdown(popup, reason);
550 notification_cfg->popups = eina_list_remove_list(notification_cfg->popups, l);
553 pos = _notification_popup_place(popup, pos);
560 _notification_popdown(Popup_Data *popup,
561 E_Notification_Closed_Reason reason)
563 if (popup->timer) ecore_timer_del(popup->timer);
564 e_popup_hide(popup->win);
566 evas_object_del(popup->app_icon);
567 evas_object_del(popup->theme);
568 e_object_del(E_OBJECT(popup->win));
569 e_notification_closed_set(popup->notif, 1);
570 e_notification_daemon_signal_notification_closed
571 (notification_cfg->daemon, e_notification_id_get(popup->notif), reason);
572 e_notification_unref(popup->notif);
577 _notification_format_message(Popup_Data *popup)
579 Evas_Object *o = popup->theme;
580 const char *title = e_notification_summary_get(popup->notif);
581 const char *b = e_notification_body_get(popup->notif);
582 edje_object_part_text_set(o, "notification.textblock.message", b);
583 edje_object_part_text_set(o, "notification.text.title", title);