change global variable position
[framework/uifw/cbhm.git] / src / xcnphandler.c
1 #include "common.h"
2 #include "cbhm_main.h"
3 #include "xcnphandler.h"
4 #include "storage.h"
5 #include "clipdrawer.h"
6 #include "scrcapture.h"
7
8 static Ecore_Event_Handler *xsel_clear_handler = NULL;
9 static Ecore_Event_Handler *xsel_request_handler = NULL;
10 static Ecore_Event_Handler *xsel_notify_handler = NULL;
11 static Ecore_Event_Handler *xclient_msg_handler = NULL;
12 static Ecore_Event_Handler *xfocus_out_handler = NULL;
13
14 char *g_lastest_content = NULL;
15 int g_history_pos = 0;
16
17 int xcnp_init(void *data)
18 {
19         struct appdata *ad = data;
20         DTRACE("xcnp_init().. start!\n");
21
22         if(!_cbhm_init(ad))
23         {
24                 DTRACE("Failed - _cbhm_init()..!\n");
25                 return NULL;
26         }
27
28         //Adding Event Handlers
29         xsel_clear_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR, _xsel_clear_cb, ad);
30         xsel_request_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_REQUEST, _xsel_request_cb, ad);
31         xsel_notify_handler = ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY, _xsel_notify_cb, ad);
32         xclient_msg_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _xclient_msg_cb, ad);
33         xfocus_out_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, _xfocus_out_cb, ad);
34
35         if(!xsel_clear_handler)
36                 DTRACE("Failed to add ECORE_X_EVENT_SELECTION_CLEAR handler\n");
37         if(!xsel_request_handler)
38                 DTRACE("Failed to add ECORE_X_EVENT_SELECTION_REQUEST handler\n");
39         if(!xsel_notify_handler)
40                 DTRACE("Failed to add ECORE_X_EVENT_SELECTION_NOTIFY handler\n");
41         if(!xclient_msg_handler)
42                 DTRACE("Failed to add ECORE_X_EVENT_CLIENT_MESSAGE handler\n");
43         if(!xfocus_out_handler)
44                 DTRACE("Failed to add ECORE_X_EVENT_WINDOW_FOCUS_OUT handler\n");
45
46         return TRUE;
47 }
48
49 int xcnp_shutdown()
50 {
51         //Removing Event Handlers
52         ecore_event_handler_del(xsel_clear_handler);
53         ecore_event_handler_del(xsel_request_handler);
54         ecore_event_handler_del(xsel_notify_handler);
55         ecore_event_handler_del(xclient_msg_handler);
56         ecore_event_handler_del(xfocus_out_handler);
57
58         xsel_clear_handler = NULL;
59         xsel_request_handler = NULL;
60         xsel_notify_handler = NULL;
61         xclient_msg_handler = NULL;
62         xfocus_out_handler = NULL;
63
64         _cbhm_fini();
65
66         return TRUE;
67 }
68
69 static int _init_atoms()
70 {
71         /* all atoms are global variables */
72         atomPrimary = XA_PRIMARY; 
73         atomSecondary = XA_SECONDARY; 
74 //      atomTarget = XA_STRING;
75         atomClipboard = XInternAtom(g_disp, ATOM_CLIPBOARD_NAME, False);
76         atomCBHM = XInternAtom (g_disp, ATOM_CLIPBOARD_MANAGER_NAME, False);
77         atomCBOut = XInternAtom(g_disp, ATOM_CBHM_OUTBUF, False);
78         atomInc = XInternAtom(g_disp, "INCR", False);
79         atomTargets = XInternAtom(g_disp, "TARGETS", False);
80         atomUTF8String = XInternAtom(g_disp, "UTF8_STRING", False);
81         atomHtmltext = XInternAtom(g_disp, "text/html;charset=utf-8", False);
82
83         return TRUE;
84 }
85
86 static void _set_cbhmwin_prop()
87 {
88         Atom atomCbhmWin = XInternAtom(g_disp, "CBHM_XWIN", False);
89         XChangeProperty(g_disp, g_rootwin, atomCbhmWin, XA_WINDOW, 
90                                         32, PropModeReplace,
91                                         (unsigned char *)&g_evtwin, (int) 1);
92 }
93
94 int increment_current_history_position()
95 {
96         int pos = g_history_pos+1;
97         if (pos >= HISTORY_QUEUE_MAX_ITEMS)
98                 pos = 0;
99         g_history_pos = pos;
100         return pos;
101 }
102
103 int get_current_history_position()
104 {
105         int pos = g_history_pos-1;
106         if (pos < 0)
107                 pos = HISTORY_QUEUE_MAX_ITEMS-1;
108         
109         return pos;
110 }
111
112 int add_to_storage_buffer(void *data, char *src, int len)
113 {
114         struct appdata *ad = data;
115
116         if (len <= 0)
117                 return -1;
118
119         if (g_lastest_content != NULL)
120                 free(g_lastest_content);
121         g_lastest_content = malloc(sizeof(char)*(len+1));
122         if (g_history_pos >= HISTORY_QUEUE_MAX_ITEMS)
123                 g_history_pos = 0;
124
125         // FIXME: remove g_lasteset_content
126         memcpy(g_lastest_content, src, len);
127         g_lastest_content[len] = '\0';
128         adding_item_to_storage(ad, g_history_pos, g_lastest_content);
129         increment_current_history_position();
130
131         int nserial = 0;
132         nserial = get_storage_serial_code(ad);
133         Atom atomCbhmSerial = XInternAtom(g_disp, "CBHM_SERIAL_NUMBER", False);
134         XChangeProperty(g_disp, g_evtwin, atomCbhmSerial, XA_INTEGER,
135                                         32, PropModeReplace,
136                                         (unsigned char *)&nserial, (int) 1);
137         XFlush(g_disp);
138
139         return 0;
140 }
141
142 int print_storage_buffer(void *data)
143 {
144         struct appdata *ad = data;
145
146         int pos;
147         int i = 0;
148         for (i = 0; i < HISTORY_QUEUE_MAX_ITEMS; i++)
149         {
150                 pos = get_current_history_position()+i;
151                 if (pos > HISTORY_QUEUE_MAX_ITEMS-1)
152                         pos = pos-HISTORY_QUEUE_MAX_ITEMS;
153                 DTRACE("%d: %s\n", i, 
154                            clipdrawer_get_item_data(ad, pos) != NULL ? clipdrawer_get_item_data(ad, pos) : "NULL");
155         }
156 }
157
158 int send_convert_selection()
159 {
160         XConvertSelection(g_disp, atomClipboard, atomUTF8String, atomCBOut, g_evtwin, CurrentTime);
161         DTRACE("sent convert selection\n");
162         return 0;
163 }
164
165 int set_clipboard_manager_owner()
166 {
167         XSetSelectionOwner(g_disp, atomCBHM, g_evtwin, CurrentTime);
168         Ecore_X_Window selowner_window = XGetSelectionOwner(g_disp, atomCBHM);
169         DTRACE("g_evtwin = 0x%x, setted clipboard manager owner is = 0x%x\n", g_evtwin, selowner_window);
170         return 0;
171 }
172
173 int set_selection_owner()
174 {
175         XSetSelectionOwner(g_disp, atomClipboard, g_evtwin, CurrentTime);
176         Ecore_X_Window selowner_window = XGetSelectionOwner(g_disp, atomClipboard);
177         DTRACE("evtwin = 0x%x, setted selection owner is = 0x%x\n", g_evtwin, selowner_window);
178         return 0;
179 }
180
181 int get_selection_content(void *data)
182 {
183         Atom cbtype;
184         int cbformat;
185         unsigned long cbsize, cbitems;
186         unsigned char *cbbuf;
187         struct appdata *ad = data;
188         const char *unesc;
189         size_t unesc_len = 0;
190         int i;
191
192         XGetWindowProperty(g_disp, g_evtwin, atomCBOut, 0, 0, False,
193                                            AnyPropertyType, &cbtype, &cbformat, &cbitems, &cbsize, &cbbuf);
194         XFree(cbbuf);
195
196         if (cbtype == atomInc)
197         {
198                 XDeleteProperty(g_disp, g_evtwin, atomCBOut);
199                 XFlush(g_disp);
200                 DTRACE("INCR \n");
201                 return -1;
202         }
203
204         DTRACE("cbsize = %d\n", cbsize);
205
206         if (cbformat != 8)
207         {
208                 DTRACE("There're nothing to read = %d\n", cbformat);
209                 return -2;
210         }
211
212         XGetWindowProperty(g_disp, g_evtwin, atomCBOut, 0, (long) cbsize, False,
213                                            AnyPropertyType, &cbtype, &cbformat, &cbitems, &cbsize, &cbbuf);
214         XDeleteProperty(g_disp, g_evtwin, atomCBOut);
215
216 #define _NORMAL
217 #ifdef _NORMAL
218         unesc = clipdrawer_get_plain_string_from_escaped(cbbuf);
219         if (unesc != NULL)
220         {
221                 unesc_len = strlen(unesc);
222                 // FIXME: invent more clever way to right trim the string
223                 for (i = unesc_len-1; i > 0; i--)
224                 {
225                         // avoid control characters
226                         if (unesc[i] >= 0x01 && unesc[i] <= 0x1F)
227                                 continue;
228                         else
229                         {
230                                 DTRACE("before right trim len = %d\n", unesc_len);
231                                 unesc_len = i+1;
232                                 DTRACE("after right trim len = %d\n", unesc_len);
233                                 break;
234                         }
235                 }
236         }
237         else
238                 unesc_len = 0;
239
240 #endif
241
242 #ifdef _DEMO
243         DTRACE("len = %ld, data = %s\n", cbitems, cbbuf);
244
245         if (cbbuf != NULL)
246         {
247                 unesc_len = strlen(cbbuf);
248                 // FIXME: invent more clever way to right trim the string
249                 for (i = unesc_len-1; i > 0; i--)
250                 {
251                         // avoid control characters
252                         if (cbbuf[i] >= 0x01 && cbbuf[i] <= 0x1F)
253                                 continue;
254                         else
255                         {
256                                 DTRACE("before right trim len = %d\n", unesc_len);
257                                 unesc_len = i+1;
258                                 DTRACE("after right trim len = %d\n", unesc_len);
259                                 break;
260                         }
261                 }
262         }
263         else
264                 unesc_len = 0;
265
266         if (!strncmp(cbbuf, "file://", 7) && 
267                 (strcasestr(cbbuf,".png") || strcasestr(cbbuf,".jpg") || strcasestr(cbbuf,".bmp")) &&
268                 check_regular_file(cbbuf+7))
269         {
270                 DTRACE("clipdrawer add path = %s\n", cbbuf+7);
271                 clipdrawer_add_item(ad, cbbuf+7, GI_IMAGE);
272         }
273         else
274         {
275                 add_to_storage_buffer(ad, cbbuf, unesc_len);
276                 clipdrawer_add_item(ad, cbbuf, GI_TEXT);
277         }
278         DTRACE("len = %ld, data = %s\n", unesc_len, cbbuf);
279 #endif
280
281 #ifdef _NORMAL
282         /* FIXME : it needs two verification. 
283                1. does the file exist?
284                2. dose the file wanted type? */
285         if (!strncmp(unesc, "file://", 7) && 
286                 (strcasestr(unesc,".png") || strcasestr(unesc,".jpg") || strcasestr(unesc,".bmp")) &&
287                 check_regular_file(unesc+7))
288         {
289                 DTRACE("clipdrawer add path = %s\n", unesc+7);
290                 clipdrawer_add_item(unesc+7, GI_IMAGE);
291         }
292         else
293         {
294                 DTRACE("clipdrawer add string = %s\n", unesc);
295                 add_to_storage_buffer(ad, unesc, unesc_len);
296                 clipdrawer_add_item(unesc, GI_TEXT);
297         }
298         DTRACE("len = %ld, data = %s\n", unesc_len, unesc);
299         free(unesc);
300 #endif
301
302         DTRACE("\n");
303         print_storage_buffer(ad);
304         DTRACE("\n");
305
306         XFree(cbbuf);
307
308         return 0;
309 }
310
311 int processing_selection_request(Ecore_X_Event_Selection_Request *ev)
312 {
313         XEvent req_evt;
314         int req_size;
315         Ecore_X_Window req_win;
316         Atom req_atom;
317
318         req_size = XExtendedMaxRequestSize(g_disp) / 4;
319         if (!req_size)
320         {
321                 req_size = XMaxRequestSize(g_disp) / 4;
322         }
323
324     req_win = ev->requestor;
325         req_atom = ev->property;
326
327         DTRACE("## wanted target = %d\n", ev->target);
328         DTRACE("## wanted target = %s\n", XGetAtomName(g_disp, ev->target));
329         DTRACE("## req target atom name = %s\n", XGetAtomName(g_disp, ev->target));
330
331         /* TODO : if there are request which cbhm doesn't understand,
332            then reply None property to requestor */
333         /* TODO : add image type */
334         if (ev->target == atomTargets) 
335         {
336 //        Atom types[2] = { atomTargets, atomUTF8String };
337         Atom types[3] = { atomTargets, atomUTF8String, atomHtmltext };
338
339         // send all (not using INCR) 
340         XChangeProperty(g_disp, req_win, req_atom, XA_ATOM,
341                                                 32, PropModeReplace, (unsigned char *) types,
342                                                 (int) (sizeof(types) / sizeof(Atom)));
343                 DTRACE("target matched\n");
344     }
345     else
346         {
347                 DTRACE("target mismatched. trying to txt\n");
348
349                 int txt_len;
350                 if (g_lastest_content != NULL)
351                         txt_len = strlen(g_lastest_content);
352                 else
353                         txt_len = 0;
354
355                 if (txt_len > req_size) 
356                 {
357                         // INCR 
358                 }
359                 else 
360                 {
361                         // send all (not using INCR) 
362                         XChangeProperty(g_disp, req_win, req_atom, atomUTF8String, 
363                                                         8, PropModeReplace, (unsigned char *) g_lastest_content, (int) txt_len);
364                 }
365                 DTRACE("txt target, len = %d\n", txt_len);
366                 if (txt_len > 0 && g_lastest_content != NULL)
367                         DTRACE("txt target, content = %s\n", g_lastest_content);
368         }
369
370 /*
371         DTRACE("wanted window = 0x%x\n", req_win);
372         DTRACE("wanted target = %s\n", XGetAtomName(g_disp, ev->target));
373 */
374         DTRACE("selection target = %s\n", XGetAtomName(g_disp, ev->selection));
375         DTRACE("getted atom name = %s\n", XGetAtomName(g_disp, req_atom));
376         DTRACE("req target atom name = %s\n", XGetAtomName(g_disp, ev->target));
377
378     req_evt.xselection.property = req_atom;
379     req_evt.xselection.type = SelectionNotify;
380     req_evt.xselection.display = g_disp;
381     req_evt.xselection.requestor = req_win;
382     req_evt.xselection.selection = ev->selection;
383     req_evt.xselection.target = ev->target;
384     req_evt.xselection.time = ev->time;
385
386     XSendEvent(g_disp, ev->requestor, 0, 0, &req_evt);
387     XFlush(g_disp);
388
389         return 0;
390 }
391
392 static int _cbhm_init(void *data)
393 {
394         struct appdata *ad = data;
395         //Set default data structure
396         //Control that the libraries are properly initialized
397         if (!ecore_init()) return EXIT_FAILURE;
398         if (!ecore_evas_init()) return EXIT_FAILURE;
399         if (!edje_init()) return EXIT_FAILURE;
400
401         // do not x init in this module, it disconnect previous e17's X connection
402         //ecore_x_init(NULL);
403
404         g_disp = ecore_x_display_get();
405
406         if( !g_disp )
407         {
408                 DTRACE("Failed to get display\n");
409                 return -1;
410         }
411
412         g_rootwin = DefaultRootWindow(g_disp);
413         g_evtwin = ecore_x_window_new(g_rootwin, 0, 0, 19, 19);
414         ecore_x_netwm_name_set(g_evtwin, CLIPBOARD_MANAGER_WINDOW_TITLE_STRING);
415
416         XSelectInput(g_disp, g_evtwin, PropertyChangeMask);
417         XSelectInput(g_disp, g_rootwin, StructureNotifyMask);
418 //      ecore_x_window_show(g_evtwin);
419         ecore_x_flush();
420
421         _set_cbhmwin_prop();
422     _init_atoms();
423         init_storage(ad);
424
425         DTRACE("_cbhm_init ok\n");
426
427         set_clipboard_manager_owner();
428         send_convert_selection();
429         set_selection_owner();
430
431         return TRUE;
432 }
433
434 static void _cbhm_fini()
435 {
436         struct appdata *ad = g_get_main_appdata();
437
438         close_storage(ad);
439
440         return;
441 }
442
443 static int _xsel_clear_cb(void *data, int ev_type, void *event)
444 {
445         struct appdata *ad = data;
446
447         Ecore_X_Event_Selection_Clear *ev = (Ecore_X_Event_Selection_Clear *)event;
448
449         if (ev->selection != ECORE_X_SELECTION_CLIPBOARD)
450                 return TRUE;
451         
452         DTRACE("XE:SelectionClear\n");
453
454         send_convert_selection();
455         ecore_x_flush();
456         /* TODO : set selection request is should after convert selection
457          * is done */
458         set_selection_owner();
459
460         return TRUE;
461 }
462
463 static int _xsel_request_cb(void *data, int ev_type, void *event)
464 {
465         Ecore_X_Event_Selection_Request *ev = (Ecore_X_Event_Selection_Request *)event;
466
467         if (ev->selection != atomClipboard)
468                 return TRUE;
469
470         DTRACE("XE:SelectionRequest\n");
471
472         processing_selection_request(ev);
473
474         return TRUE;
475 }
476
477 static int _xsel_notify_cb(void *data, int ev_type, void *event)
478 {
479         struct appdata *ad = data;
480
481         Ecore_X_Event_Selection_Notify *ev = (Ecore_X_Event_Selection_Notify *)event;
482         Ecore_X_Selection_Data_Text *text_data = NULL;
483
484         if (ev->selection != ECORE_X_SELECTION_CLIPBOARD)
485                 return TRUE;
486         
487         DTRACE("XE:SelectionNotify\n");
488
489         text_data = ev->data;
490         DTRACE("content type = %d\n", text_data->data.content);
491         get_selection_content(ad);
492
493         if (text_data->data.content != ECORE_X_SELECTION_CONTENT_TEXT)
494         {
495                 DTRACE("content isn't text\n");
496         }
497
498         return TRUE;
499 }
500
501 static int _xclient_msg_cb(void *data, int ev_type, void *event)
502 {
503         struct appdata *ad = data;
504
505         Ecore_X_Event_Client_Message *ev = (Ecore_X_Event_Client_Message*)event;
506
507         Atom atomCBHM_MSG = XInternAtom(g_disp, "CBHM_MSG", False);
508         Atom atomCBHM_cRAW = XInternAtom(g_disp, "CBHM_cRAW", False);
509         Atom atomXKey_MSG = XInternAtom(g_disp, "_XKEY_COMPOSITION", False);
510         char atomname[10];
511         Atom cbhm_atoms[HISTORY_QUEUE_MAX_ITEMS];
512         Ecore_X_Window reqwin = ev->win;
513         int i, pos;
514
515         if (ev->message_type == atomXKey_MSG)
516         {
517                 DTRACE("XE:ClientMessage for Screen capture\n");
518
519                 capture_current_screen(ad);
520
521                 return TRUE;
522         }
523
524         if (ev->message_type != atomCBHM_MSG)
525                 return -1;
526
527         DTRACE("XE:ClientMessage for CBHM\n");
528
529         DTRACE("## %s\n", ev->data.b);
530
531         if (strcmp("get count", ev->data.b) == 0)
532         {
533                 int icount = get_item_counts(ad);
534                 char countbuf[10];
535                 DTRACE("## cbhm count : %d\n", icount);
536                 sprintf(countbuf, "%d", icount);
537                 sprintf(atomname, "CBHM_cCOUNT");
538                 cbhm_atoms[0] = XInternAtom(g_disp, atomname, False);
539                 XChangeProperty(g_disp, reqwin, cbhm_atoms[0], atomUTF8String, 
540                                                 8, PropModeReplace, 
541                                                 (unsigned char *) countbuf, 
542                                                 (int) strlen(countbuf));
543         
544         }
545         else if (strncmp("get #", ev->data.b, 5) == 0)
546         {
547                 // FIXME : handle greater than 9
548                 int num = ev->data.b[5] - '0';
549                 int cur = get_current_history_position();
550                 num = cur + num - 1;
551                 if (num > HISTORY_QUEUE_MAX_ITEMS-1)
552                         num = num-HISTORY_QUEUE_MAX_ITEMS;
553
554                 if (num >= 0 && num < HISTORY_QUEUE_MAX_ITEMS)
555                 {
556                         DTRACE("## pos : #%d\n", num);
557                         // FIXME : handle with correct atom
558                         sprintf(atomname, "CBHM_c%d", num);
559                         cbhm_atoms[0] = XInternAtom(g_disp, atomname, False);
560                         if (clipdrawer_get_item_data(ad, num) != NULL)
561                         {
562                                 XChangeProperty(g_disp, reqwin, cbhm_atoms[0], atomUTF8String, 
563                                                                 8, PropModeReplace, 
564                                                                 (unsigned char *) clipdrawer_get_item_data(ad, num), 
565                                                                 (int) strlen(clipdrawer_get_item_data(ad, num)));
566                         }
567                 }
568         }
569         else if (strcmp("get all", ev->data.b) == 0)
570         {
571 //              print_history_buffer();
572                 pos = get_current_history_position();
573                 for (i = 0; i < 5; i++)
574                 {
575                         DTRACE("## %d -> %d\n", i, pos);
576                         sprintf(atomname, "CBHM_c%d", i);
577                         cbhm_atoms[i] = XInternAtom(g_disp, atomname, False);
578                         if (clipdrawer_get_item_data(ad, pos) != NULL)
579                         {
580                                 XChangeProperty(g_disp, reqwin, cbhm_atoms[i], atomUTF8String, 
581                                                                 8, PropModeReplace, 
582                                                                 (unsigned char *) clipdrawer_get_item_data(ad, pos),
583                                                                 (int) strlen(clipdrawer_get_item_data(ad, pos)));
584                         }
585                         pos--;
586                         if (pos < 0)
587                                 pos = HISTORY_QUEUE_MAX_ITEMS-1;
588                 }
589         }
590         else if (strcmp("get raw", ev->data.b) == 0)
591         {
592 /*
593                 if (get_storage_start_addr != NULL)
594                 {
595                         XChangeProperty(g_disp, reqwin, atomCBHM_cRAW, atomUTF8String, 
596                                                         8, PropModeReplace, 
597                                                         (unsigned char *) get_storage_start_addr(),
598                                                         (int) get_total_storage_size());
599                 }
600 */
601         }
602         else if (strncmp("show", ev->data.b, 4) == 0)
603         {
604                 if (ev->data.b[4] != NULL && ev->data.b[4] == '1')
605                         clipdrawer_paste_textonly_set(ad, EINA_FALSE);
606                 else
607                         clipdrawer_paste_textonly_set(ad, EINA_TRUE);
608
609                 clipdrawer_activate_view(ad);
610         }
611
612         XFlush(g_disp);
613
614         return TRUE;
615 }
616
617 static int _xfocus_out_cb(void *data, int ev_type, void *event)
618 {
619         struct appdata *ad = data;
620
621         DTRACE("XE:FOCUS OUT\n");
622
623         clipdrawer_lower_view(ad);
624
625         return TRUE;
626 }
627
628 void set_transient_for(void *data)
629 {
630         struct appdata *ad = data;
631
632         Ecore_X_Window xwin_active = None;
633         Atom atomActive = XInternAtom(g_disp, "_NET_ACTIVE_WINDOW", False);
634
635         if (ecore_x_window_prop_window_get(DefaultRootWindow(g_disp), 
636                                                                            atomActive, &xwin_active, 1) != -1)
637         {
638                 ecore_x_icccm_transient_for_set (elm_win_xwindow_get(ad->win_main), xwin_active);
639                 DTRACE("Success to set transient_for active window = 0x%X\n", xwin_active);
640         }
641         else
642         {
643                 DTRACE("Failed to find active window for transient_for\n");
644         }
645 }
646
647 void unset_transient_for(void *data)
648 {
649         struct appdata *ad = data;
650
651         ecore_x_icccm_transient_for_unset(elm_win_xwindow_get(ad->win_main));
652 }
653
654 static Ecore_X_Window get_selection_secondary_target_win()
655 {
656         Atom actual_type;
657         int actual_format;
658         unsigned long nitems, bytes_after;
659         unsigned char *prop_return = NULL;
660         Atom atomCbhmXTarget = XInternAtom(g_disp, "CBHM_XTARGET", False);
661         static Ecore_X_Window xtarget = None;
662         if (xtarget != None)
663                 return xtarget;
664
665         if(Success == 
666            XGetWindowProperty(g_disp, DefaultRootWindow(g_disp), atomCbhmXTarget, 
667                                                   0, sizeof(Ecore_X_Window), False, XA_WINDOW, 
668                                                   &actual_type, &actual_format, &nitems, &bytes_after, &prop_return) && 
669            prop_return)
670         {
671                 xtarget = *(Ecore_X_Window*)prop_return;
672                 XFree(prop_return);
673                 fprintf(stderr, "## find clipboard secondary target at root\n");
674         }
675         return xtarget;
676 }
677
678 int set_selection_secondary_data(char *sdata)
679 {
680         Ecore_X_Window setwin = get_selection_secondary_target_win();
681         if (setwin == None)
682                 return 0;
683
684         if (sdata == NULL)
685                 return 0;
686
687         int slen = strlen(sdata);
688
689         fprintf(stderr, "## cbhm xwin = 0x%x, d = %s\n", setwin, sdata);
690
691         ecore_x_selection_secondary_set(setwin, sdata, slen);
692 }