1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team.
23 */
24
25 /*
26 * GTK+ DirectFB backend
27 * Copyright (C) 2001-2002 convergence integrated media GmbH
28 * Copyright (C) 2002-2004 convergence GmbH
29 * Written by Denis Oliver Kropp <dok@convergence.de> and
30 * Sven Neumann <sven@convergence.de>
31 */
32
33 #include "config.h"
34
35 #include <string.h>
36
37 #include "gdkdirectfb.h"
38 #include "gdkprivate-directfb.h"
39
40 #include "gdkproperty.h"
41 #include "gdkselection.h"
42 #include "gdkprivate.h"
43 #include "gdkalias.h"
44
45
46 typedef struct _OwnerInfo OwnerInfo;
47
48 struct _OwnerInfo
49 {
50 GdkAtom selection;
51 GdkWindow *owner;
52 };
53
54 GSList *owner_list = NULL;
55
56 /* When a window is destroyed we check if it is the owner
57 * of any selections. This is somewhat inefficient, but
58 * owner_list is typically short, and it is a low memory,
59 * low code solution
60 */
61 void
_gdk_selection_window_destroyed(GdkWindow * window)62 _gdk_selection_window_destroyed (GdkWindow *window)
63 {
64 GSList *tmp_list = owner_list;
65
66 while (tmp_list)
67 {
68 OwnerInfo *info = tmp_list->data;
69
70 tmp_list = tmp_list->next;
71
72 if (info->owner == window)
73 {
74 owner_list = g_slist_remove (owner_list, info);
75 g_free (info);
76 }
77 }
78 }
79
80 gint
gdk_selection_owner_set_for_display(GdkDisplay * display,GdkWindow * owner,GdkAtom selection,guint32 time,gint send_event)81 gdk_selection_owner_set_for_display (GdkDisplay *display,
82 GdkWindow *owner,
83 GdkAtom selection,
84 guint32 time,
85 gint send_event)
86 {
87 GSList *tmp_list;
88 OwnerInfo *info;
89
90 tmp_list = owner_list;
91 while (tmp_list)
92 {
93 info = tmp_list->data;
94 if (info->selection == selection)
95 {
96 owner_list = g_slist_remove (owner_list, info);
97 g_free (info);
98 break;
99 }
100 tmp_list = tmp_list->next;
101 }
102
103 if (owner)
104 {
105 info = g_new (OwnerInfo, 1);
106 info->owner = owner;
107 info->selection = selection;
108
109 owner_list = g_slist_prepend (owner_list, info);
110 }
111
112 return TRUE;
113 }
114
115 GdkWindow *
gdk_selection_owner_get_for_display(GdkDisplay * display,GdkAtom selection)116 gdk_selection_owner_get_for_display (GdkDisplay *display,
117 GdkAtom selection)
118 {
119 OwnerInfo *info;
120 GSList *tmp_list;
121
122 tmp_list = owner_list;
123 while (tmp_list)
124 {
125 info = tmp_list->data;
126 if (info->selection == selection)
127 {
128 return info->owner;
129 }
130 tmp_list = tmp_list->next;
131 }
132 return NULL;
133 }
134
135 void
gdk_selection_convert(GdkWindow * requestor,GdkAtom selection,GdkAtom target,guint32 time)136 gdk_selection_convert (GdkWindow *requestor,
137 GdkAtom selection,
138 GdkAtom target,
139 guint32 time)
140 {
141 GdkEvent *event;
142 GdkWindow *owner;
143 GdkWindow *event_window;
144
145 owner = gdk_selection_owner_get (selection);
146
147 if (owner)
148 {
149 event_window = gdk_directfb_other_event_window (owner,
150 GDK_SELECTION_REQUEST);
151 if (event_window)
152 {
153 event = gdk_directfb_event_make (event_window,
154 GDK_SELECTION_REQUEST);
155 event->selection.requestor = GDK_WINDOW_DFB_ID (requestor);
156 event->selection.selection = selection;
157 event->selection.target = target;
158 event->selection.property = _gdk_selection_property;
159 }
160 }
161 else
162 {
163 /* If no owner for the specified selection exists, the X server
164 * generates a SelectionNotify event to the requestor with property None.
165 */
166 gdk_selection_send_notify (GDK_WINDOW_DFB_ID (requestor),
167 selection,
168 target,
169 GDK_NONE,
170 0);
171 }
172 }
173
174 gint
gdk_selection_property_get(GdkWindow * requestor,guchar ** data,GdkAtom * ret_type,gint * ret_format)175 gdk_selection_property_get (GdkWindow *requestor,
176 guchar **data,
177 GdkAtom *ret_type,
178 gint *ret_format)
179 {
180 guchar *t = NULL;
181 GdkAtom prop_type;
182 gint prop_format;
183 gint prop_len;
184
185 g_return_val_if_fail (requestor != NULL, 0);
186 g_return_val_if_fail (GDK_IS_WINDOW (requestor), 0);
187
188 if (!gdk_property_get (requestor,
189 _gdk_selection_property,
190 0/*AnyPropertyType?*/,
191 0, 0,
192 FALSE,
193 &prop_type, &prop_format, &prop_len,
194 &t))
195 {
196 *data = NULL;
197 return 0;
198 }
199
200 if (ret_type)
201 *ret_type = prop_type;
202 if (ret_format)
203 *ret_format = prop_format;
204
205 if (!gdk_property_get (requestor,
206 _gdk_selection_property,
207 0/*AnyPropertyType?*/,
208 0, prop_len + 1,
209 FALSE,
210 &prop_type, &prop_format, &prop_len,
211 &t))
212 {
213 *data = NULL;
214 return 0;
215 }
216
217 *data = t;
218
219 return prop_len;
220 }
221
222
223 void
gdk_selection_send_notify_for_display(GdkDisplay * display,guint32 requestor,GdkAtom selection,GdkAtom target,GdkAtom property,guint32 time)224 gdk_selection_send_notify_for_display (GdkDisplay *display,
225 guint32 requestor,
226 GdkAtom selection,
227 GdkAtom target,
228 GdkAtom property,
229 guint32 time)
230 {
231 GdkEvent *event;
232 GdkWindow *event_window;
233
234 event_window = gdk_window_lookup ((GdkNativeWindow) requestor);
235
236 if (!event_window)
237 return;
238
239 event_window = gdk_directfb_other_event_window (event_window,
240 GDK_SELECTION_NOTIFY);
241
242 if (event_window)
243 {
244 event = gdk_directfb_event_make (event_window, GDK_SELECTION_NOTIFY);
245 event->selection.selection = selection;
246 event->selection.target = target;
247 event->selection.property = property;
248 event->selection.requestor = (GdkNativeWindow) requestor;
249 }
250 }
251
252 gint
gdk_text_property_to_text_list_for_display(GdkDisplay * display,GdkAtom encoding,gint format,const guchar * text,gint length,gchar *** list)253 gdk_text_property_to_text_list_for_display (GdkDisplay *display,
254 GdkAtom encoding,
255 gint format,
256 const guchar *text,
257 gint length,
258 gchar ***list)
259 {
260 g_warning ("gdk_text_property_to_text_list() not implemented\n");
261 return 0;
262 }
263
264 void
gdk_free_text_list(gchar ** list)265 gdk_free_text_list (gchar **list)
266 {
267 g_return_if_fail (list != NULL);
268 g_warning ("gdk_free_text_list() not implemented\n");
269 }
270
271 gint
gdk_string_to_compound_text_for_display(GdkDisplay * display,const gchar * str,GdkAtom * encoding,gint * format,guchar ** ctext,gint * length)272 gdk_string_to_compound_text_for_display (GdkDisplay *display,
273 const gchar *str,
274 GdkAtom *encoding,
275 gint *format,
276 guchar **ctext,
277 gint *length)
278 {
279 g_warning ("gdk_string_to_compound_text() not implemented\n");
280 return 0;
281 }
282
283 void
gdk_free_compound_text(guchar * ctext)284 gdk_free_compound_text (guchar *ctext)
285 {
286 g_warning ("gdk_free_compound_text() not implemented\n");
287 }
288
289 /**
290 * gdk_utf8_to_string_target:
291 * @str: a UTF-8 string
292 *
293 * Convert an UTF-8 string into the best possible representation
294 * as a STRING. The representation of characters not in STRING
295 * is not specified; it may be as pseudo-escape sequences
296 * \x{ABCD}, or it may be in some other form of approximation.
297 *
298 * Return value: the newly allocated string, or %NULL if the
299 * conversion failed. (It should not fail for
300 * any properly formed UTF-8 string.)
301 **/
302 gchar *
gdk_utf8_to_string_target(const gchar * str)303 gdk_utf8_to_string_target (const gchar *str)
304 {
305 g_warning ("gdk_utf8_to_string_target() not implemented\n");
306 return 0;
307 }
308
309 /**
310 * gdk_utf8_to_compound_text:
311 * @str: a UTF-8 string
312 * @encoding: location to store resulting encoding
313 * @format: location to store format of the result
314 * @ctext: location to store the data of the result
315 * @length: location to store the length of the data
316 * stored in @ctext
317 *
318 * Convert from UTF-8 to compound text.
319 *
320 * Return value: %TRUE if the conversion succeeded, otherwise
321 * false.
322 **/
323 gboolean
gdk_utf8_to_compound_text_for_display(GdkDisplay * display,const gchar * str,GdkAtom * encoding,gint * format,guchar ** ctext,gint * length)324 gdk_utf8_to_compound_text_for_display (GdkDisplay *display,
325 const gchar *str,
326 GdkAtom *encoding,
327 gint *format,
328 guchar **ctext,
329 gint *length)
330 {
331 g_warning ("gdk_utf8_to_compound_text() not implemented\n");
332 return 0;
333 }
334
335 static gint
make_list(const gchar * text,gint length,gboolean latin1,gchar *** list)336 make_list (const gchar *text,
337 gint length,
338 gboolean latin1,
339 gchar ***list)
340 {
341 GSList *strings = NULL;
342 gint n_strings = 0;
343 gint i;
344 const gchar *p = text;
345 const gchar *q;
346 GSList *tmp_list;
347 GError *error = NULL;
348
349 while (p < text + length)
350 {
351 gchar *str;
352
353 q = p;
354 while (*q && q < text + length)
355 q++;
356
357 if (latin1)
358 {
359 str = g_convert (p, q - p,
360 "UTF-8", "ISO-8859-1",
361 NULL, NULL, &error);
362
363 if (!str)
364 {
365 g_warning ("Error converting selection from STRING: %s",
366 error->message);
367 g_error_free (error);
368 }
369 }
370 else
371 str = g_strndup (p, q - p);
372
373 if (str)
374 {
375 strings = g_slist_prepend (strings, str);
376 n_strings++;
377 }
378
379 p = q + 1;
380 }
381
382 if (list)
383 *list = g_new (gchar *, n_strings + 1);
384
385 (*list)[n_strings] = NULL;
386
387 i = n_strings;
388 tmp_list = strings;
389 while (tmp_list)
390 {
391 if (list)
392 (*list)[--i] = tmp_list->data;
393 else
394 g_free (tmp_list->data);
395
396 tmp_list = tmp_list->next;
397 }
398
399 g_slist_free (strings);
400
401 return n_strings;
402 }
403
404
405 /**
406 * gdk_text_property_to_utf8_list:
407 * @encoding: an atom representing the encoding of the text
408 * @format: the format of the property
409 * @text: the text to convert
410 * @length: the length of @text, in bytes
411 * @list: location to store the list of strings or %NULL. The
412 * list should be freed with g_strfreev().
413 *
414 * Convert a text property in the giving encoding to
415 * a list of UTF-8 strings.
416 *
417 * Return value: the number of strings in the resulting
418 * list.
419 **/
420 gint
gdk_text_property_to_utf8_list_for_display(GdkDisplay * display,GdkAtom encoding,gint format,const guchar * text,gint length,gchar *** list)421 gdk_text_property_to_utf8_list_for_display (GdkDisplay *display,
422 GdkAtom encoding,
423 gint format,
424 const guchar *text,
425 gint length,
426 gchar ***list)
427 {
428 g_return_val_if_fail (text != NULL, 0);
429 g_return_val_if_fail (length >= 0, 0);
430
431 if (encoding == GDK_TARGET_STRING)
432 {
433 return make_list ((gchar *)text, length, TRUE, list);
434 }
435 else if (encoding == gdk_atom_intern ("UTF8_STRING", FALSE))
436 {
437 return make_list ((gchar *)text, length, FALSE, list);
438 }
439 else
440 {
441 gchar **local_list;
442 gint local_count;
443 gint i;
444 const gchar *charset = NULL;
445 gboolean need_conversion = !g_get_charset (&charset);
446 gint count = 0;
447 GError *error = NULL;
448
449 /* Probably COMPOUND text, we fall back to Xlib routines
450 */
451 local_count = gdk_text_property_to_text_list (encoding,
452 format,
453 text,
454 length,
455 &local_list);
456 if (list)
457 *list = g_new (gchar *, local_count + 1);
458
459 for (i = 0; i < local_count; i++)
460 {
461 /* list contains stuff in our default encoding
462 */
463 if (need_conversion)
464 {
465 gchar *utf = g_convert (local_list[i], -1,
466 "UTF-8", charset,
467 NULL, NULL, &error);
468 if (utf)
469 {
470 if (list)
471 (*list)[count++] = utf;
472 else
473 g_free (utf);
474 }
475 else
476 {
477 g_warning ("Error converting to UTF-8 from '%s': %s",
478 charset, error->message);
479 g_error_free (error);
480 error = NULL;
481 }
482 }
483 else
484 {
485 if (list)
486 (*list)[count++] = g_strdup (local_list[i]);
487 }
488 }
489
490 gdk_free_text_list (local_list);
491 (*list)[count] = NULL;
492
493 return count;
494 }
495 }
496
497 #define __GDK_SELECTION_X11_C__
498 #include "gdkaliasdef.c"
499