3 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an AS IS BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include "clipdrawer.h"
20 #include "item_manager.h"
21 #include "xconverter.h"
23 #define EDJ_PATH "/usr/share/edje"
24 #define APP_EDJ_FILE EDJ_PATH"/cbhmdrawer.edj"
25 #define GRP_MAIN "cbhmdrawer"
27 #define ANIM_DURATION 30 // 1 seconds
28 #define ANIM_FLOPS (0.5/30)
29 #define DEFAULT_WIDTH 720
31 #define MULTI_(id) dgettext("sys_string", #id)
32 #define S_CLIPBOARD MULTI_(IDS_COM_BODY_CLIPBOARD)
33 #define S_DELETE MULTI_(IDS_COM_BODY_DELETE)
34 #define S_DONE MULTI_(IDS_COM_BODY_DONE)
36 static Evas_Object *create_win(ClipdrawerData *cd, const char *name);
37 static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part);
38 static Eina_Bool clipdrawer_add_item(AppData *ad, CNP_ITEM *item);
39 static Eina_Bool clipdrawer_del_item(AppData *ad, CNP_ITEM *item);
40 static void clipdrawer_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
41 static void _grid_item_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source);
42 static void setting_win(Ecore_X_Display *x_disp, Ecore_X_Window x_main_win);
43 static void set_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win);
44 static void unset_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win);
46 static void _change_gengrid_paste_textonly_mode(ClipdrawerData *cd)
48 CNP_ITEM *item = NULL;
50 Elm_Object_Item *gitem = elm_gengrid_first_item_get(cd->gengrid);
54 item = elm_object_item_data_get(gitem);
57 if ((item->type_index == ATOM_INDEX_IMAGE))
59 if (cd->paste_text_only)
60 elm_object_signal_emit(item->layout, "elm,state,show,dim", "elm");
62 elm_object_signal_emit(item->layout, "elm,state,hide,dim", "elm");
64 gitem = elm_gengrid_item_next_get(gitem);
68 void clipdrawer_paste_textonly_set(AppData *ad, Eina_Bool textonly)
70 ClipdrawerData *cd = ad->clipdrawer;
71 if (cd->paste_text_only != textonly)
72 cd->paste_text_only = textonly;
73 DTRACE("paste textonly mode = %d\n", textonly);
75 _change_gengrid_paste_textonly_mode(cd);
78 Eina_Bool clipdrawer_paste_textonly_get(AppData *ad)
80 ClipdrawerData *cd = ad->clipdrawer;
81 return cd->paste_text_only;
84 static Evas_Object *_load_edj(Evas_Object* win, const char *file, const char *group)
86 Evas_Object *layout = elm_layout_add(win);
89 DMSG("ERROR: elm_layout_add return NULL\n");
93 if (!elm_layout_file_set(layout, file, group))
95 DMSG("ERROR: elm_layout_file_set return FALSE\n");
96 evas_object_del(layout);
100 evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
101 elm_win_resize_object_add(win, layout);
103 evas_object_show(layout);
107 static Eina_Bool keydown_cb(void *data, int type, void *event)
110 Ecore_Event_Key *ev = event;
111 if (!strcmp(ev->keyname, KEY_END))
112 clipdrawer_lower_view(ad);
114 return ECORE_CALLBACK_DONE;
117 ClipdrawerData* init_clipdrawer(AppData *ad)
119 ClipdrawerData *cd = calloc(1, sizeof(ClipdrawerData));
122 /* create and setting window */
125 if (!(cd->main_win = create_win(cd, APPNAME)))
130 cd->x_main_win = elm_win_xwindow_get(cd->main_win);
131 setting_win(ad->x_disp, cd->x_main_win);
134 if (!(cd->main_layout = _load_edj(cd->main_win, APP_EDJ_FILE, GRP_MAIN)))
136 evas_object_del(cd->main_win);
141 double scale = elm_config_scale_get();
142 Evas_Object* ly = elm_layout_edje_get(cd->main_layout);
144 data = edje_object_data_get(ly, "clipboard_height");
145 cd->height = data ? atoi(data) : 0;
148 data = edje_object_data_get(ly, "clipboard_landscape_height");
149 cd->landscape_height = data ? atoi(data) : 0;
150 cd->landscape_height *= scale;
152 data = edje_object_data_get(ly, "grid_item_bg_w");
153 cd->grid_item_bg_w = data ? atoi(data) : 0;
154 cd->grid_item_bg_w *= scale;
156 data = edje_object_data_get(ly, "grid_item_bg_h");
157 cd->grid_item_bg_h = data ? atoi(data) : 0;
158 cd->grid_item_bg_h *= scale;
160 data = edje_object_data_get(ly, "grid_image_item_w");
161 cd->grid_image_item_w = data ? atoi(data) : 0;
162 cd->grid_image_item_w *= scale;
164 data = edje_object_data_get(ly, "grid_image_item_h");
165 cd->grid_image_item_h = data ? atoi(data) : 0;
166 cd->grid_image_item_h *= scale;
168 /* create and setting gengrid */
169 elm_theme_extension_add(NULL, APP_EDJ_FILE);
170 elm_object_signal_callback_add(cd->main_layout,
171 "mouse,clicked,1", "*", clipdrawer_ly_clicked, ad);
173 cd->gengrid = elm_gengrid_add(cd->main_win);
174 elm_object_part_content_set(cd->main_layout, "historyitems", cd->gengrid);
175 elm_gengrid_item_size_set(cd->gengrid, cd->grid_item_bg_w, cd->grid_item_bg_h);
176 elm_gengrid_align_set(cd->gengrid, 0.0, 0.0);
177 elm_gengrid_horizontal_set(cd->gengrid, EINA_TRUE);
178 elm_gengrid_bounce_set(cd->gengrid, EINA_TRUE, EINA_FALSE);
179 elm_gengrid_multi_select_set(cd->gengrid, EINA_FALSE);
180 // evas_object_smart_callback_add(cd->gengrid, "selected", _grid_click_paste, ad);
181 evas_object_size_hint_weight_set(cd->gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
183 elm_gengrid_clear(cd->gengrid);
185 cd->gic.item_style = "clipboard";
186 cd->gic.func.text_get = NULL;
187 cd->gic.func.content_get = _grid_content_get;
188 cd->gic.func.state_get = NULL;
189 cd->gic.func.del = NULL;
191 evas_object_show(cd->gengrid);
193 ad->draw_item_add = clipdrawer_add_item;
194 ad->draw_item_del = clipdrawer_del_item;
195 // ad->x_main_win = cd->x_main_win;
197 cd->keydown_handler = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, keydown_cb, ad);
198 cd->evas = evas_object_evas_get(cd->main_win);
200 delete_mode = EINA_FALSE;
205 void depose_clipdrawer(ClipdrawerData *cd)
207 utilx_ungrab_key(ecore_x_display_get(), cd->x_main_win, KEY_END);
208 evas_object_del(cd->main_win);
210 ecore_timer_del(cd->anim_timer);
211 if (cd->keydown_handler)
212 ecore_event_handler_del(cd->keydown_handler);
216 static Eina_Bool clipdrawer_add_item(AppData *ad, CNP_ITEM *item)
218 ClipdrawerData *cd = ad->clipdrawer;
219 if (item->type_index == ATOM_INDEX_IMAGE)
221 Elm_Object_Item *gitem = elm_gengrid_first_item_get(cd->gengrid);
224 CNP_ITEM *gitem_data = elm_object_item_data_get(gitem);
225 gitem = elm_gengrid_item_next_get(gitem);
226 if ((gitem_data->type_index == item->type_index) && (!strcmp(item->data, gitem_data->data)))
228 DMSG("duplicated file path = %s\n", item->data);
229 item_delete_by_CNP_ITEM(ad, gitem_data);
234 item->gitem = elm_gengrid_item_prepend(cd->gengrid, &cd->gic, item, NULL, NULL);
239 static Eina_Bool clipdrawer_del_item(AppData *ad, CNP_ITEM *item)
242 elm_object_item_del(item->gitem);
246 static Evas_Object *_grid_content_get(void *data, Evas_Object *obj, const char *part)
248 CNP_ITEM *item = data;
249 AppData *ad = item->ad;
250 ClipdrawerData *cd = ad->clipdrawer;
252 if (item->type_index == ATOM_INDEX_IMAGE && !strcmp(part, "elm.swallow.icon")) /* uri */
256 Evas_Object *layout = elm_layout_add(obj);
257 elm_layout_file_set(layout, APP_EDJ_FILE, "elm/gengrid/item/clipboard_image/default");
258 elm_object_signal_callback_add(layout,
259 "mouse,clicked,1", "*", _grid_item_ly_clicked, data);
261 int grid_image_real_w = cd->grid_image_item_w;
262 int grid_image_real_h = cd->grid_image_item_h;
264 Evas_Object *sicon = evas_object_image_add(evas_object_evas_get(obj));
265 evas_object_image_load_size_set(sicon, grid_image_real_w, grid_image_real_h);
266 evas_object_image_file_set(sicon, item->data, NULL);
267 evas_object_image_size_get(sicon, &w, &h);
269 if (w <= 0 || h <= 0)
272 if (w > grid_image_real_w || h > grid_image_real_h)
276 ih = (float)grid_image_real_w / w * h;
277 if (ih > grid_image_real_h)
279 iw = (float)grid_image_real_h / h * w;
280 ih = grid_image_real_h;
284 iw = grid_image_real_w;
289 iw = (float)grid_image_real_h / h * w;
290 ih = grid_image_real_h;
299 evas_object_image_fill_set(sicon, 0, 0, iw, ih);
300 evas_object_resize(sicon, iw, ih);
301 evas_object_size_hint_min_set(sicon, iw, ih);
302 elm_object_part_content_set(layout, "elm.swallow.icon", sicon);
304 if (cd->paste_text_only)
305 elm_object_signal_emit(layout, "elm,state,show,dim", "elm");
307 elm_object_signal_emit(layout, "elm,state,hide,dim", "elm");
309 item->layout = layout;
311 else if (item->type_index != ATOM_INDEX_IMAGE && !strcmp(part, "elm.swallow.entry")) /* text */
313 Evas_Object *layout = elm_layout_add(obj);
314 elm_layout_file_set(layout, APP_EDJ_FILE, "elm/gengrid/item/clipboard_text/default");
315 elm_object_signal_callback_add(layout,
316 "mouse,clicked,1", "*", _grid_item_ly_clicked, data);
318 Evas_Object *ientry = elm_entry_add(obj);
319 evas_object_size_hint_weight_set(ientry, 0, 0);
320 elm_entry_scrollable_set(ientry, EINA_TRUE);
322 char *entry_text = string_for_entry_get(ad, item->type_index, item->data);
325 elm_object_part_text_set(ientry, NULL, entry_text);
330 elm_object_part_text_set(ientry, NULL, item->data);
332 elm_entry_editable_set(ientry, EINA_FALSE);
333 elm_entry_context_menu_disabled_set(ientry, EINA_TRUE);
334 evas_object_show(ientry);
335 elm_object_part_content_set(layout, "elm.swallow.entry", ientry);
337 item->layout = layout;
343 elm_object_signal_emit(item->layout, "elm,state,show,delbtn", "elm");
345 elm_object_signal_emit(item->layout, "elm,state,hide,delbtn", "elm");
350 static void clipdrawer_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source)
354 if (ad->clipdrawer->anim_status != STATUS_NONE)
357 #define EDJE_CLOSE_PART_PREFIX "background/title/close/image"
358 #define EDJE_DELETE_MODE_PREFIX "background/title/delete/image"
359 if (!strncmp(source, EDJE_CLOSE_PART_PREFIX, strlen(EDJE_CLOSE_PART_PREFIX)))
361 clipdrawer_lower_view(ad);
363 else if (!strncmp(source, EDJE_DELETE_MODE_PREFIX, strlen(EDJE_DELETE_MODE_PREFIX)))
365 _delete_mode_set(ad, !delete_mode);
370 static void _grid_item_ly_clicked(void *data, Evas_Object *obj, const char *emission, const char *source)
372 CNP_ITEM *item = data;
373 AppData *ad = item->ad;
374 ClipdrawerData *cd = ad->clipdrawer;
376 if (cd->anim_status != STATUS_NONE)
381 DTRACE("ERR: cbhm can't get the selected item\n");
385 #define EDJE_DELBTN_PART_PREFIX "delbtn/img"
386 if (strncmp(source, EDJE_DELBTN_PART_PREFIX, strlen(EDJE_DELBTN_PART_PREFIX)))
391 if (item->type_index != ATOM_INDEX_IMAGE || !cd->paste_text_only)
393 set_selection_owner(ad, ECORE_X_SELECTION_SECONDARY, item);
398 item_delete_by_CNP_ITEM(ad, item);
402 void set_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win)
404 ecore_x_icccm_transient_for_set(x_main_win, x_active_win);
405 ecore_x_event_mask_set(x_active_win,
406 ECORE_X_EVENT_MASK_WINDOW_PROPERTY | ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
409 void unset_transient_for(Ecore_X_Window x_main_win, Ecore_X_Window x_active_win)
411 ecore_x_event_mask_unset(x_active_win,
412 ECORE_X_EVENT_MASK_WINDOW_PROPERTY | ECORE_X_EVENT_MASK_WINDOW_CONFIGURE);
413 ecore_x_icccm_transient_for_unset(x_main_win);
416 static void set_focus_for_app_window(Ecore_X_Window x_main_win, Eina_Bool enable)
419 Eina_Bool accepts_focus;
420 Ecore_X_Window_State_Hint initial_state;
421 Ecore_X_Pixmap icon_pixmap;
422 Ecore_X_Pixmap icon_mask;
423 Ecore_X_Window icon_window;
424 Ecore_X_Window window_group;
427 ecore_x_icccm_hints_get (x_main_win,
428 &accepts_focus, &initial_state, &icon_pixmap, &icon_mask, &icon_window, &window_group, &is_urgent);
429 ecore_x_icccm_hints_set (x_main_win,
430 enable, initial_state, icon_pixmap, icon_mask, icon_window, window_group, is_urgent);
431 DMSG("set focus mode = %d\n", enable);
434 void setting_win(Ecore_X_Display *x_disp, Ecore_X_Window x_main_win)
437 // disable window effect
438 utilx_set_window_effect_state(x_disp, x_main_win, 0);
440 ecore_x_icccm_name_class_set(x_main_win, "NORMAL_WINDOW", "NORMAL_WINDOW");
442 set_focus_for_app_window(x_main_win, EINA_FALSE);
443 utilx_grab_key(x_disp, x_main_win, KEY_END, TOP_POSITION_GRAB);
446 Evas_Object *create_win(ClipdrawerData *cd, const char *name)
450 Evas_Object *win = elm_win_add(NULL, name, ELM_WIN_BASIC);
453 DMSG("ERROR: elm_win_add return NULL\n");
456 elm_win_title_set(win, name);
457 elm_win_borderless_set(win, EINA_TRUE);
458 ecore_x_window_size_get(ecore_x_window_root_first_get(), &cd->root_w, &cd->root_h);
459 DMSG("root_w: %d, root_h: %d\n", cd->root_w, cd->root_h);
460 //evas_object_resize(win, cd->root_w, cd->root_h);
462 elm_config_scale_set((double)cd->root_w/DEFAULT_WIDTH);
466 static void set_sliding_win_geometry(ClipdrawerData *cd)
470 Evas_Coord x, y, w, h;
471 zone = ecore_x_e_illume_zone_get(cd->x_main_win);
472 DTRACE(" zone:%x\n", zone);
474 if (cd->o_degree == 90 || cd->o_degree == 270)
476 h = cd->landscape_height;
492 DTRACE("[CBHM] change degree geometry... (%d, %d, %d x %d)\n", x, y, w, h);
494 ecore_x_e_illume_clipboard_geometry_set(zone, x, y, w, h);
497 void set_rotation_to_clipdrawer(ClipdrawerData *cd)
500 int angle = cd->o_degree;
503 if (angle == 180) // reverse
510 else if (angle == 90) // right rotate
512 h = cd->landscape_height;
517 else if (angle == 270) // left rotate
519 h = cd->landscape_height;
532 evas_object_resize(cd->main_win, w, h);
533 evas_object_move(cd->main_win, x, y);
534 set_sliding_win_geometry(cd);
537 static Eina_Bool _get_anim_pos(ClipdrawerData *cd, int *sp, int *ep)
542 int angle = cd->o_degree;
543 int anim_start, anim_end;
545 if (angle == 180) // reverse
547 anim_start = -(cd->root_h - cd->height);
550 else if (angle == 90) // right rotate
552 anim_start = cd->root_w;
553 anim_end = anim_start - cd->landscape_height;
555 else if (angle == 270) // left rotate
557 anim_start = -(cd->root_w - cd->landscape_height);
562 anim_start = cd->root_h;
563 anim_end = anim_start - cd->height;
571 static Eina_Bool _do_anim_delta_pos(ClipdrawerData *cd, int sp, int ep, int ac, int *dp)
576 int angle = cd->o_degree;
579 posprop = 1.0*ac/ANIM_DURATION;
581 if (angle == 180) // reverse
583 delta = (int)((ep-sp)*posprop);
584 evas_object_move(cd->main_win, 0, sp+delta);
586 else if (angle == 90) // right rotate
588 delta = (int)((ep-sp)*posprop);
589 evas_object_move(cd->main_win, sp+delta, 0);
591 else if (angle == 270) // left rotate
593 delta = (int)((ep-sp)*posprop);
594 evas_object_move(cd->main_win, sp+delta, 0);
598 delta = (int)((sp-ep)*posprop);
599 evas_object_move(cd->main_win, 0, sp-delta);
607 static void stop_animation(AppData *ad)
610 ClipdrawerData *cd = ad->clipdrawer;
611 cd->anim_status = STATUS_NONE;
614 ecore_timer_del(cd->anim_timer);
615 cd->anim_timer = NULL;
618 set_sliding_win_geometry(cd);
621 static Eina_Bool anim_pos_calc_cb(void *data)
624 ClipdrawerData *cd = ad->clipdrawer;
625 int anim_start, anim_end, delta;
627 _get_anim_pos(cd, &anim_start, &anim_end);
629 if (cd->anim_status == SHOW_ANIM)
631 if (cd->anim_count > ANIM_DURATION)
633 cd->anim_count = ANIM_DURATION;
637 _do_anim_delta_pos(cd, anim_start, anim_end, cd->anim_count, &delta);
638 if (cd->anim_count == 1)
639 evas_object_show(cd->main_win);
642 else if (cd->anim_status == HIDE_ANIM)
644 if (cd->anim_count < 0)
647 evas_object_hide(cd->main_win);
648 elm_win_lower(cd->main_win);
649 unset_transient_for(cd->x_main_win, ad->x_active_win);
651 _delete_mode_set(ad, EINA_FALSE);
654 _do_anim_delta_pos(cd, anim_start, anim_end, cd->anim_count, &delta);
666 static Eina_Bool clipdrawer_anim_effect(AppData *ad, AnimStatus atype)
669 ClipdrawerData *cd = ad->clipdrawer;
670 if (atype == cd->anim_status)
672 DTRACE("Warning: Animation effect is already in progress. \n");
676 cd->anim_status = atype;
679 ecore_timer_del(cd->anim_timer);
680 cd->anim_timer = ecore_timer_add(ANIM_FLOPS, anim_pos_calc_cb, ad);
685 void clipdrawer_activate_view(AppData* ad)
688 ClipdrawerData *cd = ad->clipdrawer;
692 elm_object_part_text_set(cd->main_layout, "panel_title", S_CLIPBOARD);
693 elm_object_part_text_set(cd->main_layout, "panel_function", S_DELETE);
698 set_transient_for(cd->x_main_win, ad->x_active_win);
699 cd->o_degree = get_active_window_degree(ad->x_active_win);
700 elm_win_rotation_set(cd->main_win, cd->o_degree);
701 set_rotation_to_clipdrawer(cd);
702 evas_object_show(cd->main_win);
703 elm_win_activate(cd->main_win);
704 Ecore_X_Window zone = ecore_x_e_illume_zone_get(cd->x_main_win);
705 ecore_x_e_illume_clipboard_state_set(zone, ECORE_X_ILLUME_CLIPBOARD_STATE_ON);
709 void clipdrawer_lower_view(AppData* ad)
712 ClipdrawerData *cd = ad->clipdrawer;
715 evas_object_hide(cd->main_win);
716 elm_win_lower(cd->main_win);
717 unset_transient_for(cd->x_main_win, ad->x_active_win);
718 _delete_mode_set(ad, EINA_FALSE);
719 Ecore_X_Window zone = ecore_x_e_illume_zone_get(cd->x_main_win);
720 ecore_x_e_illume_clipboard_state_set(zone, ECORE_X_ILLUME_CLIPBOARD_STATE_OFF);
721 ecore_x_e_illume_clipboard_geometry_set(zone, 0, 0, 0, 0);
725 void _delete_mode_set(AppData* ad, Eina_Bool del_mode)
727 ClipdrawerData *cd = ad->clipdrawer;
728 Elm_Object_Item *gitem = elm_gengrid_first_item_get(cd->gengrid);
729 CNP_ITEM *item = NULL;
732 delete_mode = del_mode;
734 delete_mode = EINA_FALSE;
740 elm_object_part_text_set(cd->main_layout, "panel_function", S_DONE);
744 elm_object_part_text_set(cd->main_layout, "panel_function", S_DELETE);
749 item = elm_object_item_data_get(gitem);
753 elm_object_signal_emit(item->layout, "elm,state,show,delbtn", "elm");
755 elm_object_signal_emit(item->layout, "elm,state,hide,delbtn", "elm");
757 gitem = elm_gengrid_item_next_get(gitem);