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://www.tizenopensource.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.
19 #include <X11/Xatom.h>
22 Ecore_X_Window get_selection_owner(AppData *ad, Ecore_X_Selection selection)
29 case ECORE_X_SELECTION_SECONDARY:
30 sel = ECORE_X_ATOM_SELECTION_SECONDARY;
32 case ECORE_X_SELECTION_CLIPBOARD:
33 sel = ECORE_X_ATOM_SELECTION_CLIPBOARD;
38 return XGetSelectionOwner(ad->x_disp, sel);
41 Eina_Bool is_cbhm_selection_owner(AppData *ad, Ecore_X_Selection selection)
44 if (!ad) return EINA_FALSE;
45 Ecore_X_Window sel_owner = get_selection_owner(ad, selection);
46 DMSG("selection_owner: 0x%x, x_event_win: 0x%x \n", sel_owner, ad->x_event_win);
47 if (sel_owner == ad->x_event_win)
52 Eina_Bool set_selection_owner(AppData *ad, Ecore_X_Selection selection, CNP_ITEM *item)
55 if (!ad) return EINA_FALSE;
57 if (!item && is_cbhm_selection_owner(ad, selection))
61 Eina_Bool (*selection_func)(Ecore_X_Window win, const void *data, int size) = NULL;
65 case ECORE_X_SELECTION_SECONDARY:
66 // ecore_x_selection_secondary_clear();
67 selection_func = ecore_x_selection_secondary_set;
68 ad->clip_selected_item = item;
70 case ECORE_X_SELECTION_CLIPBOARD:
71 // ecore_x_selection_clipboard_clear();
72 selection_func = ecore_x_selection_clipboard_set;
78 if (selection_func(ad->x_event_win, NULL, 0))
81 DMSG("ERROR: set selection failed\n");
85 static Eina_Bool selection_timer_cb(void *data)
89 XHandlerData *xd = ad->xhandler;
91 set_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD, NULL);
92 if (is_cbhm_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD))
94 ecore_timer_del(xd->selection_timer);
95 xd->selection_timer = NULL;
96 return ECORE_CALLBACK_CANCEL;
98 return ECORE_CALLBACK_RENEW;
101 static Eina_Bool _xsel_clear_cb(void *data, int type, void *event)
104 if (!data || !event) return EINA_TRUE;
106 XHandlerData *xd = ad->xhandler;
107 Ecore_X_Event_Selection_Clear *ev = event;
109 DMSG("in %s, ev->win: 0x%x\n", __func__, ev->win);
111 if (is_cbhm_selection_owner(ad, ev->selection)) return EINA_TRUE;
112 if (ev->selection != ECORE_X_SELECTION_CLIPBOARD)
113 return ECORE_CALLBACK_PASS_ON;
115 ecore_x_selection_clipboard_request(ad->x_event_win, ECORE_X_SELECTION_TARGET_TARGETS);
117 if (xd->selection_timer)
119 ecore_timer_del(xd->selection_timer);
120 xd->selection_timer = NULL;
122 xd->selection_timer = ecore_timer_add(SELECTION_CHECK_TIME, selection_timer_cb, ad);
124 return ECORE_CALLBACK_DONE;
127 static Eina_Bool _xsel_request_cb(void *data, int type, void *event)
130 if (!data || !event) return ECORE_CALLBACK_PASS_ON;
132 Ecore_X_Event_Selection_Request *ev = event;
136 DMSG("selection_owner: 0x%x, ev->... owner: 0x%x, req: 0x%x, selection: %s, target: %s, property: %s\n",
137 get_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD), ev->owner, ev->requestor,
138 names[0] = ecore_x_atom_name_get(ev->selection),
139 names[1] = ecore_x_atom_name_get(ev->target),
140 names[2] = ecore_x_atom_name_get(ev->property));
146 CNP_ITEM *item = NULL;
147 if (ev->selection == ECORE_X_ATOM_SELECTION_CLIPBOARD)
148 item = item_get_last(ad);
149 else if (ev->selection == ECORE_X_ATOM_SELECTION_SECONDARY)
150 item = ad->clip_selected_item;
152 return ECORE_CALLBACK_PASS_ON;
156 DMSG("has no item\n");
157 ecore_x_selection_notify_send(ev->requestor,
162 DMSG("change property notify\n");
164 return ECORE_CALLBACK_DONE;
167 Ecore_X_Atom property = None;
168 void *data_ret = NULL;
173 if (!generic_converter(ad, ev->target, item, &data_ret, &size_ret, &ttype, &tsize))
174 /* if (!ecore_x_selection_convert(ev->selection,
176 &data_ret, &len, &typeAtom, &typesize))*/
179 /* Refuse selection, conversion to requested target failed */
180 DMSG("converter return FALSE\n");
184 /* FIXME: This does not properly handle large data transfers */
185 ecore_x_window_prop_property_set(
192 property = ev->property;
194 DMSG("change property\n");
197 ecore_x_selection_notify_send(ev->requestor,
202 DMSG("change property notify\n");
204 return ECORE_CALLBACK_DONE;
207 static void send_convert_selection_target(AppData *ad, Ecore_X_Selection_Data_Targets *targets_data)
210 /* struct _Ecore_X_Selection_Data_Targets {
211 Ecore_X_Selection_Data data;
212 struct _Ecore_X_Selection_Data {
214 ECORE_X_SELECTION_CONTENT_NONE,
215 ECORE_X_SELECTION_CONTENT_TEXT,
216 ECORE_X_SELECTION_CONTENT_FILES,
217 ECORE_X_SELECTION_CONTENT_TARGETS,
218 ECORE_X_SELECTION_CONTENT_CUSTOM
223 int (*FREE)(void *data);
229 if (!targets_data || !ad)
231 Ecore_X_Atom *atomlist = (Ecore_X_Atom *)targets_data->data.data;
235 DMSG("targets_data->num_targets: 0x%x\n", targets_data->num_targets);
237 for (i = 0; i < targets_data->num_targets; i++)
239 DMSG("get target: %s\n", targets_data->targets[i]);
240 for (j = 0; j < ATOM_INDEX_MAX; j++)
242 for (k = 0; k < ad->targetAtoms[j].atom_cnt; k++)
244 if (!strcmp(targets_data->targets[i], ad->targetAtoms[j].name[k]))
246 DMSG("find matched target: %s\n", ad->targetAtoms[j].name[k]);
247 ecore_x_selection_clipboard_request(ad->x_event_win, ad->targetAtoms[j].name[k]);
253 DMSG("ERROR: get target atom failed\n");
256 static Eina_Bool _add_selection_imagepath(AppData* ad, char *str)
260 DMSG("get FILE: %s\n", str);
261 char *slash = strchr(str, '/');
262 while (slash && slash[0] == '/')
267 filepath = strdup(slash);
270 if (ecore_file_exists(filepath))
272 item_add_by_data(ad, ad->targetAtoms[ATOM_INDEX_IMAGE].atom[0], filepath, strlen(filepath) + 1);
282 DMSG("Error : it isn't normal file = %s\n", str);
286 static void _get_selection_data_files(AppData* ad, Ecore_X_Selection_Data_Files *files_data)
288 /* struct _Ecore_X_Selection_Data_Files {
289 Ecore_X_Selection_Data data;
295 for (i = 0; i < files_data->num_files; i++)
297 _add_selection_imagepath(ad, files_data->files[i]);
301 static Eina_Bool _xsel_notify_cb(void *data, int type, void *event)
305 return ECORE_CALLBACK_PASS_ON;
308 XHandlerData *xd = ad->xhandler;
309 if (xd->selection_timer)
311 ecore_timer_del(xd->selection_timer);
312 xd->selection_timer = NULL;
315 /* struct _Ecore_X_Event_Selection_Notify
319 Ecore_X_Selection selection;
324 Ecore_X_Event_Selection_Notify *ev = event;
326 switch (ev->selection)
328 case ECORE_X_SELECTION_CLIPBOARD:
330 case ECORE_X_SELECTION_SECONDARY:
331 case ECORE_X_SELECTION_PRIMARY:
332 case ECORE_X_SELECTION_XDND:
334 return ECORE_CALLBACK_PASS_ON;
337 goto set_clipboard_selection_owner;
339 /* struct _Ecore_X_Selection_Data {
341 ECORE_X_SELECTION_CONTENT_NONE,
342 ECORE_X_SELECTION_CONTENT_TEXT,
343 ECORE_X_SELECTION_CONTENT_FILES,
344 ECORE_X_SELECTION_CONTENT_TARGETS,
345 ECORE_X_SELECTION_CONTENT_CUSTOM
350 int (*FREE)(void *data);
352 Ecore_X_Selection_Data *sel_data = ev->data;
353 switch (sel_data->content)
355 case ECORE_X_SELECTION_CONTENT_NONE:
356 DMSG("ECORE_X_SELECTION_CONTENT_NONE\n");
358 case ECORE_X_SELECTION_CONTENT_TEXT:
359 DMSG("ECORE_X_SELECTION_CONTENT_TEXT\n");
360 /* struct _Ecore_X_Selection_Data_Text {
361 Ecore_X_Selection_Data data;
364 Ecore_X_Selection_Data_Text *text_data = ev->data;*/
365 // DMSG("sel_data->data: 0x%x, text_data->text: 0x%x\n", sel_data->data, text_data->text);
367 case ECORE_X_SELECTION_CONTENT_FILES:
368 DMSG("ECORE_X_SELECTION_CONTENT_FILES\n");
369 _get_selection_data_files(ad, ev->data);
370 goto set_clipboard_selection_owner;
372 case ECORE_X_SELECTION_CONTENT_TARGETS:
373 DMSG("ECORE_X_SELECTION_CONTENT_TARGETS\n");
374 send_convert_selection_target(ad, ev->data);
375 if (!is_cbhm_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD))
376 xd->selection_timer = ecore_timer_add(SELECTION_CHECK_TIME, selection_timer_cb, ad);
377 return ECORE_CALLBACK_DONE;
378 case ECORE_X_SELECTION_CONTENT_CUSTOM:
379 DMSG("ECORE_X_SELECTION_CONTENT_CUSTOM\n");
384 DMSG("get atom: %d(%s), target: %s, length: %d, format: %d\n",
385 ev->atom, name = ecore_x_atom_name_get(ev->atom), ev->target, sel_data->length, sel_data->format);
389 Ecore_X_Atom targetAtom = ecore_x_atom_get(ev->target);
390 char *stripstr = strndup(sel_data->data, sel_data->length);
391 DMSG("get data: %s, len: %d\n", stripstr, strlen(stripstr));
392 if (atom_type_index_get(ad, targetAtom) == ATOM_INDEX_IMAGE)
394 _add_selection_imagepath(ad, stripstr);
398 item_add_by_data(ad, targetAtom, stripstr, strlen(stripstr) + 1);
402 set_clipboard_selection_owner:
403 set_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD, NULL);
404 if (!is_cbhm_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD))
405 xd->selection_timer = ecore_timer_add(SELECTION_CHECK_TIME, selection_timer_cb, ad);
407 return ECORE_CALLBACK_DONE;
410 static Eina_Bool _xclient_msg_cb(void *data, int type, void *event)
414 XHandlerData *xd = ad->xhandler;
416 /* struct _Ecore_X_Event_Client_Message {
418 Ecore_X_Atom message_type;
428 Ecore_X_Event_Client_Message *ev = event;
430 if (ev->message_type != xd->atomCBHM_MSG)
433 DTRACE("## %s\n", ev->data.b);
435 /* Atom cbhm_atoms[ITEM_CNT_MAX];
437 Ecore_X_Window reqwin = ev->win;*/
439 if (strncmp("show", ev->data.b, 4) == 0)
441 ad->x_active_win = ev->win;
442 if (ev->data.b[4] == '1')
443 clipdrawer_paste_textonly_set(ad, EINA_FALSE);
445 clipdrawer_paste_textonly_set(ad, EINA_TRUE);
447 clipdrawer_activate_view(ad);
449 else if (!strcmp("cbhm_hide", ev->data.b))
451 clipdrawer_lower_view(ad);
453 else if (!strcmp("get count", ev->data.b))
455 int icount = item_count_get(ad);
457 DMSG("## cbhm count : %d\n", icount);
458 snprintf(countbuf, 10, "%d", icount);
459 ecore_x_window_prop_property_set(
468 else if (strncmp("GET_ITEM", ev->data.b, 8) == 0)
472 xd->atomCBHM_ITEM = ecore_x_atom_get("CBHM_ITEM");
474 while ('0' <= ev->data.b[index] && ev->data.b[index] <= '9')
476 itempos = (itempos * 10) + (ev->data.b[index] - '0');
480 CNP_ITEM *item = item_get_by_index(ad, itempos);
483 Ecore_X_Atom itemtype = ecore_x_atom_get("CBHM_ERROR");
485 char error_buf[] = "OUT OF BOUND";
486 int bufsize = sizeof(error_buf);
487 ecore_x_window_prop_property_set(
494 DMSG("GET ITEM ERROR msg: %s, index: %d, item count: %d\n",
495 ev->data.b, itempos, item_count_get(ad));
499 ecore_x_window_prop_property_set(
502 ad->targetAtoms[item->type_index].atom[0],
506 DMSG("GET ITEM index: %d, item type: %d, item data: %s, item->len: %d\n",
507 itempos, ad->targetAtoms[item->type_index].atom[0],
508 item->data, item->len);
511 else if (strncmp("SET_ITEM", ev->data.b, 8) == 0)
516 long unsigned int bytes = 0;
517 unsigned char *item_data = NULL;
518 unsigned char *prop_ret = NULL;
519 Ecore_X_Atom format = 0;
521 xd->atomCBHM_ITEM = ecore_x_atom_get("CBHM_ITEM");
522 ret = XGetWindowProperty(ecore_x_display_get(), ad->x_event_win, xd->atomCBHM_ITEM, 0, LONG_MAX, False, ecore_x_window_prop_any_type(),
523 (Atom*)&format, &size_ret, &num_ret, &bytes, &prop_ret);
527 DMSG("Failed Set Item\n");
536 if (!(item_data = malloc(num_ret * size_ret / 8)))
545 for (i = 0; i < num_ret; i++)
546 item_data[i] = prop_ret[i];
549 for (i = 0; i < num_ret; i++)
550 ((unsigned short *)item_data)[i] = ((unsigned short *)prop_ret)[i];
553 for (i = 0; i < num_ret; i++)
554 ((unsigned int *)item_data)[i] = ((unsigned long *)prop_ret)[i];
560 DMSG("item_data:%s format:%s(%d)\n", item_data, ecore_x_atom_name_get(format), format);
561 item_add_by_data(ad, format, item_data, strlen(item_data) + 1);
563 else if (strncmp("DEL_ITEM", ev->data.b, 8) == 0)
568 while ('0' <= ev->data.b[index] && ev->data.b[index] <= '9')
570 itempos = (itempos * 10) + (ev->data.b[index] - '0');
574 item_delete_by_index(ad, itempos);
576 /* else if (strncmp("get #", ev->data.b, 5) == 0)
578 // FIXME : handle greater than 9
579 int num = ev->data.b[5] - '0';
580 int cur = get_current_history_position();
582 if (num > ITEMS_CNT_MAX-1)
583 num = num-ITEMS_CNT_MAX;
585 if (num >= 0 && num < ITEMS_CNT_MAX)
587 DTRACE("## pos : #%d\n", num);
588 // FIXME : handle with correct atom
589 sprintf(atomname, "CBHM_c%d", num);
590 cbhm_atoms[0] = XInternAtom(g_disp, atomname, False);
592 CNP_ITEM *item = clipdr;
595 if (clipdrawer_get_item_data(ad, num) != NULL)
597 XChangeProperty(g_disp, reqwin, cbhm_atoms[0], atomUTF8String,
599 (unsigned char *) clipdrawer_get_item_data(ad, num),
600 (int) strlen(clipdrawer_get_item_data(ad, num)));
604 else if (strcmp("get all", ev->data.b) == 0)
606 // print_history_buffer();
607 pos = get_current_history_position();
608 for (i = 0; i < 5; i++)
610 DTRACE("## %d -> %d\n", i, pos);
611 sprintf(atomname, "CBHM_c%d", i);
612 cbhm_atoms[i] = XInternAtom(g_disp, atomname, False);
613 if (clipdrawer_get_item_data(ad, pos) != NULL)
615 XChangeProperty(g_disp, reqwin, cbhm_atoms[i], atomUTF8String,
617 (unsigned char *) clipdrawer_get_item_data(ad, pos),
618 (int) strlen(clipdrawer_get_item_data(ad, pos)));
622 pos = ITEMS_CNT_MAX-1;
625 /* else if (strcmp("get raw", ev->data.b) == 0)
628 if (get_storage_start_addr != NULL)
630 XChangeProperty(g_disp, reqwin, atomCBHM_cRAW, atomUTF8String,
632 (unsigned char *) get_storage_start_addr(),
633 (int) get_total_storage_size());
642 static Eina_Bool _xfocus_out_cb(void *data, int type, void *event)
646 DTRACE("XE:FOCUS OUT\n");
647 clipdrawer_lower_view(ad);
651 static Eina_Bool _xproperty_notify_cb(void *data, int type, void *event)
655 XHandlerData *xd = ad->xhandler;
656 ClipdrawerData *cd = ad->clipdrawer;
657 Ecore_X_Event_Window_Property *pevent = (Ecore_X_Event_Window_Property *)event;
659 if (ad->x_active_win != pevent->win)
662 if (xd->atomWindowRotate == pevent->atom)
664 int angle = get_active_window_degree(ad->x_active_win);
665 if (angle != cd->o_degree)
667 cd->o_degree = angle;
668 elm_win_rotation_set(cd->main_win, angle);
669 set_rotation_to_clipdrawer(cd);
676 static Eina_Bool _xwin_destroy_cb(void *data, int type, void *event)
680 Ecore_X_Event_Window_Destroy *pevent = event;
681 if (ad->x_active_win != pevent->win)
683 clipdrawer_lower_view(ad);
686 XHandlerData *init_xhandler(AppData *ad)
688 XHandlerData *xd = CALLOC(1, sizeof(XHandlerData));
691 xd->xsel_clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _xsel_clear_cb, ad);
692 xd->xsel_request_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_REQUEST, _xsel_request_cb, ad);
693 xd->xsel_notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _xsel_notify_cb, ad);
694 xd->xclient_msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _xclient_msg_cb, ad);
695 xd->xfocus_out_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, _xfocus_out_cb, ad);
696 xd->xproperty_notify_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _xproperty_notify_cb, ad);
697 xd->xwindow_destroy_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _xwin_destroy_cb, ad);
699 xd->atomInc = ecore_x_atom_get("INCR");
700 xd->atomWindowRotate = ecore_x_atom_get("_E_ILLUME_ROTATE_WINDOW_ANGLE");
701 xd->atomCBHM_MSG = ecore_x_atom_get("CBHM_MSG");
702 xd->atomCBHM_ITEM = ecore_x_atom_get("CBHM_ITEM");
703 xd->atomXKey_MSG = ecore_x_atom_get("_XKEY_COMPOSITION");
704 xd->atomCBHMCount = ecore_x_atom_get("CBHM_cCOUNT");
705 xd->atomUTF8String = ecore_x_atom_get("UTF8_STRING");
708 for (i = 0; i < ITEM_CNT_MAX; i++)
711 snprintf(buf, sizeof(buf), "CBHM_ITEM%d", i);
712 xd->atomCBHM_ITEM = ecore_x_atom_get(buf);
718 void depose_xhandler(XHandlerData *xd)
720 ecore_event_handler_del(xd->xsel_clear_handler);
721 ecore_event_handler_del(xd->xsel_request_handler);
722 ecore_event_handler_del(xd->xsel_notify_handler);
723 ecore_event_handler_del(xd->xclient_msg_handler);
724 ecore_event_handler_del(xd->xfocus_out_handler);
725 ecore_event_handler_del(xd->xproperty_notify_handler);
726 ecore_event_handler_del(xd->xwindow_destroy_handler);
730 int get_active_window_degree(Ecore_X_Window active)
732 //ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE
735 unsigned char *prop_data = NULL;
737 int ret = ecore_x_window_prop_property_get(
738 active, ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
739 ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
740 if (ret && prop_data) memcpy(&rotation, prop_data, sizeof(int));
741 if (prop_data) FREE(prop_data);
745 void slot_property_set(AppData *ad, int index)
747 XHandlerData *xd = ad->xhandler;
756 EINA_LIST_FOREACH(ad->item_list, l, item)
758 snprintf(buf, sizeof(buf), "CBHM_ITEM%d", i);
759 xd->atomCBHM_ITEM = ecore_x_atom_get(buf);
762 ecore_x_window_prop_property_set(
765 ad->targetAtoms[item->type_index].atom[0],
769 DMSG("GET ITEM index: %d, item type: %d, item data: %s, item->len: %d\n",
770 i, ad->targetAtoms[item->type_index].atom[0],
771 item->data, item->len);
777 else if (index < ITEM_CNT_MAX)
780 snprintf(buf, sizeof(buf), "CBHM_ITEM%d", index);
781 xd->atomCBHM_ITEM = ecore_x_atom_get(buf);
783 CNP_ITEM *item = item_get_by_index(ad, index);
786 Ecore_X_Atom itemtype = ecore_x_atom_get("CBHM_ERROR");
788 char error_buf[] = "OUT OF BOUND";
789 int bufsize = sizeof(error_buf);
790 ecore_x_window_prop_property_set(
797 DMSG("CBHM Error: index: %d, item count: %d\n",
798 index, item_count_get(ad));
802 ecore_x_window_prop_property_set(
805 ad->targetAtoms[item->type_index].atom[0],
809 DMSG("GET ITEM index: %d, item type: %d, item data: %s, item->len: %d\n",
810 index, ad->targetAtoms[item->type_index].atom[0],
811 item->data, item->len);
816 DMSG("can't set property\n");
820 void slot_item_count_set(AppData *ad)
822 XHandlerData *xd = ad->xhandler;
824 int icount = item_count_get(ad);
826 snprintf(countbuf, 10, "%d", icount);
827 ecore_x_window_prop_property_set(