2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <Elementary.h>
19 #include <appcore-common.h>
22 #include <app_service.h>
23 #include <notification.h>
27 #include "quickpanel-ui.h"
31 #define QP_TICKER_DURATION 5
32 #define QP_TICKER_DETAIL_DURATION 6
34 #define TICKER_MSG_LEN 1024
35 #define DEFAULT_ICON ICONDIR "/quickpanel_icon_default.png"
37 static Evas_Object *g_window;
38 static Evas_Object *g_ticker;
39 static Ecore_Timer *g_timer;
40 static int g_noti_height;
42 static int quickpanel_ticker_init(void *data);
43 static int quickpanel_ticker_fini(void *data);
44 static int quickpanel_ticker_enter_hib(void *data);
45 static int quickpanel_ticker_leave_hib(void *data);
46 static void quickpanel_ticker_reflesh(void *data);
50 .init = quickpanel_ticker_init,
51 .fini = quickpanel_ticker_fini,
52 .hib_enter = quickpanel_ticker_enter_hib,
53 .hib_leave = quickpanel_ticker_leave_hib,
55 .refresh = quickpanel_ticker_reflesh
58 static int latest_inserted_time;
60 /*****************************************************************************
62 * (Static) Util functions
64 *****************************************************************************/
66 static int _quickpanel_ticker_check_ticker_off(notification_h noti)
72 notification_get_application(noti, &pkgname);
75 notification_get_pkgname(noti, &pkgname);
78 return 1; /* Ticker is not displaying. */
80 if (!strcmp(pkgname, VENDOR".message")) {
82 VCONFKEY_SETAPPL_STATE_TICKER_NOTI_MESSAGES_BOOL,
84 if (ret == 0 && boolval == 0)
86 } else if (!strcmp(pkgname, VENDOR".email")) {
88 VCONFKEY_SETAPPL_STATE_TICKER_NOTI_EMAIL_BOOL,
90 if (ret == 0 && boolval == 0)
92 } else if (!strcmp(pkgname, VENDOR".ims-syspopup")) {
94 VCONFKEY_SETAPPL_STATE_TICKER_NOTI_IM_BOOL,
96 if (ret == 0 && boolval == 0)
100 /* Displaying ticker! */
104 static int _quickpanel_ticker_check_displaying_contents_off(notification_h noti)
106 char *pkgname = NULL;
110 notification_get_application(noti, &pkgname);
113 notification_get_pkgname(noti, &pkgname);
116 return 0; /* Ticker is not displaying. */
118 if (!strcmp(pkgname, VENDOR".message")) {
119 ret = vconf_get_bool(
120 VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_MESSASGES,
122 if (ret == 0 && boolval == 0)
124 } else if (!strcmp(pkgname, VENDOR".email")) {
125 ret = vconf_get_bool(
126 VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_EMAIL,
128 if (ret == 0 && boolval == 0)
130 } else if (!strcmp(pkgname, VENDOR".ims-syspopup")) {
131 ret = vconf_get_bool(
132 VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_IM,
134 if (ret == 0 && boolval == 0)
138 /* Displaying ticker! */
142 static inline void __ticker_only_noti_del(notification_h noti)
144 int applist = NOTIFICATION_DISPLAY_APP_ALL;
146 retif(noti == NULL, ,"noti is null");
148 notification_get_display_applist(noti, &applist);
149 if (applist & NOTIFICATION_DISPLAY_APP_TICKER) {
150 if (!(applist & NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY)) {
151 char *pkgname = NULL;
154 notification_get_pkgname(noti, &pkgname);
155 notification_get_id(noti, NULL, &priv_id);
156 notification_delete_by_priv_id(pkgname,
157 NOTIFICATION_TYPE_NONE,
163 static void _quickpanel_ticker_hide(void *data)
166 evas_object_hide(g_ticker);
167 evas_object_del(g_ticker);
172 static Eina_Bool _quickpanel_ticker_timeout_cb(void *data)
178 _quickpanel_ticker_hide(data);
180 return ECORE_CALLBACK_CANCEL;
183 static void _quickpanel_ticker_detail_hide_cb(void *data, Evas *e,
188 notification_h noti = (notification_h) data;
191 ecore_timer_del(g_timer);
195 retif(noti == NULL, , "Invalid parameter!");
197 __ticker_only_noti_del(noti);
198 notification_free(noti);
201 static void _quickpanel_ticker_detail_show_cb(void *data, Evas *e,
208 static void _quickpanel_ticker_clicked_cb(void *data, Evas_Object *obj,
211 notification_h noti = (notification_h) data;
212 char *caller_pkgname = NULL;
213 char *pkgname = NULL;
215 bundle *single_service_handle = NULL;
222 int type = NOTIFICATION_TYPE_NONE;
226 retif(noti == NULL, , "Invalid parameter!");
228 /* Check idle lock state */
229 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &val);
231 /* If Lock state, there is not any action when clicked. */
232 if (ret != 0 || val == VCONFKEY_IDLE_LOCK)
235 notification_get_pkgname(noti, &caller_pkgname);
236 notification_get_application(noti, &pkgname);
238 pkgname = caller_pkgname;
240 notification_get_id(noti, NULL, &priv_id);
241 notification_get_property(noti, &flags);
242 notification_get_type(noti, &type);
244 if (flags & NOTIFICATION_PROP_DISABLE_APP_LAUNCH)
249 if (flags & NOTIFICATION_PROP_DISABLE_AUTO_DELETE)
254 notification_get_execute_option(noti,
255 NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH,
256 NULL, &single_service_handle);
258 if (flag_launch == 1) {
259 if (single_service_handle != NULL)
260 appsvc_run_service(single_service_handle, 0, NULL,
263 notification_get_args(noti, &args, NULL);
264 quickpanel_launch_app(pkgname, args);
267 /* Hide quickpanel */
269 zone = ecore_x_e_illume_zone_get(elm_win_xwindow_get(g_window));
270 ecore_x_e_illume_quickpanel_state_send(zone,
271 ECORE_X_ILLUME_QUICKPANEL_STATE_OFF);
274 if (flag_delete == 1 && type == NOTIFICATION_TYPE_NOTI) {
275 notification_delete_by_priv_id(caller_pkgname,
276 NOTIFICATION_TYPE_NOTI,
281 static void _quickpanel_ticker_button_clicked_cb(void *data, Evas_Object *obj,
287 ecore_timer_del(g_timer);
291 _quickpanel_ticker_hide(data);
294 static Evas_Object *_quickpanel_ticker_create_button(Evas_Object *parent,
297 Evas_Object *button = NULL;
301 retif(noti == NULL || parent == NULL, NULL, "Invalid parameter!");
303 /* Check idle lock state */
304 ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &val);
305 /* If Lock state, button is diabled */
306 if (ret != 0 || val == VCONFKEY_IDLE_LOCK)
309 button = elm_button_add(parent);
310 elm_object_style_set(button, "tickernoti");
311 elm_object_text_set(button, _S("IDS_COM_BODY_CLOSE"));
312 evas_object_smart_callback_add(button, "clicked",
313 _quickpanel_ticker_button_clicked_cb, noti);
318 static Evas_Object *_quickpanel_ticker_create_icon(Evas_Object *parent,
321 char *icon_path = NULL;
322 Evas_Object *icon = NULL;
324 retif(noti == NULL || parent == NULL, NULL, "Invalid parameter!");
326 notification_get_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, &icon_path);
327 icon = elm_image_add(parent);
329 if (icon_path == NULL
330 || (elm_image_file_set(icon, icon_path, NULL) == EINA_FALSE)) {
331 elm_image_file_set(icon, DEFAULT_ICON, NULL);
332 elm_image_resizable_set(icon, EINA_TRUE, EINA_TRUE);
338 static char *_quickpanel_ticker_get_label(notification_h noti)
340 char buf[TICKER_MSG_LEN] = { 0, };
344 char *result_title = NULL;
345 char *result_content = NULL;
346 char *title_utf8 = NULL;
347 char *content_utf8 = NULL;
348 notification_error_e noti_err = NOTIFICATION_ERROR_NONE;
350 retif(noti == NULL, NULL, "Invalid parameter!");
352 notification_get_text_domain(noti, &domain, &dir);
353 if (domain != NULL && dir != NULL)
354 bindtextdomain(domain, dir);
356 noti_err = notification_get_text(noti, NOTIFICATION_TEXT_TYPE_TITLE,
358 if (noti_err == NOTIFICATION_ERROR_NONE && result_title)
359 title_utf8 = elm_entry_utf8_to_markup(result_title);
361 if (_quickpanel_ticker_check_displaying_contents_off(noti) == 1) {
362 noti_err = notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF,
366 noti_err = notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT,
370 if (noti_err == NOTIFICATION_ERROR_NONE && result_content)
371 content_utf8 = elm_entry_utf8_to_markup(result_content);
373 if (title_utf8 && content_utf8) {
374 len = snprintf(buf, sizeof(buf),
375 "<font_size=26><color=#BABABA>%s</color></font>"
376 "<br><font_size=29><color=#F4F4F4>%s</color></font>",
377 title_utf8, content_utf8);
378 } else if (title_utf8) {
379 len = snprintf(buf, sizeof(buf),
380 "<font_size=29><color=#BABABA>%s</color></font>",
396 static void _noti_hide_cb(void *data, Evas_Object *obj,
397 const char *emission, const char *source)
402 ecore_timer_del(g_timer);
406 _quickpanel_ticker_hide(data);
409 static Evas_Object *_quickpanel_ticker_create_tickernoti(void *data)
411 notification_h noti = (notification_h) data;
412 Evas_Object *tickernoti = NULL;
413 Evas_Object *icon = NULL;
414 Evas_Object *detail = NULL;
415 Evas_Object *button = NULL;
417 const char *data_win_height = NULL;
420 retif(noti == NULL, NULL, "Invalid parameter!");
422 tickernoti = noti_win_add(NULL);
423 retif(tickernoti == NULL, NULL, "Failed to add elm tickernoti.");
425 detail = elm_layout_add(tickernoti);
427 ERR("Failed to get detailview.");
428 evas_object_del(tickernoti);
431 elm_layout_theme_set(detail, "tickernoti", "base", "default");
432 elm_object_signal_callback_add(detail, "request,hide", "",
433 _noti_hide_cb, noti);
435 data_win_height = (char *)elm_layout_data_get(detail, "height");
436 if (data_win_height != NULL && elm_config_scale_get() > 0.0)
437 noti_height = (int)(elm_config_scale_get()
438 * atoi(data_win_height));
439 evas_object_size_hint_min_set(detail, 1, noti_height);
440 g_noti_height = noti_height;
442 noti_win_content_set(tickernoti, detail);
444 icon = _quickpanel_ticker_create_icon(detail, noti);
446 elm_object_part_content_set(detail, "icon", icon);
448 button = _quickpanel_ticker_create_button(detail, noti);
450 elm_object_part_content_set(detail, "button", button);
452 buf = _quickpanel_ticker_get_label(noti);
454 elm_object_part_text_set(detail, "elm.text", buf);
458 /* Use style "default" for detailview mode and
459 * "info" for text only mode
461 elm_object_style_set(tickernoti, "default");
466 static int _quickpanel_ticker_get_angle(void *data)
468 struct appdata *ad = (struct appdata *)data;
469 Ecore_X_Window xwin, root;
470 int ret = 0, angle = 0, count = 0;
471 unsigned char *prop_data = NULL;
473 xwin = elm_win_xwindow_get(ad->win);
474 root = ecore_x_window_root_get(xwin);
476 ret = ecore_x_window_prop_property_get(root,
477 ECORE_X_ATOM_E_ILLUME_ROTATE_ROOT_ANGLE,
478 ECORE_X_ATOM_CARDINAL, 32,
481 if (ret && prop_data) {
482 memcpy(&angle, prop_data, sizeof(int));
489 ERR("Fail to get angle");
497 static void _quickpanel_ticker_update_geometry_on_rotation(void *data, int *x, int *y, int *w, int *h) {
502 angle = _quickpanel_ticker_get_angle(data);
503 Evas_Coord root_w, root_h;
506 * manually calculate win_tickernoti_indi window position & size
507 * - win_indi is not full size window
509 ecore_x_window_size_get(ecore_x_window_root_first_get(), &root_w, &root_h);
521 *x = root_w - g_noti_height;
526 *y = root_h - g_noti_height;
534 elm_win_rotation_set(g_ticker, angle);
537 static void _quickpanel_ticker_win_rotated(void *data) {
538 retif(data == NULL, ,"data is NULL");
539 struct appdata *ad = data;
540 int x = 0, y = 0, w = 0, h = 0;
542 _quickpanel_ticker_update_geometry_on_rotation(ad, &x, &y, &w, &h);
544 if (g_ticker != NULL) {
545 evas_object_move(g_ticker, x, y);
546 evas_object_resize(g_ticker, w, h);
550 static void _quickpanel_ticker_noti_detailed_changed_cb(void *data, notification_type_e type, notification_op *op_list, int num_op)
552 notification_h noti = NULL;
554 int applist = NOTIFICATION_DISPLAY_APP_ALL;
559 INFO("_quickpanel_ticker_noti_changed_cb");
561 retif(op_list == NULL, ,"op_list is NULL");
564 notification_op_get_data(op_list, NOTIFICATION_OP_DATA_TYPE, &op_type);
565 notification_op_get_data(op_list, NOTIFICATION_OP_DATA_PRIV_ID, &priv_id);
566 DBG("op_type:%d", op_type);
567 DBG("op_priv_id:%d", priv_id);
569 if (op_type == NOTIFICATION_OP_INSERT) {
570 noti = notification_load(NULL, priv_id);
571 } else if (op_type == NOTIFICATION_OP_UPDATE) {
572 noti = notification_load(NULL, priv_id);
580 retif(noti == NULL, ,"noti is NULL");
582 notification_get_display_applist(noti, &applist);
583 if (!(applist & NOTIFICATION_DISPLAY_APP_TICKER)) {
584 DBG("No Ticker Msg");
585 notification_free(noti);
589 /* Check setting's event notification */
590 ret = _quickpanel_ticker_check_ticker_off(noti);
592 INFO("Disable tickernoti ret : %d", ret);
593 /* delete temporary here only ticker noti display item */
594 __ticker_only_noti_del(noti);
595 notification_free(noti);
601 notification_sound_type_e nsound_type = NOTIFICATION_SOUND_TYPE_NONE;
602 const char *nsound_path = NULL;
604 notification_get_sound(noti, &nsound_type, &nsound_path);
605 DBG("Sound : %d, %s", nsound_type, nsound_path);
606 if (nsound_type > NOTIFICATION_SOUND_TYPE_NONE
607 || nsound_type < NOTIFICATION_SOUND_TYPE_MAX) {
609 switch (nsound_type) {
610 case NOTIFICATION_SOUND_TYPE_DEFAULT:
611 feedback_play_type(FEEDBACK_TYPE_SOUND, FEEDBACK_PATTERN_UNLOCK);
613 case NOTIFICATION_SOUND_TYPE_USER_DATA:
614 quickpanel_player_play(SOUND_TYPE_NOTIFICATION, nsound_path);
621 notification_vibration_type_e nvibration_type =
622 NOTIFICATION_VIBRATION_TYPE_NONE;
623 const char *nvibration_path = NULL;
625 notification_get_vibration(noti, &nvibration_type, &nvibration_path);
626 DBG("Vibration : %d, %s", nvibration_type, nvibration_path);
627 if (nvibration_type > NOTIFICATION_VIBRATION_TYPE_NONE
628 || nvibration_type < NOTIFICATION_VIBRATION_TYPE_MAX) {
630 switch (nvibration_type) {
631 case NOTIFICATION_SOUND_TYPE_DEFAULT:
632 feedback_play_type(FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_GENERAL);
634 case NOTIFICATION_SOUND_TYPE_USER_DATA:
641 /* Skip if previous ticker is still shown */
642 if (g_ticker != NULL) {
643 _quickpanel_ticker_hide(NULL);
646 /* Check tickernoti flag */
647 notification_get_property(noti, &flags);
649 if (flags & NOTIFICATION_PROP_DISABLE_TICKERNOTI) {
650 INFO("NOTIFICATION_PROP_DISABLE_TICKERNOTI");
651 __ticker_only_noti_del(noti);
652 notification_free(noti);
653 } else if (applist & NOTIFICATION_DISPLAY_APP_TICKER) {
656 ecore_timer_del(g_timer);
658 g_ticker = _quickpanel_ticker_create_tickernoti(noti);
659 if (g_ticker == NULL) {
660 ERR("Fail to create tickernoti");
661 __ticker_only_noti_del(noti);
662 notification_free(noti);
666 g_timer = ecore_timer_add(QP_TICKER_DURATION,
667 _quickpanel_ticker_timeout_cb, noti);
669 _quickpanel_ticker_win_rotated(data);
670 evas_object_show(g_ticker);
672 evas_object_event_callback_add(g_ticker, EVAS_CALLBACK_SHOW,
673 _quickpanel_ticker_detail_show_cb,
675 evas_object_event_callback_add(g_ticker, EVAS_CALLBACK_HIDE,
676 _quickpanel_ticker_detail_hide_cb,
678 evas_object_smart_callback_add(g_ticker, "clicked",
679 _quickpanel_ticker_clicked_cb,
684 /*****************************************************************************
688 *****************************************************************************/
689 static int quickpanel_ticker_init(void *data)
691 struct appdata *ad = (struct appdata *)data;
693 latest_inserted_time = time(NULL);
696 notification_register_detailed_changed_cb(_quickpanel_ticker_noti_detailed_changed_cb,
702 static int quickpanel_ticker_fini(void *data)
704 _quickpanel_ticker_hide(NULL);
709 static int quickpanel_ticker_enter_hib(void *data)
714 static int quickpanel_ticker_leave_hib(void *data)
719 static void quickpanel_ticker_reflesh(void *data)
721 retif(data == NULL, , "Invalid parameter!");
723 if (g_ticker != NULL) {
724 _quickpanel_ticker_win_rotated(data);