aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/elementary/src/lib/elm_notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/elementary/src/lib/elm_notify.c')
-rw-r--r--libraries/elementary/src/lib/elm_notify.c626
1 files changed, 626 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/elm_notify.c b/libraries/elementary/src/lib/elm_notify.c
new file mode 100644
index 0000000..1b68390
--- /dev/null
+++ b/libraries/elementary/src/lib/elm_notify.c
@@ -0,0 +1,626 @@
1#include <Elementary.h>
2#include "elm_priv.h"
3
4typedef struct _Widget_Data Widget_Data;
5
6struct _Widget_Data
7{
8 Evas_Object *notify, *content, *parent;
9
10 Elm_Notify_Orient orient;
11 Eina_Bool allow_events;
12 Evas_Object *block_events;
13
14 double timeout;
15 Ecore_Timer *timer;
16};
17
18static const char *widtype = NULL;
19static void _del_hook(Evas_Object *obj);
20static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
21static void _theme_hook(Evas_Object *obj);
22static void _sizing_eval(Evas_Object *obj);
23static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
24static void _sub_del(void *data, Evas_Object *obj, void *event_info);
25static void _signal_block_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
26static void _calc(Evas_Object *obj);
27static void _content_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
28static void _show(void *data, Evas *e, Evas_Object *obj, void *event_info);
29static void _hide(void *data, Evas *e, Evas_Object *obj, void *event_info);
30static void _parent_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
31static void _parent_hide(void *data, Evas *e, Evas_Object *obj, void *event_info);
32
33static void _resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
34static void _restack(void *data, Evas *e, Evas_Object *obj, void *event_info);
35
36static const char SIG_BLOCK_CLICKED[] = "block,clicked";
37static const char SIG_TIMEOUT[] = "timeout";
38static const Evas_Smart_Cb_Description _signals[] = {
39 {SIG_BLOCK_CLICKED, ""},
40 {SIG_TIMEOUT, ""},
41 {NULL, NULL}
42};
43
44static void
45_del_pre_hook(Evas_Object *obj)
46{
47 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
48 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_MOVE, _resize, obj);
49 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_SHOW, _show, obj);
50 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_HIDE, _hide, obj);
51 evas_object_event_callback_del_full(obj, EVAS_CALLBACK_RESTACK, _restack, obj);
52}
53
54static void
55_del_hook(Evas_Object *obj)
56{
57 Widget_Data *wd = elm_widget_data_get(obj);
58 if (!wd) return;
59 elm_notify_parent_set(obj, NULL);
60 elm_notify_allow_events_set(obj, EINA_TRUE);
61 if (wd->timer)
62 {
63 ecore_timer_del(wd->timer);
64 wd->timer = NULL;
65 }
66 free(wd);
67}
68
69/**
70 * Return Notification orientation with RTL
71 *
72 * This function switches-sides of notification area when in RTL mode.
73 *
74 * @param obj notification object.
75 *
76 * @param orient Original notification orientation.
77 *
78 * @return notification orientation with respect to the object RTL mode.
79 *
80 * @internal
81 **/
82static Elm_Notify_Orient
83_notify_orientation_with_rtl(Evas_Object *obj, Elm_Notify_Orient orient)
84{
85 if (elm_widget_mirrored_get(obj))
86 {
87 switch (orient)
88 {
89 case ELM_NOTIFY_ORIENT_LEFT:
90 orient = ELM_NOTIFY_ORIENT_RIGHT;
91 break;
92 case ELM_NOTIFY_ORIENT_RIGHT:
93 orient = ELM_NOTIFY_ORIENT_LEFT;
94 break;
95 case ELM_NOTIFY_ORIENT_TOP_LEFT:
96 orient = ELM_NOTIFY_ORIENT_TOP_RIGHT;
97 break;
98 case ELM_NOTIFY_ORIENT_TOP_RIGHT:
99 orient = ELM_NOTIFY_ORIENT_TOP_LEFT;
100 break;
101 case ELM_NOTIFY_ORIENT_BOTTOM_LEFT:
102 orient = ELM_NOTIFY_ORIENT_BOTTOM_RIGHT;
103 break;
104 case ELM_NOTIFY_ORIENT_BOTTOM_RIGHT:
105 orient = ELM_NOTIFY_ORIENT_BOTTOM_LEFT;
106 break;
107 default:
108 break;
109 }
110 }
111
112 return orient;
113}
114
115static void
116_notify_theme_apply(Evas_Object *obj)
117{
118 Widget_Data *wd = elm_widget_data_get(obj);
119 const char *style = elm_widget_style_get(obj);
120
121 switch (wd->orient)
122 {
123 case ELM_NOTIFY_ORIENT_TOP:
124 _elm_theme_object_set(obj, wd->notify, "notify", "top", style);
125 break;
126 case ELM_NOTIFY_ORIENT_CENTER:
127 _elm_theme_object_set(obj, wd->notify, "notify", "center", style);
128 break;
129 case ELM_NOTIFY_ORIENT_BOTTOM:
130 _elm_theme_object_set(obj, wd->notify, "notify", "bottom", style);
131 break;
132 case ELM_NOTIFY_ORIENT_LEFT:
133 _elm_theme_object_set(obj, wd->notify, "notify", "left", style);
134 break;
135 case ELM_NOTIFY_ORIENT_RIGHT:
136 _elm_theme_object_set(obj, wd->notify, "notify", "right", style);
137 break;
138 case ELM_NOTIFY_ORIENT_TOP_LEFT:
139 _elm_theme_object_set(obj, wd->notify, "notify", "top_left", style);
140 break;
141 case ELM_NOTIFY_ORIENT_TOP_RIGHT:
142 _elm_theme_object_set(obj, wd->notify, "notify", "top_right", style);
143 break;
144 case ELM_NOTIFY_ORIENT_BOTTOM_LEFT:
145 _elm_theme_object_set(obj, wd->notify, "notify", "bottom_left", style);
146 break;
147 case ELM_NOTIFY_ORIENT_BOTTOM_RIGHT:
148 _elm_theme_object_set(obj, wd->notify, "notify", "bottom_right", style);
149 break;
150 case ELM_NOTIFY_ORIENT_LAST:
151 break;
152 }
153}
154
155/**
156 * Moves notification to orientation.
157 *
158 * This fucntion moves notification to orientation
159 * according to object RTL orientation.
160 *
161 * @param obj notification object.
162 *
163 * @param orient notification orientation.
164 *
165 * @internal
166 **/
167static void
168_notify_move_to_orientation(Evas_Object *obj)
169{
170 Widget_Data *wd = elm_widget_data_get(obj);
171 int offx;
172 int offy;
173 Evas_Coord minw = -1, minh = -1;
174 Evas_Coord x, y, w, h;
175
176 if (!wd) return;
177 evas_object_geometry_get(obj, &x, &y, &w, &h);
178 edje_object_size_min_get(wd->notify, &minw, &minh);
179 edje_object_size_min_restricted_calc(wd->notify, &minw, &minh, minw, minh);
180 offx = (w - minw) / 2;
181 offy = (h - minh) / 2;
182
183 switch (_notify_orientation_with_rtl(obj, wd->orient))
184 {
185 case ELM_NOTIFY_ORIENT_TOP:
186 evas_object_move(wd->notify, x + offx, y);
187 break;
188 case ELM_NOTIFY_ORIENT_CENTER:
189 evas_object_move(wd->notify, x + offx, y + offy);
190 break;
191 case ELM_NOTIFY_ORIENT_BOTTOM:
192 evas_object_move(wd->notify, x + offx, y + h - minh);
193 break;
194 case ELM_NOTIFY_ORIENT_LEFT:
195 evas_object_move(wd->notify, x, y + offy);
196 break;
197 case ELM_NOTIFY_ORIENT_RIGHT:
198 evas_object_move(wd->notify, x + w - minw, y + offy);
199 break;
200 case ELM_NOTIFY_ORIENT_TOP_LEFT:
201 evas_object_move(wd->notify, x, y);
202 break;
203 case ELM_NOTIFY_ORIENT_TOP_RIGHT:
204 evas_object_move(wd->notify, x + w - minw, y);
205 break;
206 case ELM_NOTIFY_ORIENT_BOTTOM_LEFT:
207 evas_object_move(wd->notify, x, y + h - minh);
208 break;
209 case ELM_NOTIFY_ORIENT_BOTTOM_RIGHT:
210 evas_object_move(wd->notify, x + w - minw, y + h - minh);
211 break;
212 case ELM_NOTIFY_ORIENT_LAST:
213 break;
214 }
215}
216
217static void
218_block_events_theme_apply(Evas_Object *obj)
219{
220 Widget_Data *wd = elm_widget_data_get(obj);
221 const char *style = elm_widget_style_get(obj);
222 _elm_theme_object_set(obj, wd->block_events, "notify", "block_events", style);
223}
224
225static void
226_mirrored_set(Evas_Object *obj, Eina_Bool rtl)
227{
228 Widget_Data *wd = elm_widget_data_get(obj);
229 if (!wd) return;
230 edje_object_mirrored_set(wd->notify, rtl);
231 _notify_move_to_orientation(obj);
232}
233
234static void
235_theme_hook(Evas_Object *obj)
236{
237 Widget_Data *wd = elm_widget_data_get(obj);
238 if (!wd) return;
239 _elm_widget_mirrored_reload(obj);
240 _mirrored_set(obj, elm_widget_mirrored_get(obj));
241 _notify_theme_apply(obj);
242 if (wd->block_events) _block_events_theme_apply(obj);
243 edje_object_scale_set(wd->notify, elm_widget_scale_get(obj) *
244 _elm_config->scale);
245 _sizing_eval(obj);
246}
247
248static void
249_sizing_eval(Evas_Object *obj)
250{
251 Widget_Data *wd = elm_widget_data_get(obj);
252 Evas_Coord x,y,w,h;
253 if (!wd) return;
254 if (!wd->parent) return;
255 evas_object_geometry_get(wd->parent, &x, &y, &w, &h);
256 evas_object_move(obj, x, y);
257 evas_object_resize(obj, w, h);
258}
259
260static void
261_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
262{
263 _calc(data);
264}
265
266static void
267_sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
268{
269 Widget_Data *wd = elm_widget_data_get(obj);
270 Evas_Object *sub = event_info;
271 if (!wd) return;
272
273 if (sub == wd->content)
274 {
275 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
276 _changed_size_hints, obj);
277 evas_object_event_callback_del_full(sub, EVAS_CALLBACK_RESIZE,
278 _content_resize, obj);
279 wd->content = NULL;
280 }
281}
282
283static void
284_signal_block_clicked(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
285{
286 Widget_Data *wd = elm_widget_data_get(data);
287 if (!wd) return;
288 evas_object_smart_callback_call(data, SIG_BLOCK_CLICKED, NULL);
289}
290
291static void
292_restack(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
293{
294 Widget_Data *wd = elm_widget_data_get(obj);
295 if (!wd) return;
296 evas_object_layer_set(wd->notify,
297 evas_object_layer_get(obj));
298}
299
300static void
301_resize(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
302{
303 _calc(obj);
304}
305
306static void
307_content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
308{
309 _calc(data);
310}
311
312static void
313_calc(Evas_Object *obj)
314{
315 Widget_Data *wd = elm_widget_data_get(obj);
316 Evas_Coord minw = -1, minh = -1;
317 Evas_Coord x, y, w, h;
318
319 if (!wd) return;
320 _sizing_eval(obj);
321
322 evas_object_geometry_get(obj, &x, &y, &w, &h);
323 edje_object_size_min_get(wd->notify, &minw, &minh);
324 edje_object_size_min_restricted_calc(wd->notify, &minw, &minh, minw, minh);
325
326 if (wd->content)
327 {
328 _notify_move_to_orientation(obj);
329 evas_object_resize(wd->notify, minw, minh);
330 }
331}
332
333static Eina_Bool
334_timer_cb(void *data)
335{
336 Evas_Object *obj = data;
337 Widget_Data *wd = elm_widget_data_get(obj);
338 if (!wd) return ECORE_CALLBACK_CANCEL;
339 wd->timer = NULL;
340 evas_object_hide(obj);
341 evas_object_smart_callback_call(obj, SIG_TIMEOUT, NULL);
342 return ECORE_CALLBACK_CANCEL;
343}
344
345static void
346_timer_init(Evas_Object *obj, Widget_Data *wd)
347{
348 if (wd->timer)
349 {
350 ecore_timer_del(wd->timer);
351 wd->timer = NULL;
352 }
353 if ((evas_object_visible_get(obj)) && (wd->timeout > 0.0))
354 wd->timer = ecore_timer_add(wd->timeout, _timer_cb, obj);
355}
356
357static void
358_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
359{
360 Widget_Data *wd = elm_widget_data_get(obj);
361 if (!wd) return;
362 evas_object_show(wd->notify);
363 if (!wd->allow_events) evas_object_show(wd->block_events);
364 _timer_init(obj, wd);
365 elm_object_focus_set(obj, EINA_TRUE);
366}
367
368static void
369_hide(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
370{
371 Widget_Data *wd = elm_widget_data_get(obj);
372 if (!wd) return;
373 evas_object_hide(wd->notify);
374 if (!wd->allow_events) evas_object_hide(wd->block_events);
375 if (wd->timer)
376 {
377 ecore_timer_del(wd->timer);
378 wd->timer = NULL;
379 }
380}
381
382static void
383_parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
384{
385 Widget_Data *wd = elm_widget_data_get(data);
386 if (!wd) return;
387 wd->parent = NULL;
388 evas_object_hide(data);
389}
390
391static void
392_parent_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
393{
394 Widget_Data *wd = elm_widget_data_get(data);
395 if (!wd) return;
396 evas_object_hide(data);
397}
398
399static Eina_Bool
400_elm_notify_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
401{
402 Widget_Data *wd = elm_widget_data_get(obj);
403 Evas_Object *cur;
404
405 if ((!wd) || (!wd->content))
406 return EINA_FALSE;
407
408 cur = wd->content;
409
410 /* Try Focus cycle in subitem */
411 return elm_widget_focus_next_get(cur, dir, next);
412}
413
414static void
415_content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
416{
417 ELM_CHECK_WIDTYPE(obj, widtype);
418 Widget_Data *wd;
419 if (part && strcmp(part ,"default")) return;
420 wd = elm_widget_data_get(obj);
421 if (!wd) return;
422 if (wd->content == content) return;
423 if (wd->content) evas_object_del(wd->content);
424 wd->content = content;
425
426 if (content)
427 {
428 elm_widget_sub_object_add(obj, content);
429 evas_object_event_callback_add(content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
430 _changed_size_hints, obj);
431 evas_object_event_callback_add(content, EVAS_CALLBACK_RESIZE,
432 _content_resize, obj);
433 edje_object_part_swallow(wd->notify, "elm.swallow.content", content);
434 }
435 _sizing_eval(obj);
436 _calc(obj);
437}
438
439static Evas_Object *
440_content_get_hook(const Evas_Object *obj, const char *part)
441{
442 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
443 Widget_Data *wd;
444 if (part && strcmp(part ,"default")) return NULL;
445 wd = elm_widget_data_get(obj);
446 if (!wd) return NULL;
447 return wd->content;
448}
449
450static Evas_Object *
451_content_unset_hook(Evas_Object *obj, const char *part)
452{
453 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
454 Widget_Data *wd;
455 Evas_Object *content;
456 if (part && strcmp(part ,"default")) return NULL;
457 wd = elm_widget_data_get(obj);
458 if (!wd) return NULL;
459 if (!wd->content) return NULL;
460 content = wd->content;
461 elm_widget_sub_object_del(obj, wd->content);
462 edje_object_part_unswallow(wd->notify, content);
463 return content;
464}
465
466EAPI Evas_Object *
467elm_notify_add(Evas_Object *parent)
468{
469 Evas_Object *obj;
470 Evas *e;
471 Widget_Data *wd;
472
473 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
474
475 ELM_SET_WIDTYPE(widtype, "notify");
476 elm_widget_type_set(obj, "notify");
477 elm_widget_sub_object_add(parent, obj);
478 elm_widget_data_set(obj, wd);
479 elm_widget_del_pre_hook_set(obj, _del_pre_hook);
480 elm_widget_del_hook_set(obj, _del_hook);
481 elm_widget_theme_hook_set(obj, _theme_hook);
482 elm_widget_can_focus_set(obj, EINA_FALSE);
483 elm_widget_focus_next_hook_set(obj, _elm_notify_focus_next_hook);
484 elm_widget_content_set_hook_set(obj, _content_set_hook);
485 elm_widget_content_get_hook_set(obj, _content_get_hook);
486 elm_widget_content_unset_hook_set(obj, _content_unset_hook);
487
488 wd->allow_events = EINA_TRUE;
489
490 wd->notify = edje_object_add(e);
491 wd->orient = -1;
492 elm_notify_orient_set(obj, ELM_NOTIFY_ORIENT_TOP);
493
494 elm_notify_parent_set(obj, parent);
495
496 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
497 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
498 evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _resize, obj);
499 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _show, obj);
500 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _hide, obj);
501 evas_object_event_callback_add(obj, EVAS_CALLBACK_RESTACK, _restack, obj);
502 _mirrored_set(obj, elm_widget_mirrored_get(obj));
503 _sizing_eval(obj);
504
505 evas_object_smart_callbacks_descriptions_set(obj, _signals);
506 return obj;
507}
508
509EAPI void
510elm_notify_parent_set(Evas_Object *obj, Evas_Object *parent)
511{
512 ELM_CHECK_WIDTYPE(obj, widtype);
513 Widget_Data *wd = elm_widget_data_get(obj);
514 if (!wd) return;
515 if (wd->parent)
516 {
517 evas_object_event_callback_del_full(wd->parent,
518 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
519 _changed_size_hints, obj);
520 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE,
521 _changed_size_hints, obj);
522 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_MOVE,
523 _changed_size_hints, obj);
524 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_DEL,
525 _parent_del, obj);
526 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_HIDE,
527 _parent_hide, obj);
528 wd->parent = NULL;
529 }
530
531 if (parent)
532 {
533 wd->parent = parent;
534 evas_object_event_callback_add(parent,
535 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
536 _changed_size_hints, obj);
537 evas_object_event_callback_add(parent, EVAS_CALLBACK_RESIZE,
538 _changed_size_hints, obj);
539 evas_object_event_callback_add(parent, EVAS_CALLBACK_MOVE,
540 _changed_size_hints, obj);
541 evas_object_event_callback_add(parent, EVAS_CALLBACK_DEL,
542 _parent_del, obj);
543 evas_object_event_callback_add(parent, EVAS_CALLBACK_HIDE,
544 _parent_hide, obj);
545 _sizing_eval(obj);
546 }
547 _calc(obj);
548}
549
550EAPI Evas_Object *
551elm_notify_parent_get(const Evas_Object *obj)
552{
553 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
554 Widget_Data *wd = elm_widget_data_get(obj);
555 if (!wd) return NULL;
556 return wd->parent;
557}
558
559EAPI void
560elm_notify_orient_set(Evas_Object *obj, Elm_Notify_Orient orient)
561{
562 ELM_CHECK_WIDTYPE(obj, widtype);
563 Widget_Data *wd = elm_widget_data_get(obj);
564 if (!wd) return;
565 if (wd->orient == orient) return;
566 wd->orient = orient;
567 _notify_theme_apply(obj);
568 _resize(obj, NULL, obj, NULL);
569}
570
571EAPI Elm_Notify_Orient
572elm_notify_orient_get(const Evas_Object *obj)
573{
574 ELM_CHECK_WIDTYPE(obj, widtype) -1;
575 Widget_Data *wd = elm_widget_data_get(obj);
576 if (!wd) return -1;
577 return wd->orient;
578}
579
580EAPI void
581elm_notify_timeout_set(Evas_Object *obj, double timeout)
582{
583 ELM_CHECK_WIDTYPE(obj, widtype);
584 Widget_Data *wd = elm_widget_data_get(obj);
585 if (!wd) return;
586 wd->timeout = timeout;
587 _timer_init(obj, wd);
588}
589
590EAPI double
591elm_notify_timeout_get(const Evas_Object *obj)
592{
593 ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
594 Widget_Data *wd = elm_widget_data_get(obj);
595 if (!wd) return 0.0;
596 return wd->timeout;
597}
598
599EAPI void
600elm_notify_allow_events_set(Evas_Object *obj, Eina_Bool allow)
601{
602 ELM_CHECK_WIDTYPE(obj, widtype);
603 Widget_Data *wd = elm_widget_data_get(obj);
604 if (!wd) return;
605 if (allow == wd->allow_events) return;
606 wd->allow_events = allow;
607 if (!allow)
608 {
609 wd->block_events = edje_object_add(evas_object_evas_get(obj));
610 _block_events_theme_apply(obj);
611 elm_widget_resize_object_set(obj, wd->block_events);
612 edje_object_signal_callback_add(wd->block_events, "elm,action,click",
613 "elm", _signal_block_clicked, obj);
614 }
615 else
616 evas_object_del(wd->block_events);
617}
618
619EAPI Eina_Bool
620elm_notify_allow_events_get(const Evas_Object *obj)
621{
622 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
623 Widget_Data *wd = elm_widget_data_get(obj);
624 if (!wd) return EINA_FALSE;
625 return wd->allow_events;
626}