evolution-3.6.4/shell/e-shell-taskbar.c

No issues found

  1 /*
  2  * e-shell-taskbar.c
  3  *
  4  * This program 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) version 3.
  8  *
  9  * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 19  *
 20  */
 21 
 22 /**
 23  * SECTION: e-shell-taskbar
 24  * @short_description: the bottom of the main window
 25  * @include: shell/e-shell-taskbar.h
 26  **/
 27 
 28 #ifdef HAVE_CONFIG_H
 29 #include <config.h>
 30 #endif
 31 
 32 #include "e-shell-taskbar.h"
 33 
 34 #include <libebackend/libebackend.h>
 35 
 36 #include <e-shell-view.h>
 37 #include <misc/e-activity-proxy.h>
 38 
 39 #define E_SHELL_TASKBAR_GET_PRIVATE(obj) \
 40 	(G_TYPE_INSTANCE_GET_PRIVATE \
 41 	((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbarPrivate))
 42 
 43 struct _EShellTaskbarPrivate {
 44 
 45 	gpointer shell_view;  /* weak pointer */
 46 
 47 	/* Keep a reference to the shell backend since
 48 	 * we connect to its "activity-added" signal. */
 49 	EShellBackend *shell_backend;
 50 
 51 	GtkWidget *label;
 52 	GtkWidget *hbox;
 53 
 54 	GHashTable *proxy_table;
 55 
 56 	gint fixed_height;
 57 };
 58 
 59 enum {
 60 	PROP_0,
 61 	PROP_MESSAGE,
 62 	PROP_SHELL_VIEW
 63 };
 64 
 65 G_DEFINE_TYPE_WITH_CODE (
 66 	EShellTaskbar,
 67 	e_shell_taskbar,
 68 	GTK_TYPE_HBOX,
 69 	G_IMPLEMENT_INTERFACE (
 70 		E_TYPE_EXTENSIBLE, NULL))
 71 
 72 static void
 73 shell_taskbar_weak_notify_cb (EShellTaskbar *shell_taskbar,
 74                               GObject *where_the_activity_was)
 75 {
 76 	GtkWidget *proxy;
 77 	GtkContainer *container;
 78 	GHashTable *proxy_table;
 79 	GList *children;
 80 
 81 	proxy_table = shell_taskbar->priv->proxy_table;
 82 	proxy = g_hash_table_lookup (proxy_table, where_the_activity_was);
 83 	g_hash_table_remove (proxy_table, where_the_activity_was);
 84 	g_return_if_fail (proxy != NULL);
 85 
 86 	container = GTK_CONTAINER (shell_taskbar->priv->hbox);
 87 	gtk_container_remove (container, proxy);
 88 
 89 	children = gtk_container_get_children (container);
 90 
 91 	if (children == NULL)
 92 		gtk_widget_hide (GTK_WIDGET (container));
 93 
 94 	g_list_free (children);
 95 }
 96 
 97 static void
 98 shell_taskbar_activity_add (EShellTaskbar *shell_taskbar,
 99                             EActivity *activity)
100 {
101 	GtkBox *box;
102 	GtkWidget *proxy;
103 	EActivityState state;
104 	GHashTable *proxy_table;
105 
106 	/* Sanity check the activity state. */
107 	state = e_activity_get_state (activity);
108 	g_return_if_fail (state == E_ACTIVITY_RUNNING);
109 
110 	/* Make sure it hasn't already been added. */
111 	proxy_table = shell_taskbar->priv->proxy_table;
112 	proxy = g_hash_table_lookup (proxy_table, activity);
113 	g_return_if_fail (proxy == NULL);
114 
115 	/* Proxy widgets manage their own visibility.
116 	 * Don't call gtk_widget_show() on it here. */
117 	proxy = e_activity_proxy_new (activity);
118 	box = GTK_BOX (shell_taskbar->priv->hbox);
119 	gtk_box_pack_start (box, proxy, TRUE, TRUE, 0);
120 	gtk_box_reorder_child (box, proxy, 0);
121 	gtk_widget_show (GTK_WIDGET (box));
122 
123 	/* The proxy widget also holds a weak reference to the activity,
124 	 * so the activity should get finalized in the normal course of
125 	 * operation.  When that happens we remove the corresponding
126 	 * proxy widget from the taskbar. */
127 
128 	g_object_weak_ref (
129 		G_OBJECT (activity), (GWeakNotify)
130 		shell_taskbar_weak_notify_cb, shell_taskbar);
131 
132 	g_hash_table_insert (proxy_table, activity, proxy);
133 }
134 
135 static gboolean
136 shell_taskbar_weak_unref (EActivity *activity,
137                           EActivityProxy *proxy,
138                           EShellTaskbar *shell_taskbar)
139 {
140 	g_object_weak_unref (
141 		G_OBJECT (activity), (GWeakNotify)
142 		shell_taskbar_weak_notify_cb, shell_taskbar);
143 
144 	return TRUE;
145 }
146 
147 static void
148 shell_taskbar_set_shell_view (EShellTaskbar *shell_taskbar,
149                               EShellView *shell_view)
150 {
151 	g_return_if_fail (shell_taskbar->priv->shell_view == NULL);
152 
153 	shell_taskbar->priv->shell_view = shell_view;
154 
155 	g_object_add_weak_pointer (
156 		G_OBJECT (shell_view),
157 		&shell_taskbar->priv->shell_view);
158 }
159 
160 static void
161 shell_taskbar_set_property (GObject *object,
162                             guint property_id,
163                             const GValue *value,
164                             GParamSpec *pspec)
165 {
166 	switch (property_id) {
167 		case PROP_MESSAGE:
168 			e_shell_taskbar_set_message (
169 				E_SHELL_TASKBAR (object),
170 				g_value_get_string (value));
171 			return;
172 
173 		case PROP_SHELL_VIEW:
174 			shell_taskbar_set_shell_view (
175 				E_SHELL_TASKBAR (object),
176 				g_value_get_object (value));
177 			return;
178 	}
179 
180 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
181 }
182 
183 static void
184 shell_taskbar_get_property (GObject *object,
185                             guint property_id,
186                             GValue *value,
187                             GParamSpec *pspec)
188 {
189 	switch (property_id) {
190 		case PROP_MESSAGE:
191 			g_value_set_string (
192 				value, e_shell_taskbar_get_message (
193 				E_SHELL_TASKBAR (object)));
194 			return;
195 
196 		case PROP_SHELL_VIEW:
197 			g_value_set_object (
198 				value, e_shell_taskbar_get_shell_view (
199 				E_SHELL_TASKBAR (object)));
200 			return;
201 	}
202 
203 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
204 }
205 
206 static void
207 shell_taskbar_dispose (GObject *object)
208 {
209 	EShellTaskbarPrivate *priv;
210 
211 	priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
212 
213 	g_hash_table_foreach_remove (
214 		priv->proxy_table, (GHRFunc)
215 		shell_taskbar_weak_unref, object);
216 
217 	if (priv->shell_view != NULL) {
218 		g_object_remove_weak_pointer (
219 			G_OBJECT (priv->shell_view), &priv->shell_view);
220 		priv->shell_view = NULL;
221 	}
222 
223 	if (priv->shell_backend != NULL) {
224 		g_signal_handlers_disconnect_matched (
225 			priv->shell_backend, G_SIGNAL_MATCH_DATA,
226 			0, 0, NULL, NULL, object);
227 		g_object_unref (priv->shell_backend);
228 		priv->shell_backend = NULL;
229 	}
230 
231 	if (priv->label != NULL) {
232 		g_object_unref (priv->label);
233 		priv->label = NULL;
234 	}
235 
236 	if (priv->hbox != NULL) {
237 		g_object_unref (priv->hbox);
238 		priv->hbox = NULL;
239 	}
240 
241 	/* Chain up to parent's dispose() method. */
242 	G_OBJECT_CLASS (e_shell_taskbar_parent_class)->dispose (object);
243 }
244 
245 static void
246 shell_taskbar_finalize (GObject *object)
247 {
248 	EShellTaskbarPrivate *priv;
249 
250 	priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
251 
252 	g_hash_table_destroy (priv->proxy_table);
253 
254 	/* Chain up to parent's finalize() method. */
255 	G_OBJECT_CLASS (e_shell_taskbar_parent_class)->finalize (object);
256 }
257 
258 static void
259 shell_taskbar_constructed (GObject *object)
260 {
261 	EShellView *shell_view;
262 	EShellBackend *shell_backend;
263 	EShellTaskbar *shell_taskbar;
264 
265 	shell_taskbar = E_SHELL_TASKBAR (object);
266 	shell_view = e_shell_taskbar_get_shell_view (shell_taskbar);
267 	shell_backend = e_shell_view_get_shell_backend (shell_view);
268 
269 	/* Keep a reference to the shell backend so we can
270 	 * disconnect the signal handler during dispose(). */
271 	shell_taskbar->priv->shell_backend = g_object_ref (shell_backend);
272 
273 	g_signal_connect_swapped (
274 		shell_backend, "activity-added",
275 		G_CALLBACK (shell_taskbar_activity_add), shell_taskbar);
276 
277 	e_extensible_load_extensions (E_EXTENSIBLE (object));
278 
279 	/* Chain up to parent's constructed() method. */
280 	G_OBJECT_CLASS (e_shell_taskbar_parent_class)->constructed (object);
281 }
282 
283 static void
284 shell_taskbar_size_allocate (GtkWidget *widget,
285                              GtkAllocation *allocation)
286 {
287 	EShellTaskbar *shell_taskbar;
288 	gint fixed_height;
289 
290 	shell_taskbar = E_SHELL_TASKBAR (widget);
291 
292 	/* Maximum height allocation sticks. */
293 	fixed_height = shell_taskbar->priv->fixed_height;
294 	fixed_height = MAX (fixed_height, allocation->height);
295 	shell_taskbar->priv->fixed_height = fixed_height;
296 
297 	/* Chain up to parent's size_allocate() method. */
298 	GTK_WIDGET_CLASS (e_shell_taskbar_parent_class)->
299 		size_allocate (widget, allocation);
300 }
301 
302 static void
303 shell_taskbar_get_preferred_height (GtkWidget *widget,
304                                     gint *minimum_height,
305                                     gint *natural_height)
306 {
307 	EShellTaskbar *shell_taskbar;
308 
309 	shell_taskbar = E_SHELL_TASKBAR (widget);
310 
311 	if (minimum_height != NULL)
312 		*minimum_height = shell_taskbar->priv->fixed_height;
313 
314 	if (natural_height != NULL)
315 		*natural_height = shell_taskbar->priv->fixed_height;
316 }
317 
318 static void
319 shell_taskbar_get_preferred_width (GtkWidget *widget,
320                                    gint *minimum_width,
321                                    gint *natural_width)
322 {
323 	/* to never get larger than allocated size (which changes window width) */
324 
325 	if (minimum_width != NULL)
326 		*minimum_width = 1;
327 
328 	if (natural_width != NULL)
329 		*natural_width = 1;
330 }
331 
332 static void
333 e_shell_taskbar_class_init (EShellTaskbarClass *class)
334 {
335 	GObjectClass *object_class;
336 	GtkWidgetClass *widget_class;
337 
338 	g_type_class_add_private (class, sizeof (EShellTaskbarPrivate));
339 
340 	object_class = G_OBJECT_CLASS (class);
341 	object_class->set_property = shell_taskbar_set_property;
342 	object_class->get_property = shell_taskbar_get_property;
343 	object_class->dispose = shell_taskbar_dispose;
344 	object_class->finalize = shell_taskbar_finalize;
345 	object_class->constructed = shell_taskbar_constructed;
346 
347 	widget_class = GTK_WIDGET_CLASS (class);
348 	widget_class->size_allocate = shell_taskbar_size_allocate;
349 	widget_class->get_preferred_height = shell_taskbar_get_preferred_height;
350 	widget_class->get_preferred_width = shell_taskbar_get_preferred_width;
351 
352 	/**
353 	 * EShellTaskbar:message
354 	 *
355 	 * The message to display in the taskbar.
356 	 **/
357 	g_object_class_install_property (
358 		object_class,
359 		PROP_MESSAGE,
360 		g_param_spec_string (
361 			"message",
362 			NULL,
363 			NULL,
364 			NULL,
365 			G_PARAM_READWRITE |
366 			G_PARAM_CONSTRUCT));
367 
368 	/**
369 	 * EShellTaskbar:shell-view
370 	 *
371 	 * The #EShellView to which the taskbar widget belongs.
372 	 **/
373 	g_object_class_install_property (
374 		object_class,
375 		PROP_SHELL_VIEW,
376 		g_param_spec_object (
377 			"shell-view",
378 			NULL,
379 			NULL,
380 			E_TYPE_SHELL_VIEW,
381 			G_PARAM_READWRITE |
382 			G_PARAM_CONSTRUCT_ONLY));
383 }
384 
385 static void
386 e_shell_taskbar_init (EShellTaskbar *shell_taskbar)
387 {
388 	GtkWidget *widget;
389 
390 	shell_taskbar->priv = E_SHELL_TASKBAR_GET_PRIVATE (shell_taskbar);
391 	shell_taskbar->priv->proxy_table = g_hash_table_new (NULL, NULL);
392 
393 	gtk_box_set_spacing (GTK_BOX (shell_taskbar), 12);
394 
395 	widget = gtk_label_new (NULL);
396 	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
397 	gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
398 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
399 	shell_taskbar->priv->label = g_object_ref (widget);
400 	gtk_widget_hide (widget);
401 
402 	widget = gtk_hbox_new (FALSE, 3);
403 	gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
404 	shell_taskbar->priv->hbox = g_object_ref (widget);
405 	gtk_widget_hide (widget);
406 }
407 
408 /**
409  * e_shell_taskbar_new:
410  * @shell_view: an #EShellView
411  *
412  * Creates a new #EShellTaskbar instance belonging to @shell_view.
413  *
414  * Returns: a new #EShellTaskbar instance
415  **/
416 GtkWidget *
417 e_shell_taskbar_new (EShellView *shell_view)
418 {
419 	g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
420 
421 	return g_object_new (
422 		E_TYPE_SHELL_TASKBAR, "shell-view", shell_view, NULL);
423 }
424 
425 /**
426  * e_shell_taskbar_get_shell_view:
427  * @shell_taskbar: an #EShellTaskbar
428  *
429  * Returns the #EShellView that was passed to e_shell_taskbar_new().
430  *
431  * Returns: the #EShellView to which @shell_taskbar belongs
432  **/
433 EShellView *
434 e_shell_taskbar_get_shell_view (EShellTaskbar *shell_taskbar)
435 {
436 	g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
437 
438 	return shell_taskbar->priv->shell_view;
439 }
440 
441 /**
442  * e_shell_taskbar_get_message:
443  * @shell_taskbar: an #EShellTaskbar
444  *
445  * Returns the message currently shown in the taskbar, or an empty string
446  * if no message is shown.  Taskbar messages are used primarily for menu
447  * tooltips.
448  *
449  * Returns: the current taskbar message
450  **/
451 const gchar *
452 e_shell_taskbar_get_message (EShellTaskbar *shell_taskbar)
453 {
454 	GtkWidget *label;
455 
456 	g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
457 
458 	label = shell_taskbar->priv->label;
459 
460 	return gtk_label_get_text (GTK_LABEL (label));
461 }
462 
463 /**
464  * e_shell_taskbar_set_message:
465  * @shell_taskbar: an #EShellTaskbar
466  * @message: the message to show
467  *
468  * Shows a message in the taskbar.  If @message is %NULL or an empty string,
469  * the taskbar message is cleared.  Taskbar messages are used primarily for
470  * menu tooltips.
471  **/
472 void
473 e_shell_taskbar_set_message (EShellTaskbar *shell_taskbar,
474                              const gchar *message)
475 {
476 	GtkWidget *label;
477 
478 	g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
479 
480 	label = shell_taskbar->priv->label;
481 	gtk_label_set_text (GTK_LABEL (label), message);
482 
483 	if (message != NULL && *message != '\0')
484 		gtk_widget_show (label);
485 	else
486 		gtk_widget_hide (label);
487 
488 	g_object_notify (G_OBJECT (shell_taskbar), "message");
489 }
490 
491 /**
492  * e_shell_taskbar_unset_message:
493  * @shell_taskbar: an #EShellTaskbar
494  *
495  * This is equivalent to passing a %NULL message to
496  * e_shell_taskbar_set_message().
497  **/
498 void
499 e_shell_taskbar_unset_message (EShellTaskbar *shell_taskbar)
500 {
501 	g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
502 
503 	e_shell_taskbar_set_message (shell_taskbar, NULL);
504 }
505 
506 /**
507  * e_shell_taskbar_get_activity_count:
508  * @shell_taskbar: an #EShellTaskbar
509  *
510  * Returns the number of active #EActivity instances being tracked.
511  *
512  * Returns: the number of #EActivity instances
513  **/
514 guint
515 e_shell_taskbar_get_activity_count (EShellTaskbar *shell_taskbar)
516 {
517 	g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), 0);
518 
519 	return g_hash_table_size (shell_taskbar->priv->proxy_table);
520 }