1 /* util header */
2 /* vim: set sw=2 et: */
3
4 /*
5 * Copyright (C) 2001 Havoc Pennington
6 * Copyright (C) 2006-2007 Vincent Untz
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #undef WNCK_DISABLE_DEPRECATED
25
26 #include <config.h>
27
28 #include <glib/gi18n-lib.h>
29 #include "util.h"
30 #include "xutils.h"
31 #include "private.h"
32 #include "inlinepixbufs.h"
33 #include <gdk/gdkx.h>
34 #include <string.h>
35 #ifdef HAVE_XRES
36 #include <X11/extensions/XRes.h>
37 #endif
38
39 /**
40 * SECTION:resource
41 * @short_description: reading resource usage of X clients.
42 * @see_also: wnck_window_get_xid(), wnck_application_get_xid(), wnck_window_get_pid(), wnck_application_get_pid()
43 * @stability: Unstable
44 *
45 * libwnck provides an easy-to-use interface to the XRes X server extension to
46 * read resource usage of X clients, which can be defined either by the X
47 * window ID of one of their windows or by the process ID of their process.
48 */
49
50 /**
51 * SECTION:misc
52 * @short_description: other additional features.
53 * @stability: Unstable
54 *
55 * These functions are utility functions providing some additional features to
56 * libwcnk users.
57 */
58
59 /**
60 * wnck_gtk_window_set_dock_type:
61 * @window: a <classname>GtkWindow</classname>.
62 *
63 * Sets the semantic type of @window to %WNCK_WINDOW_DOCK.
64 *
65 * Deprecated:2.20: Use gdk_window_set_type_hint() instead.
66 */
67 void
wnck_gtk_window_set_dock_type(GtkWindow * window)68 wnck_gtk_window_set_dock_type (GtkWindow *window)
69 {
70 g_return_if_fail (GTK_IS_WINDOW (window));
71
72 gdk_window_set_type_hint (gtk_widget_get_window (GTK_WIDGET (window)),
73 GDK_WINDOW_TYPE_HINT_DOCK);
74 }
75
76 typedef enum
77 {
78 WNCK_EXT_UNKNOWN = 0,
79 WNCK_EXT_FOUND = 1,
80 WNCK_EXT_MISSING = 2
81 } WnckExtStatus;
82
83
84 #if 0
85 /* useful for debugging */
86 static void
87 _wnck_print_resource_usage (WnckResourceUsage *usage)
88 {
89 if (!usage)
90 return;
91
92 g_print ("\twindows : %d\n"
93 "\tGCs : %d\n"
94 "\tfonts : %d\n"
95 "\tpixmaps : %d\n"
96 "\tpictures : %d\n"
97 "\tglyphsets : %d\n"
98 "\tcolormaps : %d\n"
99 "\tpassive grabs : %d\n"
100 "\tcursors : %d\n"
101 "\tunknowns : %d\n"
102 "\tpixmap bytes : %ld\n"
103 "\ttotal bytes : ~%ld\n",
104 usage->n_windows,
105 usage->n_gcs,
106 usage->n_fonts,
107 usage->n_pixmaps,
108 usage->n_pictures,
109 usage->n_glyphsets,
110 usage->n_colormap_entries,
111 usage->n_passive_grabs,
112 usage->n_cursors,
113 usage->n_other,
114 usage->pixmap_bytes,
115 usage->total_bytes_estimate);
116 }
117 #endif
118
119 static WnckExtStatus
wnck_init_resource_usage(GdkDisplay * gdisplay)120 wnck_init_resource_usage (GdkDisplay *gdisplay)
121 {
122 int event, error;
123 Display *xdisplay;
124 WnckExtStatus status;
125
126 xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
127
128 status = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (gdisplay),
129 "wnck-xres-status"));
130
131 if (status == WNCK_EXT_UNKNOWN)
132 {
133 #ifdef HAVE_XRES
134 if (!XResQueryExtension (xdisplay, &event, &error))
135 status = WNCK_EXT_MISSING;
136 else
137 status = WNCK_EXT_FOUND;
138 #else
139 status = WNCK_EXT_MISSING;
140 #endif
141
142 g_object_set_data (G_OBJECT (gdisplay),
143 "wnck-xres-status",
144 GINT_TO_POINTER (status));
145 }
146
147 g_assert (status != WNCK_EXT_UNKNOWN);
148
149 return status;
150 }
151
152 /**
153 * wnck_xid_read_resource_usage:
154 * @gdk_display: a <classname>GdkDisplay</classname>.
155 * @xid: an X window ID.
156 * @usage: return location for the X resource usage of the application owning
157 * the X window ID @xid.
158 *
159 * Looks for the X resource usage of the application owning the X window ID
160 * @xid on display @gdisplay. If no resource usage can be found, then all
161 * fields of @usage are set to 0.
162 *
163 * To properly work, this function requires the XRes extension on the X server.
164 *
165 * Since: 2.6
166 */
167 void
wnck_xid_read_resource_usage(GdkDisplay * gdisplay,gulong xid,WnckResourceUsage * usage)168 wnck_xid_read_resource_usage (GdkDisplay *gdisplay,
169 gulong xid,
170 WnckResourceUsage *usage)
171 {
172 g_return_if_fail (usage != NULL);
173
174 memset (usage, '\0', sizeof (*usage));
175
176 if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING)
177 return;
178
179 #ifdef HAVE_XRES
180 {
181 Display *xdisplay;
182 XResType *types;
183 int n_types;
184 unsigned long pixmap_bytes;
185 int i;
186 Atom pixmap_atom;
187 Atom window_atom;
188 Atom gc_atom;
189 Atom picture_atom;
190 Atom glyphset_atom;
191 Atom font_atom;
192 Atom colormap_entry_atom;
193 Atom passive_grab_atom;
194 Atom cursor_atom;
195
196 types = NULL;
197 n_types = 0;
198 pixmap_bytes = 0;
199
200 _wnck_error_trap_push ();
201
202 xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
203
204 XResQueryClientResources (xdisplay,
205 xid, &n_types,
206 &types);
207
208 XResQueryClientPixmapBytes (xdisplay,
209 xid, &pixmap_bytes);
210 _wnck_error_trap_pop ();
211
212 usage->pixmap_bytes = pixmap_bytes;
213
214 pixmap_atom = _wnck_atom_get ("PIXMAP");
215 window_atom = _wnck_atom_get ("WINDOW");
216 gc_atom = _wnck_atom_get ("GC");
217 font_atom = _wnck_atom_get ("FONT");
218 glyphset_atom = _wnck_atom_get ("GLYPHSET");
219 picture_atom = _wnck_atom_get ("PICTURE");
220 colormap_entry_atom = _wnck_atom_get ("COLORMAP ENTRY");
221 passive_grab_atom = _wnck_atom_get ("PASSIVE GRAB");
222 cursor_atom = _wnck_atom_get ("CURSOR");
223
224 i = 0;
225 while (i < n_types)
226 {
227 int t = types[i].resource_type;
228
229 if (t == pixmap_atom)
230 usage->n_pixmaps += types[i].count;
231 else if (t == window_atom)
232 usage->n_windows += types[i].count;
233 else if (t == gc_atom)
234 usage->n_gcs += types[i].count;
235 else if (t == picture_atom)
236 usage->n_pictures += types[i].count;
237 else if (t == glyphset_atom)
238 usage->n_glyphsets += types[i].count;
239 else if (t == font_atom)
240 usage->n_fonts += types[i].count;
241 else if (t == colormap_entry_atom)
242 usage->n_colormap_entries += types[i].count;
243 else if (t == passive_grab_atom)
244 usage->n_passive_grabs += types[i].count;
245 else if (t == cursor_atom)
246 usage->n_cursors += types[i].count;
247 else
248 usage->n_other += types[i].count;
249
250 ++i;
251 }
252
253 XFree(types);
254
255 usage->total_bytes_estimate = usage->pixmap_bytes;
256
257 /* FIXME look in the X server source and come up with better
258 * answers here. Ideally we change XRes to return a number
259 * like this since it can do things like divide the cost of
260 * a shared resource among those sharing it.
261 */
262 usage->total_bytes_estimate += usage->n_windows * 24;
263 usage->total_bytes_estimate += usage->n_gcs * 24;
264 usage->total_bytes_estimate += usage->n_pictures * 24;
265 usage->total_bytes_estimate += usage->n_glyphsets * 24;
266 usage->total_bytes_estimate += usage->n_fonts * 1024;
267 usage->total_bytes_estimate += usage->n_colormap_entries * 24;
268 usage->total_bytes_estimate += usage->n_passive_grabs * 24;
269 usage->total_bytes_estimate += usage->n_cursors * 24;
270 usage->total_bytes_estimate += usage->n_other * 24;
271 }
272 #else /* HAVE_XRES */
273 g_assert_not_reached ();
274 #endif /* HAVE_XRES */
275 }
276
277 #ifdef HAVE_XRES
278 static void
wnck_pid_read_resource_usage_free_hash(gpointer data)279 wnck_pid_read_resource_usage_free_hash (gpointer data)
280 {
281 g_slice_free (gulong, data);
282 }
283
284 static guint
wnck_gulong_hash(gconstpointer v)285 wnck_gulong_hash (gconstpointer v)
286 {
287 /* FIXME: this is obvioulsy wrong, but nearly 100% of the time, the gulong
288 * only contains guint values */
289 return *(const guint *) v;
290 }
291
292 static gboolean
wnck_gulong_equal(gconstpointer a,gconstpointer b)293 wnck_gulong_equal (gconstpointer a,
294 gconstpointer b)
295 {
296 return *((const gulong *) a) == *((const gulong *) b);
297 }
298
299 static gulong
wnck_check_window_for_pid(Window win,XID match_xid,XID mask)300 wnck_check_window_for_pid (Window win,
301 XID match_xid,
302 XID mask)
303 {
304 if ((win & ~mask) == match_xid) {
305 return _wnck_get_pid (win);
306 }
307
308 return 0;
309 }
310
311 static void
wnck_find_pid_for_resource_r(Display * xdisplay,Window win_top,XID match_xid,XID mask,gulong * xid,gulong * pid)312 wnck_find_pid_for_resource_r (Display *xdisplay,
313 Window win_top,
314 XID match_xid,
315 XID mask,
316 gulong *xid,
317 gulong *pid)
318 {
319 Status qtres;
320 int err;
321 Window dummy;
322 Window *children;
323 guint n_children;
324 int i;
325 gulong found_pid = 0;
326
327 while (gtk_events_pending ())
328 gtk_main_iteration ();
329
330 found_pid = wnck_check_window_for_pid (win_top, match_xid, mask);
331 if (found_pid != 0)
332 {
333 *xid = win_top;
334 *pid = found_pid;
335 }
336
337 _wnck_error_trap_push ();
338 qtres = XQueryTree (xdisplay, win_top, &dummy, &dummy,
339 &children, &n_children);
340 err = _wnck_error_trap_pop ();
341
342 if (!qtres || err != Success)
343 return;
344
345 for (i = 0; i < n_children; i++)
346 {
347 wnck_find_pid_for_resource_r (xdisplay, children[i],
348 match_xid, mask, xid, pid);
349
350 if (*pid != 0)
351 break;
352 }
353
354 if (children)
355 XFree ((char *)children);
356 }
357
358 struct xresclient_state
359 {
360 XResClient *clients;
361 int n_clients;
362 int next;
363 Display *xdisplay;
364 GHashTable *hashtable_pid;
365 };
366
367 static struct xresclient_state xres_state = { NULL, 0, -1, NULL, NULL };
368 static guint xres_idleid = 0;
369 static GHashTable *xres_hashtable = NULL;
370 static time_t start_update = 0;
371 static time_t end_update = 0;
372 static guint xres_removeid = 0;
373
374 static void
wnck_pid_read_resource_usage_xres_state_free(gpointer data)375 wnck_pid_read_resource_usage_xres_state_free (gpointer data)
376 {
377 struct xresclient_state *state;
378
379 state = (struct xresclient_state *) data;
380
381 if (state->clients)
382 XFree (state->clients);
383 state->clients = NULL;
384
385 state->n_clients = 0;
386 state->next = -1;
387 state->xdisplay = NULL;
388
389 if (state->hashtable_pid)
390 g_hash_table_destroy (state->hashtable_pid);
391 state->hashtable_pid = NULL;
392 }
393
394 static gboolean
wnck_pid_read_resource_usage_fill_cache(struct xresclient_state * state)395 wnck_pid_read_resource_usage_fill_cache (struct xresclient_state *state)
396 {
397 int i;
398 gulong pid;
399 gulong xid;
400 XID match_xid;
401
402 if (state->next >= state->n_clients)
403 {
404 if (xres_hashtable)
405 g_hash_table_destroy (xres_hashtable);
406 xres_hashtable = state->hashtable_pid;
407 state->hashtable_pid = NULL;
408
409 time (&end_update);
410
411 xres_idleid = 0;
412 return FALSE;
413 }
414
415 match_xid = (state->clients[state->next].resource_base &
416 ~state->clients[state->next].resource_mask);
417
418 pid = 0;
419 xid = 0;
420
421 for (i = 0; i < ScreenCount (state->xdisplay); i++)
422 {
423 Window root;
424
425 root = RootWindow (state->xdisplay, i);
426
427 if (root == None)
428 continue;
429
430 wnck_find_pid_for_resource_r (state->xdisplay, root, match_xid,
431 state->clients[state->next].resource_mask,
432 &xid, &pid);
433
434 if (pid != 0 && xid != 0)
435 break;
436 }
437
438 if (pid != 0 && xid != 0)
439 {
440 gulong *key;
441 gulong *value;
442
443 key = g_slice_new (gulong);
444 value = g_slice_new (gulong);
445 *key = pid;
446 *value = xid;
447 g_hash_table_insert (state->hashtable_pid, key, value);
448 }
449
450 state->next++;
451
452 return TRUE;
453 }
454
455 static void
wnck_pid_read_resource_usage_start_build_cache(GdkDisplay * gdisplay)456 wnck_pid_read_resource_usage_start_build_cache (GdkDisplay *gdisplay)
457 {
458 Display *xdisplay;
459 int err;
460
461 if (xres_idleid != 0)
462 return;
463
464 time (&start_update);
465
466 xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
467
468 _wnck_error_trap_push ();
469 XResQueryClients (xdisplay, &xres_state.n_clients, &xres_state.clients);
470 err = _wnck_error_trap_pop ();
471
472 if (err != Success)
473 return;
474
475 xres_state.next = (xres_state.n_clients > 0) ? 0 : -1;
476 xres_state.xdisplay = xdisplay;
477 xres_state.hashtable_pid = g_hash_table_new_full (
478 wnck_gulong_hash,
479 wnck_gulong_equal,
480 wnck_pid_read_resource_usage_free_hash,
481 wnck_pid_read_resource_usage_free_hash);
482
483 xres_idleid = g_idle_add_full (
484 G_PRIORITY_HIGH_IDLE,
485 (GSourceFunc) wnck_pid_read_resource_usage_fill_cache,
486 &xres_state, wnck_pid_read_resource_usage_xres_state_free);
487 }
488
489 static gboolean
wnck_pid_read_resource_usage_destroy_hash_table(gpointer data)490 wnck_pid_read_resource_usage_destroy_hash_table (gpointer data)
491 {
492 xres_removeid = 0;
493
494 if (xres_hashtable)
495 g_hash_table_destroy (xres_hashtable);
496
497 xres_hashtable = NULL;
498
499 return FALSE;
500 }
501
502 #define XRES_UPDATE_RATE_SEC 30
503 static gboolean
wnck_pid_read_resource_usage_from_cache(GdkDisplay * gdisplay,gulong pid,WnckResourceUsage * usage)504 wnck_pid_read_resource_usage_from_cache (GdkDisplay *gdisplay,
505 gulong pid,
506 WnckResourceUsage *usage)
507 {
508 gboolean need_rebuild;
509 gulong *xid_p;
510 int cache_validity;
511
512 if (end_update == 0)
513 time (&end_update);
514
515 cache_validity = MAX (XRES_UPDATE_RATE_SEC, (end_update - start_update) * 2);
516
517 /* we rebuild the cache if it was never built or if it's old */
518 need_rebuild = (xres_hashtable == NULL ||
519 (end_update < time (NULL) - cache_validity));
520
521 if (xres_hashtable)
522 {
523 /* clear the cache after quite some time, because it might not be used
524 * anymore */
525 if (xres_removeid != 0)
526 g_source_remove (xres_removeid);
527 xres_removeid = g_timeout_add_seconds (cache_validity * 2,
528 wnck_pid_read_resource_usage_destroy_hash_table,
529 NULL);
530 }
531
532 if (need_rebuild)
533 wnck_pid_read_resource_usage_start_build_cache (gdisplay);
534
535 if (xres_hashtable)
536 xid_p = g_hash_table_lookup (xres_hashtable, &pid);
537 else
538 xid_p = NULL;
539
540 if (xid_p)
541 {
542 wnck_xid_read_resource_usage (gdisplay, *xid_p, usage);
543 return TRUE;
544 }
545
546 return FALSE;
547 }
548
549 static void
wnck_pid_read_resource_usage_no_cache(GdkDisplay * gdisplay,gulong pid,WnckResourceUsage * usage)550 wnck_pid_read_resource_usage_no_cache (GdkDisplay *gdisplay,
551 gulong pid,
552 WnckResourceUsage *usage)
553 {
554 Display *xdisplay;
555 int i;
556
557 xdisplay = GDK_DISPLAY_XDISPLAY (gdisplay);
558
559 i = 0;
560 while (i < ScreenCount (xdisplay))
561 {
562 WnckScreen *screen;
563 GList *windows;
564 GList *tmp;
565
566 screen = wnck_screen_get (i);
567
568 g_assert (screen != NULL);
569
570 windows = wnck_screen_get_windows (screen);
571 tmp = windows;
572 while (tmp != NULL)
573 {
574 if (wnck_window_get_pid (tmp->data) == pid)
575 {
576 wnck_xid_read_resource_usage (gdisplay,
577 wnck_window_get_xid (tmp->data),
578 usage);
579
580 /* stop on first window found */
581 return;
582 }
583
584 tmp = tmp->next;
585 }
586
587 ++i;
588 }
589 }
590 #endif /* HAVE_XRES */
591
592 /**
593 * wnck_pid_read_resource_usage:
594 * @gdk_display: a <classname>GdkDisplay</classname>.
595 * @pid: a process ID.
596 * @usage: return location for the X resource usage of the application with
597 * process ID @pid.
598 *
599 * Looks for the X resource usage of the application with process ID @pid on
600 * display @gdisplay. If no resource usage can be found, then all fields of
601 * @usage are set to 0.
602 *
603 * In order to find the resource usage of an application that does not have an
604 * X window visible to libwnck (panel applets do not have any toplevel windows,
605 * for example), wnck_pid_read_resource_usage() walks through the whole tree of
606 * X windows. Since this walk is expensive in CPU, a cache is created. This
607 * cache is updated in the background. This means there is a non-null
608 * probability that no resource usage will be found for an application, even if
609 * it is an X client. If this happens, calling wnck_pid_read_resource_usage()
610 * again after a few seconds should work.
611 *
612 * To properly work, this function requires the XRes extension on the X server.
613 *
614 * Since: 2.6
615 */
616 void
wnck_pid_read_resource_usage(GdkDisplay * gdisplay,gulong pid,WnckResourceUsage * usage)617 wnck_pid_read_resource_usage (GdkDisplay *gdisplay,
618 gulong pid,
619 WnckResourceUsage *usage)
620 {
621 g_return_if_fail (usage != NULL);
622
623 memset (usage, '\0', sizeof (*usage));
624
625 if (wnck_init_resource_usage (gdisplay) == WNCK_EXT_MISSING)
626 return;
627
628 #ifdef HAVE_XRES
629 if (!wnck_pid_read_resource_usage_from_cache (gdisplay, pid, usage))
630 /* the cache might not be built, might be outdated or might not contain
631 * data for a new X client, so try to fallback to something else */
632 wnck_pid_read_resource_usage_no_cache (gdisplay, pid, usage);
633 #endif /* HAVE_XRES */
634 }
635
636 static WnckClientType client_type = 0;
637
638 /**
639 * wnck_set_client_type:
640 * @ewmh_sourceindication_client_type: a role for the client.
641 *
642 * Sets the role of the libwnck user.
643 *
644 * The default role is %WNCK_CLIENT_TYPE_APPLICATION. Therefore, for
645 * applications providing some window management features, like pagers or
646 * tasklists, it is important to set the role to %WNCK_CLIENT_TYPE_PAGER for
647 * libwnck to properly work.
648 *
649 * Since: 2.14
650 */
651 void
wnck_set_client_type(WnckClientType ewmh_sourceindication_client_type)652 wnck_set_client_type (WnckClientType ewmh_sourceindication_client_type)
653 {
654 /* Clients constantly switching types makes no sense; this should only be
655 * set once.
656 */
657 if (client_type != 0)
658 g_critical ("wnck_set_client_type got called multiple times.\n");
659 else
660 client_type = ewmh_sourceindication_client_type;
661 }
662
663 WnckClientType
_wnck_get_client_type(void)664 _wnck_get_client_type (void)
665 {
666 /* If the type hasn't been set yet, use the default--treat it as a
667 * normal application.
668 */
669 if (client_type == 0)
670 client_type = WNCK_CLIENT_TYPE_APPLICATION;
671
672 return client_type;
673 }
674
675 /**
676 * _make_gtk_label_bold:
677 *
678 * Switches the font of label to a bold equivalent.
679 * @label: The label.
680 **/
681 void
_make_gtk_label_bold(GtkLabel * label)682 _make_gtk_label_bold (GtkLabel *label)
683 {
684 PangoFontDescription *font_desc;
685
686 font_desc = pango_font_description_new ();
687
688 pango_font_description_set_weight (font_desc,
689 PANGO_WEIGHT_BOLD);
690
691 /* This will only affect the weight of the font, the rest is
692 * from the current state of the widget, which comes from the
693 * theme or user prefs, since the font desc only has the
694 * weight flag turned on.
695 */
696 gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
697
698 pango_font_description_free (font_desc);
699 }
700
701 void
_make_gtk_label_normal(GtkLabel * label)702 _make_gtk_label_normal (GtkLabel *label)
703 {
704 PangoFontDescription *font_desc;
705
706 font_desc = pango_font_description_new ();
707
708 pango_font_description_set_weight (font_desc,
709 PANGO_WEIGHT_NORMAL);
710
711 /* This will only affect the weight of the font, the rest is
712 * from the current state of the widget, which comes from the
713 * theme or user prefs, since the font desc only has the
714 * weight flag turned on.
715 */
716 gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
717
718 pango_font_description_free (font_desc);
719 }
720
721 #ifdef HAVE_STARTUP_NOTIFICATION
722 static gboolean
_wnck_util_sn_utf8_validator(const char * str,int max_len)723 _wnck_util_sn_utf8_validator (const char *str,
724 int max_len)
725 {
726 return g_utf8_validate (str, max_len, NULL);
727 }
728 #endif /* HAVE_STARTUP_NOTIFICATION */
729
730 void
_wnck_init(void)731 _wnck_init (void)
732 {
733 static gboolean done = FALSE;
734
735 if (!done)
736 {
737 bindtextdomain (GETTEXT_PACKAGE, WNCK_LOCALEDIR);
738 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
739
740 #ifdef HAVE_STARTUP_NOTIFICATION
741 sn_set_utf8_validator (_wnck_util_sn_utf8_validator);
742 #endif /* HAVE_STARTUP_NOTIFICATION */
743
744 done = TRUE;
745 }
746 }
747
748 Display *
_wnck_get_default_display(void)749 _wnck_get_default_display (void)
750 {
751 /* FIXME: when we fix libwnck to not use the GDK default display, we will
752 * need to fix wnckprop accordingly. */
753 return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
754 }
755
756 /* stock icon code Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org> */
757 typedef struct
758 {
759 char *stock_id;
760 const guint8 *icon_data;
761 } StockIcon;
762
763 void
_wnck_stock_icons_init(void)764 _wnck_stock_icons_init (void)
765 {
766 GtkIconFactory *factory;
767 int i;
768 static gboolean done = FALSE;
769
770 StockIcon items[] =
771 {
772 { WNCK_STOCK_DELETE, stock_delete_data },
773 { WNCK_STOCK_MINIMIZE, stock_minimize_data },
774 { WNCK_STOCK_MAXIMIZE, stock_maximize_data }
775 };
776
777 if (done)
778 return;
779
780 done = TRUE;
781
782 factory = gtk_icon_factory_new ();
783 gtk_icon_factory_add_default (factory);
784
785 for (i = 0; i < (gint) G_N_ELEMENTS (items); i++)
786 {
787 GtkIconSet *icon_set;
788 GdkPixbuf *pixbuf;
789
790 pixbuf = gdk_pixbuf_new_from_inline (-1, items[i].icon_data,
791 FALSE,
792 NULL);
793
794 icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
795 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
796 gtk_icon_set_unref (icon_set);
797
798 g_object_unref (G_OBJECT (pixbuf));
799 }
800
801 g_object_unref (G_OBJECT (factory));
802 }
803