No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | shell-tray-manager.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 #include "config.h"
4
5 #include <clutter/clutter.h>
6 #include <clutter/x11/clutter-x11.h>
7 #include <girepository.h>
8 #include <gtk/gtk.h>
9 #include <meta/display.h>
10
11 #include "shell-tray-manager.h"
12 #include "na-tray-manager.h"
13
14 #include "shell-tray-icon.h"
15 #include "shell-embedded-window.h"
16 #include "shell-global.h"
17
18 struct _ShellTrayManagerPrivate {
19 NaTrayManager *na_manager;
20 ClutterStage *stage;
21 ClutterColor bg_color;
22
23 GHashTable *icons;
24 };
25
26 typedef struct {
27 ShellTrayManager *manager;
28 GtkWidget *socket;
29 GtkWidget *window;
30 ClutterActor *actor;
31 } ShellTrayManagerChild;
32
33 enum {
34 PROP_0,
35
36 PROP_BG_COLOR
37 };
38
39 /* Signals */
40 enum
41 {
42 TRAY_ICON_ADDED,
43 TRAY_ICON_REMOVED,
44 LAST_SIGNAL
45 };
46
47 G_DEFINE_TYPE (ShellTrayManager, shell_tray_manager, G_TYPE_OBJECT);
48
49 static guint shell_tray_manager_signals [LAST_SIGNAL] = { 0 };
50
51 static const ClutterColor default_color = { 0x00, 0x00, 0x00, 0xff };
52
53 static void na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *child, gpointer manager);
54 static void na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *child, gpointer manager);
55
56 static void
57 free_tray_icon (gpointer data)
58 {
59 ShellTrayManagerChild *child = data;
60
61 gtk_widget_destroy (child->window);
62 if (child->actor)
63 {
64 g_signal_handlers_disconnect_matched (child->actor, G_SIGNAL_MATCH_DATA,
65 0, 0, NULL, NULL, child);
66 g_object_unref (child->actor);
67 }
68 g_slice_free (ShellTrayManagerChild, child);
69 }
70
71 static void
72 shell_tray_manager_set_property(GObject *object,
73 guint prop_id,
74 const GValue *value,
75 GParamSpec *pspec)
76 {
77 ShellTrayManager *manager = SHELL_TRAY_MANAGER (object);
78
79 switch (prop_id)
80 {
81 case PROP_BG_COLOR:
82 {
83 ClutterColor *color = g_value_get_boxed (value);
84 if (color)
85 manager->priv->bg_color = *color;
86 else
87 manager->priv->bg_color = default_color;
88 }
89 break;
90 default:
91 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 break;
93 }
94 }
95
96 static void
97 shell_tray_manager_get_property(GObject *object,
98 guint prop_id,
99 GValue *value,
100 GParamSpec *pspec)
101 {
102 ShellTrayManager *manager = SHELL_TRAY_MANAGER (object);
103
104 switch (prop_id)
105 {
106 case PROP_BG_COLOR:
107 g_value_set_boxed (value, &manager->priv->bg_color);
108 break;
109 default:
110 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111 break;
112 }
113 }
114
115 static void
116 shell_tray_manager_init (ShellTrayManager *manager)
117 {
118 manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, SHELL_TYPE_TRAY_MANAGER,
119 ShellTrayManagerPrivate);
120 manager->priv->na_manager = na_tray_manager_new ();
121
122 manager->priv->icons = g_hash_table_new_full (NULL, NULL,
123 NULL, free_tray_icon);
124 manager->priv->bg_color = default_color;
125
126 g_signal_connect (manager->priv->na_manager, "tray-icon-added",
127 G_CALLBACK (na_tray_icon_added), manager);
128 g_signal_connect (manager->priv->na_manager, "tray-icon-removed",
129 G_CALLBACK (na_tray_icon_removed), manager);
130 }
131
132 static void
133 shell_tray_manager_finalize (GObject *object)
134 {
135 ShellTrayManager *manager = SHELL_TRAY_MANAGER (object);
136
137 g_object_unref (manager->priv->na_manager);
138 g_object_unref (manager->priv->stage);
139 g_hash_table_destroy (manager->priv->icons);
140
141 G_OBJECT_CLASS (shell_tray_manager_parent_class)->finalize (object);
142 }
143
144 static void
145 shell_tray_manager_class_init (ShellTrayManagerClass *klass)
146 {
147 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
148
149 g_type_class_add_private (klass, sizeof (ShellTrayManagerPrivate));
150
151 gobject_class->finalize = shell_tray_manager_finalize;
152 gobject_class->set_property = shell_tray_manager_set_property;
153 gobject_class->get_property = shell_tray_manager_get_property;
154
155 shell_tray_manager_signals[TRAY_ICON_ADDED] =
156 g_signal_new ("tray-icon-added",
157 G_TYPE_FROM_CLASS (klass),
158 G_SIGNAL_RUN_LAST,
159 G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
160 NULL, NULL, NULL,
161 G_TYPE_NONE, 1,
162 CLUTTER_TYPE_ACTOR);
163 shell_tray_manager_signals[TRAY_ICON_REMOVED] =
164 g_signal_new ("tray-icon-removed",
165 G_TYPE_FROM_CLASS (klass),
166 G_SIGNAL_RUN_LAST,
167 G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_removed),
168 NULL, NULL, NULL,
169 G_TYPE_NONE, 1,
170 CLUTTER_TYPE_ACTOR);
171
172 /* Lifting the CONSTRUCT_ONLY here isn't hard; you just need to
173 * iterate through the icons, reset the background pixmap, and
174 * call na_tray_child_force_redraw()
175 */
176 g_object_class_install_property (gobject_class,
177 PROP_BG_COLOR,
178 g_param_spec_boxed ("bg-color",
179 "BG Color",
180 "Background color (only if we don't have transparency)",
181 CLUTTER_TYPE_COLOR,
182 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
183 }
184
185 ShellTrayManager *
186 shell_tray_manager_new (void)
187 {
188 return g_object_new (SHELL_TYPE_TRAY_MANAGER, NULL);
189 }
190
191 static void
192 shell_tray_manager_style_changed (StWidget *theme_widget,
193 gpointer user_data)
194 {
195 ShellTrayManager *manager = user_data;
196 StThemeNode *theme_node;
197 StIconColors *icon_colors;
198 GdkColor foreground, warning, error, success;
199
200 theme_node = st_widget_get_theme_node (theme_widget);
201 icon_colors = st_theme_node_get_icon_colors (theme_node);
202
203 foreground.red = icon_colors->foreground.red * 0x101;
204 foreground.green = icon_colors->foreground.green * 0x101;
205 foreground.blue = icon_colors->foreground.blue * 0x101;
206 warning.red = icon_colors->warning.red * 0x101;
207 warning.green = icon_colors->warning.green * 0x101;
208 warning.blue = icon_colors->warning.blue * 0x101;
209 error.red = icon_colors->error.red * 0x101;
210 error.green = icon_colors->error.green * 0x101;
211 error.blue = icon_colors->error.blue * 0x101;
212 success.red = icon_colors->success.red * 0x101;
213 success.green = icon_colors->success.green * 0x101;
214 success.blue = icon_colors->success.blue * 0x101;
215
216 na_tray_manager_set_colors (manager->priv->na_manager,
217 &foreground, &warning,
218 &error, &success);
219 }
220
221 void
222 shell_tray_manager_manage_stage (ShellTrayManager *manager,
223 ClutterStage *stage,
224 StWidget *theme_widget)
225 {
226 Window stage_xwindow;
227 GdkWindow *stage_window;
228 GdkDisplay *display;
229 GdkScreen *screen;
230
231 g_return_if_fail (manager->priv->stage == NULL);
232
233 manager->priv->stage = g_object_ref (stage);
234
235 stage_xwindow = clutter_x11_get_stage_window (stage);
236
237 /* This is a pretty ugly way to get the GdkScreen for the stage; it
238 * will normally go through the foreign_new() case with a
239 * round-trip to the X server, it might be nicer to pass the screen
240 * in in some way. (The Clutter/Mutter combo is currently incapable
241 * of multi-screen operation, so alternatively we could just assume
242 * that clutter_x11_get_default_screen() gives us the right
243 * screen.) We assume, in any case, that we are using the default
244 * GDK display.
245 */
246 display = gdk_display_get_default();
247 stage_window = gdk_x11_window_lookup_for_display (display, stage_xwindow);
248 if (stage_window)
249 g_object_ref (stage_window);
250 else
251 stage_window = gdk_x11_window_foreign_new_for_display (display, stage_xwindow);
252
253 screen = gdk_window_get_screen (stage_window);
254
255 g_object_unref (stage_window);
256
257 na_tray_manager_manage_screen (manager->priv->na_manager, screen);
258
259 g_signal_connect (theme_widget, "style-changed",
260 G_CALLBACK (shell_tray_manager_style_changed), manager);
261 shell_tray_manager_style_changed (theme_widget, manager);
262 }
263
264 static void
265 shell_tray_manager_child_on_realize (GtkWidget *widget,
266 ShellTrayManagerChild *child)
267 {
268 /* If the tray child is using an RGBA colormap (and so we have real
269 * transparency), we don't need to worry about the background. If
270 * not, we obey the bg-color property by creating a cairo pattern of
271 * that color and setting it as our background. Then "parent-relative"
272 * background on the socket and the plug within that will cause
273 * the icons contents to appear on top of our background color.
274 */
275 if (!na_tray_child_has_alpha (NA_TRAY_CHILD (child->socket)))
276 {
277 ClutterColor color = child->manager->priv->bg_color;
278 cairo_pattern_t *bg_pattern;
279
280 bg_pattern = cairo_pattern_create_rgb (color.red / 255.,
281 color.green / 255.,
282 color.blue / 255.);
283 gdk_window_set_background_pattern (gtk_widget_get_window (widget),
284 bg_pattern);
285
286 cairo_pattern_destroy (bg_pattern);
287 }
288 }
289
290 static void
291 on_plug_added (GtkSocket *socket,
292 ShellTrayManager *manager)
293 {
294 ShellTrayManagerChild *child;
295
296 g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager);
297
298 child = g_hash_table_lookup (manager->priv->icons, socket);
299
300 child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window));
301 g_object_ref_sink (child->actor);
302
303 g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
304 child->actor);
305 }
306
307 static void
308 na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
309 gpointer user_data)
310 {
311 ShellTrayManager *manager = user_data;
312 GtkWidget *win;
313 ShellTrayManagerChild *child;
314
315 /* We don't need the NaTrayIcon to be composited on the window we
316 * put it in: the window is the same size as the tray icon
317 * and transparent. We can just use the default X handling of
318 * subwindows as mode of SOURCE (replace the parent with the
319 * child) and then composite the parent onto the stage.
320 */
321 na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);
322
323 win = shell_embedded_window_new (manager->priv->stage);
324 gtk_container_add (GTK_CONTAINER (win), socket);
325
326 /* The visual of the socket matches that of its contents; make
327 * the window we put it in match that as well */
328 gtk_widget_set_visual (win, gtk_widget_get_visual (socket));
329
330 child = g_slice_new0 (ShellTrayManagerChild);
331 child->manager = manager;
332 child->window = win;
333 child->socket = socket;
334
335 g_signal_connect (win, "realize",
336 G_CALLBACK (shell_tray_manager_child_on_realize), child);
337
338 gtk_widget_show_all (win);
339
340 g_hash_table_insert (manager->priv->icons, socket, child);
341
342 g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);
343 }
344
345 static void
346 na_tray_icon_removed (NaTrayManager *na_manager, GtkWidget *socket,
347 gpointer user_data)
348 {
349 ShellTrayManager *manager = user_data;
350 ShellTrayManagerChild *child;
351
352 child = g_hash_table_lookup (manager->priv->icons, socket);
353 g_return_if_fail (child != NULL);
354
355 if (child->actor != NULL)
356 {
357 /* Only emit signal if a corresponding tray-icon-added signal was emitted,
358 that is, if embedding did not fail and we got a plug-added
359 */
360 g_signal_emit (manager,
361 shell_tray_manager_signals[TRAY_ICON_REMOVED], 0,
362 child->actor);
363 }
364 g_hash_table_remove (manager->priv->icons, socket);
365 }