2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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));
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;
155 return ECORE_CALLBACK_PASS_ON;
158 Ecore_X_Atom property = None;
159 void *data_ret = NULL;
164 if (!generic_converter(ad, ev->target, item, &data_ret, &size_ret, &ttype, &tsize))
165 /* if (!ecore_x_selection_convert(ev->selection,
167 &data_ret, &len, &typeAtom, &typesize))*/
170 /* Refuse selection, conversion to requested target failed */
171 DMSG("converter return FALSE\n");
175 /* FIXME: This does not properly handle large data transfers */
176 ecore_x_window_prop_property_set(
183 property = ev->property;
185 DMSG("change property\n");
188 ecore_x_selection_notify_send(ev->requestor,
193 DMSG("change property notify\n");
195 return ECORE_CALLBACK_DONE;
198 static void send_convert_selection_target(AppData *ad, Ecore_X_Selection_Data_Targets *targets_data)
201 /* struct _Ecore_X_Selection_Data_Targets {
202 Ecore_X_Selection_Data data;
203 struct _Ecore_X_Selection_Data {
205 ECORE_X_SELECTION_CONTENT_NONE,
206 ECORE_X_SELECTION_CONTENT_TEXT,
207 ECORE_X_SELECTION_CONTENT_FILES,
208 ECORE_X_SELECTION_CONTENT_TARGETS,
209 ECORE_X_SELECTION_CONTENT_CUSTOM
214 int (*FREE)(void *data);
220 if (!targets_data || !ad)
222 Ecore_X_Atom *atomlist = (Ecore_X_Atom *)targets_data->data.data;
226 DMSG("targets_data->num_targets: 0x%x\n", targets_data->num_targets);
228 for (i = 0; i < targets_data->num_targets; i++)
230 DMSG("get target: %s\n", targets_data->targets[i]);
231 for (j = 0; j < ATOM_INDEX_MAX; j++)
233 for (k = 0; k < ad->targetAtoms[j].atom_cnt; k++)
235 if (!strcmp(targets_data->targets[i], ad->targetAtoms[j].name[k]))
237 DMSG("find matched target: %s\n", ad->targetAtoms[j].name[k]);
238 ecore_x_selection_clipboard_request(ad->x_event_win, ad->targetAtoms[j].name[k]);
244 DMSG("ERROR: get target atom failed\n");
247 static Eina_Bool _add_selection_imagepath(AppData* ad, char *str)
251 DMSG("get FILE: %s\n", str);
252 char *slash = strchr(str, '/');
253 while (slash && slash[0] == '/')
258 filepath = strdup(slash);
261 if (ecore_file_exists(filepath))
263 item_add_by_data(ad, ad->targetAtoms[ATOM_INDEX_IMAGE].atom[0], filepath, strlen(filepath) + 1);
273 DMSG("Error : it isn't normal file = %s\n", str);
277 static void _get_selection_data_files(AppData* ad, Ecore_X_Selection_Data_Files *files_data)
279 /* struct _Ecore_X_Selection_Data_Files {
280 Ecore_X_Selection_Data data;
286 for (i = 0; i < files_data->num_files; i++)
288 _add_selection_imagepath(ad, files_data->files[i]);
292 static Eina_Bool _xsel_notify_cb(void *data, int type, void *event)
296 return ECORE_CALLBACK_PASS_ON;
299 XHandlerData *xd = ad->xhandler;
300 if (xd->selection_timer)
302 ecore_timer_del(xd->selection_timer);
303 xd->selection_timer = NULL;
306 /* struct _Ecore_X_Event_Selection_Notify
310 Ecore_X_Selection selection;
315 Ecore_X_Event_Selection_Notify *ev = event;
317 switch (ev->selection)
319 case ECORE_X_SELECTION_CLIPBOARD:
321 case ECORE_X_SELECTION_SECONDARY:
322 case ECORE_X_SELECTION_PRIMARY:
323 case ECORE_X_SELECTION_XDND:
325 return ECORE_CALLBACK_PASS_ON;
328 goto set_clipboard_selection_owner;
330 /* struct _Ecore_X_Selection_Data {
332 ECORE_X_SELECTION_CONTENT_NONE,
333 ECORE_X_SELECTION_CONTENT_TEXT,
334 ECORE_X_SELECTION_CONTENT_FILES,
335 ECORE_X_SELECTION_CONTENT_TARGETS,
336 ECORE_X_SELECTION_CONTENT_CUSTOM
341 int (*FREE)(void *data);
343 Ecore_X_Selection_Data *sel_data = ev->data;
344 switch (sel_data->content)
346 case ECORE_X_SELECTION_CONTENT_NONE:
347 DMSG("ECORE_X_SELECTION_CONTENT_NONE\n");
349 case ECORE_X_SELECTION_CONTENT_TEXT:
350 DMSG("ECORE_X_SELECTION_CONTENT_TEXT\n");
351 /* struct _Ecore_X_Selection_Data_Text {
352 Ecore_X_Selection_Data data;
355 Ecore_X_Selection_Data_Text *text_data = ev->data;*/
356 // DMSG("sel_data->data: 0x%x, text_data->text: 0x%x\n", sel_data->data, text_data->text);
358 case ECORE_X_SELECTION_CONTENT_FILES:
359 DMSG("ECORE_X_SELECTION_CONTENT_FILES\n");
360 _get_selection_data_files(ad, ev->data);
361 goto set_clipboard_selection_owner;
363 case ECORE_X_SELECTION_CONTENT_TARGETS:
364 DMSG("ECORE_X_SELECTION_CONTENT_TARGETS\n");
365 send_convert_selection_target(ad, ev->data);
366 goto set_clipboard_selection_owner;
368 case ECORE_X_SELECTION_CONTENT_CUSTOM:
369 DMSG("ECORE_X_SELECTION_CONTENT_CUSTOM\n");
374 DMSG("get atom: %d(%s), target: %s, length: %d, format: %d\n",
375 ev->atom, name = ecore_x_atom_name_get(ev->atom), ev->target, sel_data->length, sel_data->format);
379 Ecore_X_Atom targetAtom = ecore_x_atom_get(ev->target);
380 char *stripstr = strndup(sel_data->data, sel_data->length);
381 DMSG("get data: %s, len: %d\n", stripstr, strlen(stripstr));
382 if (atom_type_index_get(ad, targetAtom) == ATOM_INDEX_IMAGE)
384 _add_selection_imagepath(ad, stripstr);
388 item_add_by_data(ad, targetAtom, stripstr, strlen(stripstr) + 1);
392 set_clipboard_selection_owner:
393 set_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD, NULL);
394 if (!is_cbhm_selection_owner(ad, ECORE_X_SELECTION_CLIPBOARD))
395 xd->selection_timer = ecore_timer_add(SELECTION_CHECK_TIME, selection_timer_cb, ad);
397 return ECORE_CALLBACK_DONE;
400 static Eina_Bool _xclient_msg_cb(void *data, int type, void *event)
404 XHandlerData *xd = ad->xhandler;
406 /* struct _Ecore_X_Event_Client_Message {
408 Ecore_X_Atom message_type;
418 Ecore_X_Event_Client_Message *ev = event;
420 if (ev->message_type == xd->atomXKey_MSG)
422 DTRACE("XE:ClientMessage for Screen capture\n");
423 capture_current_screen(ad);
427 if (ev->message_type != xd->atomCBHM_MSG)
430 DTRACE("## %s\n", ev->data.b);
432 /* Atom cbhm_atoms[ITEM_CNT_MAX];
434 Ecore_X_Window reqwin = ev->win;*/
436 if (strncmp("show", ev->data.b, 4) == 0)
438 ad->x_active_win = ev->win;
439 if (ev->data.b[4] == '1')
440 clipdrawer_paste_textonly_set(ad, EINA_FALSE);
442 clipdrawer_paste_textonly_set(ad, EINA_TRUE);
444 clipdrawer_activate_view(ad);
446 else if (!strcmp("cbhm_hide", ev->data.b))
448 clipdrawer_lower_view(ad);
450 else if (!strcmp("get count", ev->data.b))
452 int icount = item_count_get(ad);
454 DMSG("## cbhm count : %d\n", icount);
455 snprintf(countbuf, 10, "%d", icount);
456 ecore_x_window_prop_property_set(
465 else if (strncmp("GET_ITEM", ev->data.b, 8) == 0)
469 xd->atomCBHM_ITEM = ecore_x_atom_get("CBHM_ITEM");
471 while ('0' <= ev->data.b[index] && ev->data.b[index] <= '9')
473 itempos = (itempos * 10) + (ev->data.b[index] - '0');
477 CNP_ITEM *item = item_get_by_index(ad, itempos);
480 Ecore_X_Atom itemtype = ecore_x_atom_get("CBHM_ERROR");
482 char error_buf[] = "OUT OF BOUND";
483 int bufsize = sizeof(error_buf);
484 ecore_x_window_prop_property_set(
491 DMSG("GET ITEM ERROR msg: %s, index: %d, item count: %d\n",
492 ev->data.b, itempos, item_count_get(ad));
496 ecore_x_window_prop_property_set(
499 ad->targetAtoms[item->type_index].atom[0],
503 DMSG("GET ITEM index: %d, item type: %d, item data: %s, item->len: %d\n",
504 itempos, ad->targetAtoms[item->type_index].atom[0],
505 item->data, item->len);
508 /* else if (strncmp("get #", ev->data.b, 5) == 0)
510 // FIXME : handle greater than 9
511 int num = ev->data.b[5] - '0';
512 int cur = get_current_history_position();
514 if (num > ITEMS_CNT_MAX-1)
515 num = num-ITEMS_CNT_MAX;
517 if (num >= 0 && num < ITEMS_CNT_MAX)
519 DTRACE("## pos : #%d\n", num);
520 // FIXME : handle with correct atom
521 sprintf(atomname, "CBHM_c%d", num);
522 cbhm_atoms[0] = XInternAtom(g_disp, atomname, False);
524 CNP_ITEM *item = clipdr;
527 if (clipdrawer_get_item_data(ad, num) != NULL)
529 XChangeProperty(g_disp, reqwin, cbhm_atoms[0], atomUTF8String,
531 (unsigned char *) clipdrawer_get_item_data(ad, num),
532 (int) strlen(clipdrawer_get_item_data(ad, num)));
536 else if (strcmp("get all", ev->data.b) == 0)
538 // print_history_buffer();
539 pos = get_current_history_position();
540 for (i = 0; i < 5; i++)
542 DTRACE("## %d -> %d\n", i, pos);
543 sprintf(atomname, "CBHM_c%d", i);
544 cbhm_atoms[i] = XInternAtom(g_disp, atomname, False);
545 if (clipdrawer_get_item_data(ad, pos) != NULL)
547 XChangeProperty(g_disp, reqwin, cbhm_atoms[i], atomUTF8String,
549 (unsigned char *) clipdrawer_get_item_data(ad, pos),
550 (int) strlen(clipdrawer_get_item_data(ad, pos)));
554 pos = ITEMS_CNT_MAX-1;
557 /* else if (strcmp("get raw", ev->data.b) == 0)
560 if (get_storage_start_addr != NULL)
562 XChangeProperty(g_disp, reqwin, atomCBHM_cRAW, atomUTF8String,
564 (unsigned char *) get_storage_start_addr(),
565 (int) get_total_storage_size());
574 static Eina_Bool _xfocus_out_cb(void *data, int type, void *event)
578 DTRACE("XE:FOCUS OUT\n");
579 clipdrawer_lower_view(ad);
583 static Eina_Bool _xproperty_notify_cb(void *data, int type, void *event)
587 XHandlerData *xd = ad->xhandler;
588 ClipdrawerData *cd = ad->clipdrawer;
589 Ecore_X_Event_Window_Property *pevent = (Ecore_X_Event_Window_Property *)event;
591 if (ad->x_active_win != pevent->win)
594 if (xd->atomWindowRotate == pevent->atom)
596 int angle = get_active_window_degree(ad->x_active_win);
597 if (angle != cd->o_degree)
599 cd->o_degree = angle;
600 elm_win_rotation_set(cd->main_win, angle);
601 set_rotation_to_clipdrawer(cd);
608 static Eina_Bool _xwin_destroy_cb(void *data, int type, void *event)
612 Ecore_X_Event_Window_Destroy *pevent = event;
613 if (ad->x_active_win != pevent->win)
615 clipdrawer_lower_view(ad);
618 XHandlerData *init_xhandler(AppData *ad)
620 XHandlerData *xd = CALLOC(1, sizeof(XHandlerData));
623 xd->xsel_clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _xsel_clear_cb, ad);
624 xd->xsel_request_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_REQUEST, _xsel_request_cb, ad);
625 xd->xsel_notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _xsel_notify_cb, ad);
626 xd->xclient_msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _xclient_msg_cb, ad);
627 xd->xfocus_out_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, _xfocus_out_cb, ad);
628 xd->xproperty_notify_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _xproperty_notify_cb, ad);
629 xd->xwindow_destroy_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _xwin_destroy_cb, ad);
631 xd->atomInc = ecore_x_atom_get("INCR");
632 xd->atomWindowRotate = ecore_x_atom_get("_E_ILLUME_ROTATE_WINDOW_ANGLE");
633 xd->atomCBHM_MSG = ecore_x_atom_get("CBHM_MSG");
634 xd->atomCBHM_ITEM = ecore_x_atom_get("CBHM_ITEM");
635 xd->atomXKey_MSG = ecore_x_atom_get("_XKEY_COMPOSITION");
636 xd->atomCBHMCount = ecore_x_atom_get("CBHM_cCOUNT");
637 xd->atomUTF8String = ecore_x_atom_get("UTF8_STRING");
641 void depose_xhandler(XHandlerData *xd)
643 ecore_event_handler_del(xd->xsel_clear_handler);
644 ecore_event_handler_del(xd->xsel_request_handler);
645 ecore_event_handler_del(xd->xsel_notify_handler);
646 ecore_event_handler_del(xd->xclient_msg_handler);
647 ecore_event_handler_del(xd->xfocus_out_handler);
648 ecore_event_handler_del(xd->xproperty_notify_handler);
649 ecore_event_handler_del(xd->xwindow_destroy_handler);
653 int get_active_window_degree(Ecore_X_Window active)
655 //ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE
658 unsigned char *prop_data = NULL;
660 int ret = ecore_x_window_prop_property_get(
661 active, ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
662 ECORE_X_ATOM_CARDINAL, 32, &prop_data, &count);
663 if (ret && prop_data) memcpy(&rotation, prop_data, sizeof(int));
664 if (prop_data) FREE(prop_data);