Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / libanjuta / anjuta-status.c
blob697ba9bdee3709068f895d7dda0fec0296d8b7ca
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-status.c
4 * Copyright (C) 2004 Naba Kumar <naba@gnome.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 59
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /**
22 * SECTION:anjuta-status
23 * @short_description: Program status such as status message, progress etc.
24 * @see_also:
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-status.h
30 #include <config.h>
31 #include <gtk/gtkwindow.h>
32 #include <gtk/gtkprogressbar.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <libanjuta/anjuta-status.h>
35 #include <libanjuta/anjuta-utils.h>
36 #include <libanjuta/resources.h>
37 #include <libanjuta/e-splash.h>
39 struct _AnjutaStatusPriv
41 GHashTable *default_status_items;
42 gint busy_count;
43 GHashTable *widgets;
45 /* Status bar */
46 GtkWidget *status_bar;
47 guint status_message;
48 guint push_message;
49 GList *push_values;
51 /* Progress bar */
52 GtkWidget *progress_bar;
53 gint total_ticks;
54 gint current_ticks;
56 /* Splash */
57 GtkWidget *splash;
58 gboolean disable_splash;
59 gchar *splash_file;
60 gint splash_progress_position;
62 /* Title window */
63 GtkWindow *window;
66 enum {
67 BUSY,
68 LAST_SIGNAL
71 static gpointer parent_class = NULL;
72 static guint status_signals[LAST_SIGNAL] = { 0 };
74 static void on_widget_destroy (AnjutaStatus *status, GObject *widget);
76 static void
77 anjuta_status_finalize (GObject *widget)
79 g_free(ANJUTA_STATUS(widget)->priv);
80 G_OBJECT_CLASS (parent_class)->finalize (widget);
83 static void
84 foreach_widget_unref (gpointer key, gpointer value, gpointer data)
86 g_object_weak_unref (G_OBJECT (key), (GWeakNotify) on_widget_destroy, data);
89 static void
90 anjuta_status_dispose (GObject *widget)
92 AnjutaStatus *status;
94 status = ANJUTA_STATUS (widget);
96 if (status->priv->default_status_items)
98 g_hash_table_destroy (status->priv->default_status_items);
99 status->priv->default_status_items = NULL;
101 if (status->priv->splash != NULL) {
102 gtk_widget_destroy (status->priv->splash);
103 status->priv->splash = NULL;
105 if (status->priv->splash_file)
107 g_free (status->priv->splash_file);
108 status->priv->splash_file = NULL;
110 if (status->priv->push_values)
112 g_list_free (status->priv->push_values);
113 status->priv->push_values = NULL;
115 if (status->priv->widgets)
117 g_hash_table_foreach (status->priv->widgets,
118 foreach_widget_unref, widget);
119 g_hash_table_destroy (status->priv->widgets);
120 status->priv->widgets = NULL;
122 if (status->priv->window)
124 g_object_remove_weak_pointer (G_OBJECT (status->priv->window),
125 (gpointer*)(gpointer)&status->priv->window);
126 status->priv->window = NULL;
128 G_OBJECT_CLASS (parent_class)->dispose (widget);
131 static void
132 anjuta_status_instance_init (AnjutaStatus *status)
134 status->priv = g_new0 (AnjutaStatusPriv, 1);
135 status->priv->progress_bar = gtk_progress_bar_new ();
136 gtk_box_pack_start (GTK_BOX (status), status->priv->progress_bar, FALSE, TRUE, 0);
137 gtk_widget_show (status->priv->progress_bar);
138 status->priv->status_bar = gtk_statusbar_new ();
139 gtk_box_pack_start (GTK_BOX (status), status->priv->status_bar, TRUE, TRUE, 0);
140 gtk_widget_show (status->priv->status_bar);
141 status->priv->status_message = gtk_statusbar_get_context_id (GTK_STATUSBAR (status->priv->status_bar),
142 "status-message");
143 status->priv->push_message = gtk_statusbar_get_context_id (GTK_STATUSBAR (status->priv->status_bar),
144 "push-message");
145 status->priv->push_values = NULL;
146 status->priv->splash_file = NULL;
147 status->priv->splash_progress_position = 0;
148 status->priv->disable_splash = FALSE;
149 status->priv->total_ticks = 0;
150 status->priv->current_ticks = 0;
151 status->priv->splash = NULL;
152 status->priv->default_status_items =
153 g_hash_table_new_full (g_str_hash, g_str_equal,
154 g_free, g_free);
157 static void
158 anjuta_status_class_init (AnjutaStatusClass *class)
160 GObjectClass *object_class;
162 parent_class = g_type_class_peek_parent (class);
163 object_class = (GObjectClass*) class;
164 object_class->finalize = anjuta_status_finalize;
165 object_class->dispose = anjuta_status_dispose;
167 status_signals[BUSY] =
168 g_signal_new ("busy",
169 ANJUTA_TYPE_STATUS,
170 G_SIGNAL_RUN_LAST,
171 G_STRUCT_OFFSET (AnjutaStatusClass, busy),
172 NULL, NULL,
173 g_cclosure_marshal_VOID__BOOLEAN,
174 G_TYPE_NONE, 1,
175 G_TYPE_BOOLEAN);
178 GtkWidget *
179 anjuta_status_new (void)
181 GtkWidget *status;
183 status = GTK_WIDGET (g_object_new (ANJUTA_TYPE_STATUS, NULL));
184 return status;
187 void
188 anjuta_status_set (AnjutaStatus *status, const gchar * mesg, ...)
190 gchar* message;
191 va_list args;
193 g_return_if_fail (ANJUTA_IS_STATUS (status));
194 g_return_if_fail (mesg != NULL);
196 va_start (args, mesg);
197 message = g_strdup_vprintf (mesg, args);
198 va_end (args);
199 gtk_statusbar_pop (GTK_STATUSBAR (status->priv->status_bar),
200 status->priv->status_message);
201 gtk_statusbar_push (GTK_STATUSBAR (status->priv->status_bar),
202 status->priv->status_message, message);
203 g_free(message);
206 void
207 anjuta_status_push (AnjutaStatus *status, const gchar * mesg, ...)
209 gchar* message;
210 va_list args;
211 guint value;
213 g_return_if_fail (ANJUTA_IS_STATUS (status));
214 g_return_if_fail (mesg != NULL);
216 va_start (args, mesg);
217 message = g_strdup_vprintf (mesg, args);
218 va_end (args);
220 value = gtk_statusbar_push (GTK_STATUSBAR (status->priv->status_bar),
221 status->priv->push_message, message);
222 status->priv->push_values = g_list_prepend (status->priv->push_values,
223 GUINT_TO_POINTER (value));
224 g_free(message);
227 void
228 anjuta_status_pop (AnjutaStatus *status)
230 g_return_if_fail (ANJUTA_IS_STATUS (status));
232 gtk_statusbar_pop (GTK_STATUSBAR (status->priv->status_bar),
233 status->priv->push_message);
235 status->priv->push_values = g_list_remove_link (status->priv->push_values,
236 status->priv->push_values);
239 void
240 anjuta_status_clear_stack (AnjutaStatus *status)
242 GList *l;
243 g_return_if_fail (ANJUTA_IS_STATUS (status));
245 for (l = status->priv->push_values; l != NULL; l = g_list_next (l))
247 guint value = GPOINTER_TO_UINT (l->data);
248 gtk_statusbar_remove (GTK_STATUSBAR (status->priv->status_bar),
249 status->priv->push_message, value);
251 g_list_free (status->priv->push_values);
252 status->priv->push_values = NULL;
255 static void
256 foreach_widget_set_cursor (gpointer widget, gpointer value, gpointer cursor)
258 if (GTK_WIDGET (widget)->window)
259 gdk_window_set_cursor (GTK_WIDGET (widget)->window, (GdkCursor*)cursor);
262 void
263 anjuta_status_busy_push (AnjutaStatus *status)
265 GtkWidget *top;
266 GdkCursor *cursor;
268 g_return_if_fail (ANJUTA_IS_STATUS (status));
270 top = gtk_widget_get_toplevel (GTK_WIDGET (status));
271 if (top == NULL)
272 return;
274 status->priv->busy_count++;
275 if (status->priv->busy_count > 1)
276 return;
277 cursor = gdk_cursor_new (GDK_WATCH);
278 if (GTK_WIDGET (top)->window)
279 gdk_window_set_cursor (GTK_WIDGET (top)->window, cursor);
280 if (status->priv->widgets)
281 g_hash_table_foreach (status->priv->widgets,
282 foreach_widget_set_cursor, cursor);
283 gdk_cursor_unref (cursor);
284 gdk_flush ();
285 g_signal_emit_by_name (G_OBJECT (status), "busy", TRUE);
288 void
289 anjuta_status_busy_pop (AnjutaStatus *status)
291 GtkWidget *top;
293 g_return_if_fail (ANJUTA_IS_STATUS (status));
295 top = gtk_widget_get_toplevel (GTK_WIDGET (status));
296 if (top == NULL)
297 return;
299 status->priv->busy_count--;
300 if (status->priv->busy_count > 0)
301 return;
303 status->priv->busy_count = 0;
304 if (GTK_WIDGET (top)->window)
305 gdk_window_set_cursor (GTK_WIDGET (top)->window, NULL);
306 if (status->priv->widgets)
307 g_hash_table_foreach (status->priv->widgets,
308 foreach_widget_set_cursor, NULL);
309 g_signal_emit_by_name (G_OBJECT (status), "busy", FALSE);
312 static void
313 foreach_hash (gpointer key, gpointer value, gpointer userdata)
315 GString *str = (GString*)(userdata);
316 const gchar *divider = ": ";
317 const gchar *separator = " ";
319 g_string_append (str, separator);
320 g_string_append (str, (const gchar*)key);
321 g_string_append (str, divider);
322 g_string_append (str, (const gchar*)value);
325 void
326 anjuta_status_set_default (AnjutaStatus *status, const gchar *label,
327 const gchar *value_format, ...)
329 GString *str;
330 gchar *status_str;
332 g_return_if_fail (ANJUTA_IS_STATUS (status));
333 g_return_if_fail (label != NULL);
335 if (value_format)
337 gchar* value;
338 va_list args;
340 va_start (args, value_format);
341 value = g_strdup_vprintf (value_format, args);
342 va_end (args);
343 g_hash_table_replace (status->priv->default_status_items,
344 g_strdup (label), value);
346 else
348 if (g_hash_table_lookup (status->priv->default_status_items, label))
350 g_hash_table_remove (status->priv->default_status_items, label);
354 /* Update default status */
355 str = g_string_new (NULL);
356 g_hash_table_foreach (status->priv->default_status_items, foreach_hash, str);
357 status_str = g_string_free (str, FALSE);
358 anjuta_status_set (status, status_str, NULL);
359 g_free (status_str);
362 static void
363 on_widget_destroy (AnjutaStatus *status, GObject *widget)
365 if (g_hash_table_lookup (status->priv->widgets, widget))
366 g_hash_table_remove (status->priv->widgets, widget);
369 void
370 anjuta_status_add_widget (AnjutaStatus *status, GtkWidget *widget)
372 g_return_if_fail (ANJUTA_IS_STATUS (status));
373 g_return_if_fail (GTK_IS_WIDGET (widget));
375 if (status->priv->widgets == NULL)
376 status->priv->widgets =
377 g_hash_table_new (g_direct_hash, g_direct_equal);
379 g_hash_table_insert (status->priv->widgets, widget, widget);
380 g_object_weak_ref (G_OBJECT (widget),
381 (GWeakNotify) (on_widget_destroy), status);
384 void
385 anjuta_status_set_splash (AnjutaStatus *status, const gchar *splash_file,
386 gint splash_progress_position)
388 g_return_if_fail (ANJUTA_IS_STATUS (status));
389 g_return_if_fail (splash_file != NULL);
390 g_return_if_fail (splash_progress_position >= 0);
391 if (status->priv->splash_file)
392 g_free (status->priv->splash_file);
393 status->priv->splash_file = g_strdup (splash_file);
394 status->priv->splash_progress_position = splash_progress_position;
397 void
398 anjuta_status_disable_splash (AnjutaStatus *status,
399 gboolean disable_splash)
401 g_return_if_fail (ANJUTA_IS_STATUS (status));
403 status->priv->disable_splash = disable_splash;
404 if (status->priv->splash)
406 gtk_widget_destroy (status->priv->splash);
407 status->priv->splash = NULL;
408 anjuta_status_progress_add_ticks (status, 0);
412 void
413 anjuta_status_progress_add_ticks (AnjutaStatus *status, gint ticks)
415 gfloat percentage;
417 g_return_if_fail (ANJUTA_IS_STATUS (status));
418 g_return_if_fail (ticks >= 0);
420 status->priv->total_ticks += ticks;
421 if (!GTK_WIDGET_REALIZED (status))
423 if (status->priv->splash == NULL &&
424 status->priv->splash_file &&
425 !status->priv->disable_splash)
427 status->priv->splash = e_splash_new (status->priv->splash_file, 100);
428 if (status->priv->splash)
429 gtk_widget_show (status->priv->splash);
432 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
433 if (status->priv->splash)
435 e_splash_set (E_SPLASH(status->priv->splash), NULL, NULL, NULL,
436 percentage);
437 while (g_main_context_iteration(NULL, FALSE));
439 else
441 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar),
442 percentage);
443 gtk_widget_queue_draw (GTK_WIDGET (status->priv->status_bar));
444 gtk_widget_queue_draw (GTK_WIDGET (status->priv->progress_bar));
445 if (GTK_WIDGET(status->priv->progress_bar)->window != NULL &&
446 GDK_IS_WINDOW(GTK_WIDGET(status->priv->progress_bar)->window))
447 gdk_window_process_updates (GTK_WIDGET(status->priv->progress_bar)->window, TRUE);
448 if (GTK_WIDGET(status->priv->status_bar)->window != NULL &&
449 GDK_IS_WINDOW(GTK_WIDGET(status->priv->status_bar)->window))
450 gdk_window_process_updates (GTK_WIDGET(status->priv->status_bar)->window, TRUE);
454 void
455 anjuta_status_progress_pulse (AnjutaStatus *status, const gchar *text)
457 GtkProgressBar *progressbar;
458 GtkWidget *statusbar;
460 progressbar = GTK_PROGRESS_BAR (status->priv->progress_bar);
461 statusbar = status->priv->status_bar;
463 if (text)
464 anjuta_status_set (status, "%s", text);
466 gtk_progress_bar_pulse (progressbar);
468 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
469 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
470 if (GTK_WIDGET(progressbar)->window != NULL &&
471 GDK_IS_WINDOW(GTK_WIDGET(progressbar)->window))
472 gdk_window_process_updates (GTK_WIDGET(progressbar)->window, TRUE);
473 if (GTK_WIDGET(statusbar)->window != NULL &&
474 GDK_IS_WINDOW(GTK_WIDGET(statusbar)->window))
475 gdk_window_process_updates (GTK_WIDGET(statusbar)->window, TRUE);
478 void
479 anjuta_status_progress_tick (AnjutaStatus *status,
480 GdkPixbuf *icon, const gchar *text)
482 gfloat percentage;
484 g_return_if_fail (ANJUTA_IS_STATUS (status));
485 g_return_if_fail (status->priv->total_ticks != 0);
487 status->priv->current_ticks++;
488 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
490 if (status->priv->splash)
492 e_splash_set (E_SPLASH(status->priv->splash), icon, text, NULL, percentage);
493 while (g_main_context_iteration(NULL, FALSE));
495 else
497 GtkProgressBar *progressbar;
498 GtkWidget *statusbar;
500 if (text)
501 anjuta_status_set (status, "%s", text);
502 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar),
503 percentage);
504 progressbar = GTK_PROGRESS_BAR (status->priv->progress_bar);
505 statusbar = status->priv->status_bar;
506 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
507 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
508 if (GTK_WIDGET(progressbar)->window != NULL &&
509 GDK_IS_WINDOW(GTK_WIDGET(progressbar)->window))
510 gdk_window_process_updates (GTK_WIDGET(progressbar)->window, TRUE);
511 if (GTK_WIDGET(statusbar)->window != NULL &&
512 GDK_IS_WINDOW(GTK_WIDGET(statusbar)->window))
513 gdk_window_process_updates (GTK_WIDGET(statusbar)->window, TRUE);
515 if (status->priv->current_ticks >= status->priv->total_ticks)
516 anjuta_status_progress_reset (status);
519 void
520 anjuta_status_progress_increment_ticks (AnjutaStatus *status, gint ticks,
521 const gchar *text)
523 gfloat percentage;
525 g_return_if_fail (ANJUTA_IS_STATUS (status));
526 g_return_if_fail (status->priv->total_ticks != 0);
528 status->priv->current_ticks += ticks;
529 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
531 GtkProgressBar *progressbar;
532 GtkWidget *statusbar;
534 if (text)
535 anjuta_status_set (status, "%s", text);
536 gnome_appbar_set_progress_percentage (GNOME_APPBAR (status),
537 percentage);
538 progressbar = gnome_appbar_get_progress (GNOME_APPBAR (status));
539 statusbar = gnome_appbar_get_status (GNOME_APPBAR (status));
540 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
541 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
542 if (GTK_WIDGET(progressbar)->window != NULL &&
543 GDK_IS_WINDOW(GTK_WIDGET(progressbar)->window))
544 gdk_window_process_updates (GTK_WIDGET(progressbar)->window, TRUE);
545 if (GTK_WIDGET(statusbar)->window != NULL &&
546 GDK_IS_WINDOW(GTK_WIDGET(statusbar)->window))
547 gdk_window_process_updates (GTK_WIDGET(statusbar)->window, TRUE);
549 if (status->priv->current_ticks >= status->priv->total_ticks)
550 anjuta_status_progress_reset (status);
553 void
554 anjuta_status_progress_reset (AnjutaStatus *status)
556 g_return_if_fail (ANJUTA_IS_STATUS (status));
558 if (status->priv->splash)
560 gtk_widget_destroy (status->priv->splash);
561 status->priv->splash = NULL;
563 status->priv->current_ticks = 0;
564 status->priv->total_ticks = 0;
565 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar), 0);
566 anjuta_status_clear_stack (status);
569 static gboolean
570 anjuta_status_timeout (AnjutaStatus *status)
572 anjuta_status_pop (status);
573 return FALSE;
576 /* Display message in status until timeout (secondes) */
577 void
578 anjuta_status (AnjutaStatus *status, const gchar *mesg, gint timeout)
580 g_return_if_fail (ANJUTA_IS_STATUS (status));
581 g_return_if_fail (mesg != NULL);
582 anjuta_status_push (status, "%s", mesg);
583 g_timeout_add (timeout * 1000, (void*) anjuta_status_timeout, status);
586 void
587 anjuta_status_set_title_window (AnjutaStatus *status, GtkWidget *window)
589 g_return_if_fail (ANJUTA_IS_STATUS (status));
590 g_return_if_fail (GTK_IS_WINDOW (window));
591 status->priv->window = GTK_WINDOW (window);
592 g_object_add_weak_pointer (G_OBJECT (window),
593 (gpointer*)(gpointer)&status->priv->window);
596 void
597 anjuta_status_set_title (AnjutaStatus *status, const gchar *title)
599 g_return_if_fail (ANJUTA_IS_STATUS (status));
601 if (!status->priv->window)
602 return;
604 const gchar *app_name = g_get_application_name();
605 if (title)
607 gchar* str = g_strconcat (title, " - ", app_name, NULL);
608 gtk_window_set_title (status->priv->window, str);
609 g_free (str);
611 else
613 gtk_window_set_title (status->priv->window, app_name);
617 ANJUTA_TYPE_BEGIN(AnjutaStatus, anjuta_status, GTK_TYPE_HBOX);
618 ANJUTA_TYPE_END;