gnome-shell-3.6.3.1/src/shell-tray-manager.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }