Updated Makefile.am files after make -f git.mk
[anjuta.git] / libanjuta / anjuta-status.c
blob9500b4da13438ff15528089691f992bed688aeb3
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/gtk.h>
32 #include <libanjuta/anjuta-status.h>
33 #include <libanjuta/anjuta-utils.h>
34 #include <libanjuta/anjuta-debug.h>
35 #include <libanjuta/resources.h>
36 #include <libanjuta/e-splash.h>
38 struct _AnjutaStatusPriv
40 GHashTable *default_status_items;
41 gint busy_count;
42 GHashTable *widgets;
44 /* Status bar */
45 GtkWidget *status_bar;
46 guint status_message;
47 guint push_message;
48 GList *push_values;
50 /* Progress bar */
51 GtkWidget *progress_bar;
52 gint total_ticks;
53 gint current_ticks;
55 /* Splash */
56 GtkWidget *splash;
57 gboolean disable_splash;
58 gchar *splash_file;
59 gint splash_progress_position;
61 /* Title window */
62 GtkWindow *window;
65 enum {
66 BUSY,
67 LAST_SIGNAL
70 static gpointer parent_class = NULL;
71 static guint status_signals[LAST_SIGNAL] = { 0 };
73 static void on_widget_destroy (AnjutaStatus *status, GObject *widget);
75 static void
76 anjuta_status_finalize (GObject *widget)
78 g_free(ANJUTA_STATUS(widget)->priv);
79 G_OBJECT_CLASS (parent_class)->finalize (widget);
82 static void
83 foreach_widget_unref (gpointer key, gpointer value, gpointer data)
85 g_object_weak_unref (G_OBJECT (key), (GWeakNotify) on_widget_destroy, data);
88 static void
89 anjuta_status_dispose (GObject *widget)
91 AnjutaStatus *status;
93 status = ANJUTA_STATUS (widget);
95 if (status->priv->default_status_items)
97 g_hash_table_destroy (status->priv->default_status_items);
98 status->priv->default_status_items = NULL;
100 if (status->priv->splash != NULL) {
101 gtk_widget_destroy (status->priv->splash);
102 status->priv->splash = NULL;
104 if (status->priv->splash_file)
106 g_free (status->priv->splash_file);
107 status->priv->splash_file = NULL;
109 if (status->priv->push_values)
111 g_list_free (status->priv->push_values);
112 status->priv->push_values = NULL;
114 if (status->priv->widgets)
116 g_hash_table_foreach (status->priv->widgets,
117 foreach_widget_unref, widget);
118 g_hash_table_destroy (status->priv->widgets);
119 status->priv->widgets = NULL;
121 if (status->priv->window)
123 g_object_remove_weak_pointer (G_OBJECT (status->priv->window),
124 (gpointer*)(gpointer)&status->priv->window);
125 status->priv->window = NULL;
127 if (status->priv->progress_bar)
129 g_object_remove_weak_pointer (G_OBJECT (status->priv->progress_bar),
130 (gpointer)&status->priv->progress_bar);
131 gtk_widget_destroy (status->priv->progress_bar);
132 status->priv->progress_bar = NULL;
134 if (status->priv->status_bar)
136 g_object_remove_weak_pointer (G_OBJECT (status->priv->status_bar),
137 (gpointer)&status->priv->status_bar);
138 gtk_widget_destroy (status->priv->status_bar);
139 status->priv->status_bar = NULL;
142 G_OBJECT_CLASS (parent_class)->dispose (widget);
145 static void
146 anjuta_status_instance_init (AnjutaStatus *status)
148 status->priv = g_new0 (AnjutaStatusPriv, 1);
149 status->priv->progress_bar = gtk_progress_bar_new ();
150 gtk_box_pack_start (GTK_BOX (status), status->priv->progress_bar, FALSE, TRUE, 0);
151 gtk_widget_show (status->priv->progress_bar);
152 g_object_add_weak_pointer (G_OBJECT (status->priv->progress_bar),
153 (gpointer)&status->priv->progress_bar);
154 status->priv->status_bar = gtk_statusbar_new ();
155 gtk_box_pack_start (GTK_BOX (status), status->priv->status_bar, TRUE, TRUE, 0);
156 gtk_widget_show (status->priv->status_bar);
157 g_object_add_weak_pointer (G_OBJECT(status->priv->status_bar),
158 (gpointer)&status->priv->status_bar);
159 status->priv->status_message = gtk_statusbar_get_context_id (GTK_STATUSBAR (status->priv->status_bar),
160 "status-message");
161 status->priv->push_message = gtk_statusbar_get_context_id (GTK_STATUSBAR (status->priv->status_bar),
162 "push-message");
163 status->priv->push_values = NULL;
164 status->priv->splash_file = NULL;
165 status->priv->splash_progress_position = 0;
166 status->priv->disable_splash = FALSE;
167 status->priv->total_ticks = 0;
168 status->priv->current_ticks = 0;
169 status->priv->splash = NULL;
170 status->priv->default_status_items =
171 g_hash_table_new_full (g_str_hash, g_str_equal,
172 g_free, g_free);
175 static void
176 anjuta_status_class_init (AnjutaStatusClass *class)
178 GObjectClass *object_class;
180 parent_class = g_type_class_peek_parent (class);
181 object_class = (GObjectClass*) class;
182 object_class->finalize = anjuta_status_finalize;
183 object_class->dispose = anjuta_status_dispose;
185 status_signals[BUSY] =
186 g_signal_new ("busy",
187 ANJUTA_TYPE_STATUS,
188 G_SIGNAL_RUN_LAST,
189 G_STRUCT_OFFSET (AnjutaStatusClass, busy),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__BOOLEAN,
192 G_TYPE_NONE, 1,
193 G_TYPE_BOOLEAN);
196 GtkWidget *
197 anjuta_status_new (void)
199 GtkWidget *status;
201 status = GTK_WIDGET (g_object_new (ANJUTA_TYPE_STATUS, NULL));
202 return status;
205 void
206 anjuta_status_set (AnjutaStatus *status, const gchar * mesg, ...)
208 gchar* message;
209 va_list args;
211 g_return_if_fail (ANJUTA_IS_STATUS (status));
212 g_return_if_fail (mesg != NULL);
214 va_start (args, mesg);
215 message = g_strdup_vprintf (mesg, args);
216 va_end (args);
217 gtk_statusbar_pop (GTK_STATUSBAR (status->priv->status_bar),
218 status->priv->status_message);
219 gtk_statusbar_push (GTK_STATUSBAR (status->priv->status_bar),
220 status->priv->status_message, message);
221 g_free(message);
224 void
225 anjuta_status_push (AnjutaStatus *status, const gchar * mesg, ...)
227 gchar* message;
228 va_list args;
229 guint value;
231 g_return_if_fail (ANJUTA_IS_STATUS (status));
232 g_return_if_fail (mesg != NULL);
234 va_start (args, mesg);
235 message = g_strdup_vprintf (mesg, args);
236 va_end (args);
238 value = gtk_statusbar_push (GTK_STATUSBAR (status->priv->status_bar),
239 status->priv->push_message, message);
240 status->priv->push_values = g_list_prepend (status->priv->push_values,
241 GUINT_TO_POINTER (value));
242 g_free(message);
245 void
246 anjuta_status_pop (AnjutaStatus *status)
248 g_return_if_fail (ANJUTA_IS_STATUS (status));
250 /* This can be called on a time out when the status object is destroyed */
251 if (status->priv->status_bar != NULL)
253 gtk_statusbar_pop (GTK_STATUSBAR (status->priv->status_bar),
254 status->priv->push_message);
257 status->priv->push_values = g_list_remove_link (status->priv->push_values,
258 status->priv->push_values);
261 void
262 anjuta_status_clear_stack (AnjutaStatus *status)
264 GList *l;
265 g_return_if_fail (ANJUTA_IS_STATUS (status));
267 for (l = status->priv->push_values; l != NULL; l = g_list_next (l))
269 guint value = GPOINTER_TO_UINT (l->data);
270 gtk_statusbar_remove (GTK_STATUSBAR (status->priv->status_bar),
271 status->priv->push_message, value);
273 g_list_free (status->priv->push_values);
274 status->priv->push_values = NULL;
277 static void
278 foreach_widget_set_cursor (gpointer widget, gpointer value, gpointer cursor)
280 GdkWindow *window;
282 window = gtk_widget_get_window (widget);
283 if (window)
284 gdk_window_set_cursor (window, (GdkCursor*)cursor);
287 void
288 anjuta_status_busy_push (AnjutaStatus *status)
290 GtkWidget *top;
291 GdkCursor *cursor;
292 GdkWindow *window;
293 GdkDisplay *display;
295 g_return_if_fail (ANJUTA_IS_STATUS (status));
297 top = gtk_widget_get_toplevel (GTK_WIDGET (status));
298 if (top == NULL)
299 return;
301 status->priv->busy_count++;
303 DEBUG_PRINT ("Busy status: %d", status->priv->busy_count);
305 if (status->priv->busy_count > 1)
306 return;
307 display = gtk_widget_get_display (top);
308 cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
309 window = gtk_widget_get_window (top);
310 if (window)
311 gdk_window_set_cursor (window, cursor);
312 if (status->priv->widgets)
313 g_hash_table_foreach (status->priv->widgets,
314 foreach_widget_set_cursor, cursor);
315 g_object_unref (cursor);
316 gdk_flush ();
317 g_signal_emit_by_name (G_OBJECT (status), "busy", TRUE);
320 void
321 anjuta_status_busy_pop (AnjutaStatus *status)
323 GtkWidget *top;
324 GdkWindow *window;
326 g_return_if_fail (ANJUTA_IS_STATUS (status));
328 top = gtk_widget_get_toplevel (GTK_WIDGET (status));
329 if (top == NULL)
330 return;
332 status->priv->busy_count--;
333 DEBUG_PRINT ("Busy status: %d", status->priv->busy_count);
335 if (status->priv->busy_count > 0)
336 return;
338 status->priv->busy_count = 0;
339 window = gtk_widget_get_window (top);
340 if (window)
341 gdk_window_set_cursor (window, NULL);
342 if (status->priv->widgets)
343 g_hash_table_foreach (status->priv->widgets,
344 foreach_widget_set_cursor, NULL);
345 g_signal_emit_by_name (G_OBJECT (status), "busy", FALSE);
348 static void
349 foreach_hash (gpointer key, gpointer value, gpointer userdata)
351 GString *str = (GString*)(userdata);
352 const gchar *divider = ": ";
353 const gchar *separator = " ";
355 g_string_append (str, separator);
356 g_string_append (str, (const gchar*)key);
357 g_string_append (str, divider);
358 g_string_append (str, (const gchar*)value);
361 void
362 anjuta_status_set_default (AnjutaStatus *status, const gchar *label,
363 const gchar *value_format, ...)
365 GString *str;
366 gchar *status_str;
368 g_return_if_fail (ANJUTA_IS_STATUS (status));
369 g_return_if_fail (label != NULL);
371 if (value_format)
373 gchar* value;
374 va_list args;
376 va_start (args, value_format);
377 value = g_strdup_vprintf (value_format, args);
378 va_end (args);
379 g_hash_table_replace (status->priv->default_status_items,
380 g_strdup (label), value);
382 else
384 if (g_hash_table_lookup (status->priv->default_status_items, label))
386 g_hash_table_remove (status->priv->default_status_items, label);
390 /* Update default status */
391 str = g_string_new (NULL);
392 g_hash_table_foreach (status->priv->default_status_items, foreach_hash, str);
393 status_str = g_string_free (str, FALSE);
394 anjuta_status_set (status, status_str, NULL);
395 g_free (status_str);
398 static void
399 on_widget_destroy (AnjutaStatus *status, GObject *widget)
401 if (g_hash_table_lookup (status->priv->widgets, widget))
402 g_hash_table_remove (status->priv->widgets, widget);
405 void
406 anjuta_status_add_widget (AnjutaStatus *status, GtkWidget *widget)
408 g_return_if_fail (ANJUTA_IS_STATUS (status));
409 g_return_if_fail (GTK_IS_WIDGET (widget));
411 if (status->priv->widgets == NULL)
412 status->priv->widgets =
413 g_hash_table_new (g_direct_hash, g_direct_equal);
415 g_hash_table_insert (status->priv->widgets, widget, widget);
416 g_object_weak_ref (G_OBJECT (widget),
417 (GWeakNotify) (on_widget_destroy), status);
420 void
421 anjuta_status_set_splash (AnjutaStatus *status, const gchar *splash_file,
422 gint splash_progress_position)
424 g_return_if_fail (ANJUTA_IS_STATUS (status));
425 g_return_if_fail (splash_file != NULL);
426 g_return_if_fail (splash_progress_position >= 0);
427 if (status->priv->splash_file)
428 g_free (status->priv->splash_file);
429 status->priv->splash_file = g_strdup (splash_file);
430 status->priv->splash_progress_position = splash_progress_position;
433 void
434 anjuta_status_disable_splash (AnjutaStatus *status,
435 gboolean disable_splash)
437 g_return_if_fail (ANJUTA_IS_STATUS (status));
439 status->priv->disable_splash = disable_splash;
440 if (status->priv->splash)
442 gtk_widget_destroy (status->priv->splash);
443 status->priv->splash = NULL;
444 anjuta_status_progress_add_ticks (status, 0);
448 void
449 anjuta_status_progress_add_ticks (AnjutaStatus *status, gint ticks)
451 gfloat percentage;
453 g_return_if_fail (ANJUTA_IS_STATUS (status));
454 g_return_if_fail (ticks >= 0);
456 status->priv->total_ticks += ticks;
457 if (!gtk_widget_get_realized (GTK_WIDGET (status)))
459 if (status->priv->splash == NULL &&
460 status->priv->splash_file &&
461 !status->priv->disable_splash)
463 status->priv->splash = e_splash_new (status->priv->splash_file, 100);
464 if (status->priv->splash)
465 gtk_widget_show (status->priv->splash);
468 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
469 if (status->priv->splash)
471 e_splash_set (E_SPLASH(status->priv->splash), NULL, NULL, NULL,
472 percentage);
473 while (g_main_context_iteration(NULL, FALSE));
475 else
477 if (status->priv->progress_bar && status->priv->status_bar)
479 GdkWindow *progressbar_window, *statusbar_window;
481 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar),
482 percentage);
483 gtk_widget_queue_draw (GTK_WIDGET (status->priv->status_bar));
484 gtk_widget_queue_draw (GTK_WIDGET (status->priv->progress_bar));
485 progressbar_window = gtk_widget_get_window (GTK_WIDGET(status->priv->progress_bar));
486 statusbar_window = gtk_widget_get_window (GTK_WIDGET(status->priv->status_bar));
487 if (progressbar_window != NULL)
488 gdk_window_process_updates (progressbar_window, TRUE);
489 if (statusbar_window != NULL)
490 gdk_window_process_updates (statusbar_window, TRUE);
495 void
496 anjuta_status_progress_pulse (AnjutaStatus *status, const gchar *text)
498 GtkProgressBar *progressbar;
499 GtkWidget *statusbar;
500 GdkWindow *progressbar_window, *statusbar_window;
502 progressbar = GTK_PROGRESS_BAR (status->priv->progress_bar);
503 statusbar = status->priv->status_bar;
505 if (text)
506 anjuta_status_push (status, "%s", text);
508 gtk_progress_bar_pulse (progressbar);
510 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
511 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
512 progressbar_window = gtk_widget_get_window (GTK_WIDGET (progressbar));
513 if (progressbar_window != NULL)
514 gdk_window_process_updates (progressbar_window, TRUE);
515 statusbar_window = gtk_widget_get_window (GTK_WIDGET (statusbar));
516 if (statusbar_window != NULL)
517 gdk_window_process_updates (statusbar_window, TRUE);
520 void
521 anjuta_status_progress_tick (AnjutaStatus *status,
522 GdkPixbuf *icon, const gchar *text)
524 gfloat percentage;
526 g_return_if_fail (ANJUTA_IS_STATUS (status));
527 g_return_if_fail (status->priv->total_ticks != 0);
529 status->priv->current_ticks++;
530 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
532 if (status->priv->splash)
534 e_splash_set (E_SPLASH(status->priv->splash), icon, text, NULL, percentage);
536 else
538 GtkProgressBar *progressbar;
539 GtkWidget *statusbar;
540 GdkWindow *progressbar_window, *statusbar_window;
542 if (text)
543 anjuta_status_set (status, "%s", text);
544 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar),
545 percentage);
546 progressbar = GTK_PROGRESS_BAR (status->priv->progress_bar);
547 statusbar = status->priv->status_bar;
548 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
549 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
550 progressbar_window = gtk_widget_get_window (GTK_WIDGET (progressbar));
551 if (progressbar_window != NULL)
552 gdk_window_process_updates (progressbar_window, TRUE);
553 statusbar_window = gtk_widget_get_window (GTK_WIDGET (statusbar));
554 if (statusbar_window != NULL)
555 gdk_window_process_updates (statusbar_window, TRUE);
557 if (status->priv->current_ticks >= status->priv->total_ticks)
558 anjuta_status_progress_reset (status);
561 void
562 anjuta_status_progress_increment_ticks (AnjutaStatus *status, gint ticks,
563 const gchar *text)
565 gfloat percentage;
566 GdkWindow *progressbar_window, *statusbar_window;
568 g_return_if_fail (ANJUTA_IS_STATUS (status));
569 g_return_if_fail (status->priv->total_ticks != 0);
571 status->priv->current_ticks += ticks;
572 percentage = ((gfloat)status->priv->current_ticks)/status->priv->total_ticks;
574 GtkProgressBar *progressbar;
575 GtkWidget *statusbar;
577 if (text)
578 anjuta_status_set (status, "%s", text);
579 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar),
580 percentage);
581 progressbar = GTK_PROGRESS_BAR (status->priv->progress_bar);
582 statusbar = status->priv->status_bar;
583 gtk_widget_queue_draw (GTK_WIDGET (statusbar));
584 gtk_widget_queue_draw (GTK_WIDGET (progressbar));
585 progressbar_window = gtk_widget_get_window (GTK_WIDGET(progressbar));
586 if (progressbar_window != NULL)
587 gdk_window_process_updates (progressbar_window, TRUE);
588 statusbar_window = gtk_widget_get_window (GTK_WIDGET(statusbar));
589 if (statusbar_window != NULL)
590 gdk_window_process_updates (statusbar_window, TRUE);
592 if (status->priv->current_ticks >= status->priv->total_ticks)
593 anjuta_status_progress_reset (status);
596 void
597 anjuta_status_progress_reset (AnjutaStatus *status)
599 g_return_if_fail (ANJUTA_IS_STATUS (status));
601 if (status->priv->splash)
603 gtk_widget_destroy (status->priv->splash);
604 status->priv->splash = NULL;
606 status->priv->current_ticks = 0;
607 status->priv->total_ticks = 0;
608 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status->priv->progress_bar), 0);
609 anjuta_status_clear_stack (status);
612 static gboolean
613 anjuta_status_timeout (AnjutaStatus *status)
615 anjuta_status_pop (status);
616 g_object_unref (status);
618 return FALSE;
622 * anjuta_status: (skip)
623 * Display message in status until timeout (seconds)
625 void
626 anjuta_status (AnjutaStatus *status, const gchar *mesg, gint timeout)
628 g_return_if_fail (ANJUTA_IS_STATUS (status));
629 g_return_if_fail (mesg != NULL);
630 anjuta_status_push (status, "%s", mesg);
631 g_timeout_add_seconds (timeout, (void*) anjuta_status_timeout, g_object_ref (status));
634 void
635 anjuta_status_set_title_window (AnjutaStatus *status, GtkWidget *window)
637 g_return_if_fail (ANJUTA_IS_STATUS (status));
638 g_return_if_fail (GTK_IS_WINDOW (window));
639 status->priv->window = GTK_WINDOW (window);
640 g_object_add_weak_pointer (G_OBJECT (window),
641 (gpointer*)(gpointer)&status->priv->window);
644 void
645 anjuta_status_set_title (AnjutaStatus *status, const gchar *title)
647 g_return_if_fail (ANJUTA_IS_STATUS (status));
649 if (!status->priv->window)
650 return;
652 const gchar *app_name = g_get_application_name();
653 if (title)
655 gchar* str = g_strconcat (title, " - ", app_name, NULL);
656 gtk_window_set_title (status->priv->window, str);
657 g_free (str);
659 else
661 gtk_window_set_title (status->priv->window, app_name);
665 ANJUTA_TYPE_BEGIN(AnjutaStatus, anjuta_status, GTK_TYPE_BOX);
666 ANJUTA_TYPE_END;