'smart qotes' now will replace '<', '>' and '&' inside 'pre' and 'code' tags
[k8lowj.git] / src / progress.c
blob08b381c07d806dcaeccbb6f2a63558a17be62701
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "gtk-all.h"
9 #include "util.h"
10 #include "throbber.h"
11 #include "progress.h"
13 struct _ProgressWindow {
14 GtkWindow win;
15 GtkWidget *parent, *box, *clientbox;
16 GtkWidget *titlelabel, *label, *progress;
17 gboolean showing_error;
18 GtkWidget *throbber;
20 ProgressWindowCancelFunc cancel_cb;
21 gpointer cancel_cb_data;
24 void
25 progress_window_show_error(ProgressWindow *pw, const char *fmt, ...) {
26 char buf[1024];
27 va_list ap;
29 va_start(ap, fmt);
30 g_vsnprintf(buf, 1024, fmt, ap);
31 va_end(ap);
33 if (pw) {
34 progress_window_set_title(pw, _("Error"));
35 gtk_label_set_text(GTK_LABEL(pw->label), buf);
37 throbber_stop(THROBBER(pw->throbber));
38 gtk_image_set_from_stock(GTK_IMAGE(pw->throbber),
39 GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
40 gtk_widget_hide(pw->progress);
41 if (pw->clientbox) gtk_widget_hide(pw->clientbox);
42 pw->showing_error = TRUE;
43 gtk_main();
44 } else {
45 g_print(_("Error: %s\n"), buf);
49 static void
50 cancel_cb(ProgressWindow *pw) {
51 if (pw->showing_error)
52 gtk_main_quit();
53 else if (pw->cancel_cb)
54 pw->cancel_cb(pw->cancel_cb_data);
57 static void
58 destroy_cb(GtkWidget *w, ProgressWindow *pw) {
59 throbber_stop(THROBBER(pw->throbber));
60 if (pw->parent)
61 g_signal_handlers_disconnect_matched(pw->parent,
62 G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, pw);
65 static gboolean
66 delete_event_cb(GtkWidget *w, GdkEvent *e, ProgressWindow *pw) {
67 cancel_cb(pw);
68 return TRUE; /* don't destroy us. */
71 static void
72 reposition(ProgressWindow *pw, gint w, gint h) {
73 gint ox, oy, px, py, x, y;
75 if (!pw->parent)
76 return;
77 gdk_window_get_origin(pw->parent->window, &px, &py);
78 if (w == -1)
79 w = GTK_WIDGET(pw)->allocation.width;
80 if (h == -1)
81 h = GTK_WIDGET(pw)->allocation.height;
82 x = px + (pw->parent->allocation.width - w) / 2;
83 y = py + (pw->parent->allocation.height - h) / 2;
85 gdk_window_get_origin(GTK_WIDGET(pw)->window, &ox, &oy);
86 if (x != ox || y != oy) {
87 gtk_window_move(GTK_WINDOW(pw), x, y);
91 static gboolean
92 parent_configure_cb(GtkWidget *w, GdkEvent *e, ProgressWindow *pw) {
93 reposition(pw, -1, -1);
94 return FALSE;
97 static gboolean
98 configure_cb(GtkWidget *w, GdkEventConfigure *e, ProgressWindow *pw) {
99 if (GTK_WIDGET(pw)->allocation.width != e->width ||
100 GTK_WIDGET(pw)->allocation.height != e->height)
101 reposition(pw, e->width, e->height);
102 return FALSE;
106 static void
107 progress_window_set_parent(ProgressWindow *pw, GtkWindow *parent) {
108 pw->parent = GTK_WIDGET(parent);
109 gtk_window_set_transient_for(GTK_WINDOW(pw), parent);
110 g_signal_connect(G_OBJECT(parent), "configure-event",
111 G_CALLBACK(parent_configure_cb), pw);
114 static void
115 progress_window_init(ProgressWindow *pw) {
116 GtkWidget *frame;
117 GtkWidget *vbox;
118 GtkWidget *hbox, *align, *bbox, *button, *lbox;
120 gtk_window_set_decorated(GTK_WINDOW(pw), FALSE);
121 gtk_window_set_type_hint(GTK_WINDOW(pw), GDK_WINDOW_TYPE_HINT_DIALOG);
122 gtk_window_set_modal(GTK_WINDOW(pw), TRUE);
123 gtk_window_set_default_size(GTK_WINDOW(pw), 250, -1);
124 g_signal_connect(G_OBJECT(pw), "destroy", G_CALLBACK(destroy_cb), pw);
125 g_signal_connect(G_OBJECT(pw), "delete-event",
126 G_CALLBACK(delete_event_cb), pw);
127 gtk_window_set_position(GTK_WINDOW(pw), GTK_WIN_POS_CENTER_ON_PARENT);
128 g_signal_connect(G_OBJECT(pw), "configure-event",
129 G_CALLBACK(configure_cb), pw);
131 vbox = gtk_vbox_new(FALSE, 6);
132 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
134 hbox = gtk_hbox_new(FALSE, 6);
136 pw->throbber = throbber_new();
137 align = gtk_alignment_new(0.5, 0, 0, 0);
138 gtk_container_add(GTK_CONTAINER(align), pw->throbber);
139 gtk_box_pack_start(GTK_BOX(hbox), align, FALSE, FALSE, 0);
140 throbber_start(THROBBER(pw->throbber));
142 pw->box = lbox = gtk_vbox_new(FALSE, 6);
143 pw->titlelabel = gtk_label_new(NULL);
144 gtk_box_pack_start(GTK_BOX(lbox), pw->titlelabel, TRUE, TRUE, 0);
146 pw->label = gtk_label_new(NULL);
147 gtk_label_set_line_wrap(GTK_LABEL(pw->label), TRUE);
148 gtk_box_pack_start(GTK_BOX(lbox), pw->label, TRUE, TRUE, 0);
150 pw->progress = gtk_progress_bar_new();
151 gtk_box_pack_end(GTK_BOX(lbox), pw->progress, FALSE, FALSE, 0);
153 gtk_box_pack_start(GTK_BOX(hbox), lbox, TRUE, TRUE, 0);
155 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
157 bbox = gtk_hbutton_box_new();
158 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
159 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
160 g_signal_connect_swapped(G_OBJECT(button), "clicked",
161 G_CALLBACK(cancel_cb), pw);
162 gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
163 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
165 frame = gtk_frame_new(NULL);
166 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
167 gtk_container_add(GTK_CONTAINER(frame), vbox);
168 gtk_widget_show_all(frame);
169 gtk_widget_hide(pw->progress);
170 gtk_container_add(GTK_CONTAINER(pw), frame);
172 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
173 gtk_widget_grab_default(button);
176 void
177 progress_window_pack(ProgressWindow *pw, GtkWidget *contents) {
178 if (!pw->clientbox) {
179 pw->clientbox = gtk_vbox_new(FALSE, 6);
180 gtk_box_pack_start(GTK_BOX(pw->box), pw->clientbox, TRUE, TRUE, 0);
181 gtk_widget_show(pw->clientbox);
184 gtk_box_pack_start(GTK_BOX(pw->clientbox), contents, FALSE, FALSE, 0);
187 void
188 progress_window_set_title(ProgressWindow *pw, const char *title) {
189 char *t;
190 gtk_window_set_title(GTK_WINDOW(pw), title);
191 t = title ? g_strdup_printf("<b>%s</b>", title) : g_strdup("");
192 gtk_label_set_markup(GTK_LABEL(pw->titlelabel), t);
193 g_free(t);
196 void
197 progress_window_set_text(ProgressWindow *pw, const char *text) {
198 gtk_label_set_text(GTK_LABEL(pw->label), text);
201 void
202 progress_window_set_progress(ProgressWindow *pw, float frac) {
203 if (frac >= 0)
204 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(pw->progress), frac);
206 if (frac > 0) {
207 gtk_widget_show(pw->progress);
208 }/* else {
209 gtk_widget_hide(pw->progress);
213 void progress_window_set_cancel_cb(ProgressWindow *pw,
214 ProgressWindowCancelFunc func, gpointer data) {
215 pw->cancel_cb = func;
216 pw->cancel_cb_data = data;
219 GtkWidget*
220 progress_window_new(GtkWindow *parent, const char *title) {
221 ProgressWindow *pw = PROGRESS_WINDOW(g_object_new(progress_window_get_type(), NULL));
222 if (parent)
223 progress_window_set_parent(pw, parent);
224 progress_window_set_title(pw, title);
225 return GTK_WIDGET(pw);
228 GType
229 progress_window_get_type(void) {
230 static GType pw_type = 0;
231 if (!pw_type) {
232 static const GTypeInfo pw_info = {
233 sizeof (GtkWindowClass),
234 NULL,
235 NULL,
236 NULL, /*(GClassInitFunc) progress_window_class_init,*/
237 NULL,
238 NULL,
239 sizeof (ProgressWindow),
241 (GInstanceInitFunc) progress_window_init,
243 pw_type = g_type_register_static(GTK_TYPE_WINDOW, "ProgressWindow",
244 &pw_info, 0);
246 return pw_type;