gimpstatusbar.c 45.4 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program Copyright (C) 1995
2
 * Spencer Kimball and Peter Mattis
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7 8 9 10 11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20 21
#include <string.h>

22
#include <gegl.h>
23 24
#include <gtk/gtk.h>

25
#include "libgimpbase/gimpbase.h"
26
#include "libgimpmath/gimpmath.h"
27 28
#include "libgimpwidgets/gimpwidgets.h"

29 30
#include "display-types.h"

31 32
#include "config/gimpdisplayconfig.h"

33
#include "core/gimpimage.h"
34
#include "core/gimpprogress.h"
35

36
#include "widgets/gimpwidgets-utils.h"
37

38
#include "gimpdisplay.h"
39
#include "gimpdisplayshell.h"
40
#include "gimpdisplayshell-scale.h"
41
#include "gimpimagewindow.h"
42
#include "gimpscalecombobox.h"
43 44
#include "gimpstatusbar.h"

45
#include "gimp-intl.h"
46 47


48 49 50
/*  maximal width of the string holding the cursor-coordinates  */
#define CURSOR_LEN        256

51 52 53
/*  the spacing of the hbox                                     */
#define HBOX_SPACING        1

54 55
/*  spacing between the icon and the statusbar label            */
#define ICON_SPACING        2
56

57
/*  timeout (in milliseconds) for temporary statusbar messages  */
58
#define MESSAGE_TIMEOUT  8000
59 60


61 62 63 64 65
typedef struct _GimpStatusbarMsg GimpStatusbarMsg;

struct _GimpStatusbarMsg
{
  guint  context_id;
66
  gchar *stock_id;
67
  gchar *text;
68 69
};

70

71
static void     gimp_statusbar_progress_iface_init (GimpProgressInterface *iface);
72

73
static void     gimp_statusbar_dispose            (GObject           *object);
74
static void     gimp_statusbar_finalize           (GObject           *object);
75

76
static void     gimp_statusbar_hbox_size_request  (GtkWidget         *widget,
77 78
                                                   GtkRequisition    *requisition,
                                                   GimpStatusbar     *statusbar);
79

80
static GimpProgress *
81 82 83 84 85 86 87 88 89 90
                gimp_statusbar_progress_start     (GimpProgress      *progress,
                                                   const gchar       *message,
                                                   gboolean           cancelable);
static void     gimp_statusbar_progress_end       (GimpProgress      *progress);
static gboolean gimp_statusbar_progress_is_active (GimpProgress      *progress);
static void     gimp_statusbar_progress_set_text  (GimpProgress      *progress,
                                                   const gchar       *message);
static void     gimp_statusbar_progress_set_value (GimpProgress      *progress,
                                                   gdouble            percentage);
static gdouble  gimp_statusbar_progress_get_value (GimpProgress      *progress);
Sven Neumann's avatar
Sven Neumann committed
91
static void     gimp_statusbar_progress_pulse     (GimpProgress      *progress);
92 93 94 95 96
static gboolean gimp_statusbar_progress_message   (GimpProgress      *progress,
                                                   Gimp              *gimp,
                                                   GimpMessageSeverity severity,
                                                   const gchar       *domain,
                                                   const gchar       *message);
97 98 99
static void     gimp_statusbar_progress_canceled  (GtkWidget         *button,
                                                   GimpStatusbar     *statusbar);

100
static gboolean gimp_statusbar_label_expose       (GtkWidget         *widget,
101 102 103
                                                   GdkEventExpose    *event,
                                                   GimpStatusbar     *statusbar);

104 105 106 107 108
static void     gimp_statusbar_update             (GimpStatusbar     *statusbar);
static void     gimp_statusbar_unit_changed       (GimpUnitComboBox  *combo,
                                                   GimpStatusbar     *statusbar);
static void     gimp_statusbar_scale_changed      (GimpScaleComboBox *combo,
                                                   GimpStatusbar     *statusbar);
109 110
static void     gimp_statusbar_scale_activated    (GimpScaleComboBox *combo,
                                                   GimpStatusbar     *statusbar);
111 112
static void     gimp_statusbar_shell_scaled       (GimpDisplayShell  *shell,
                                                   GimpStatusbar     *statusbar);
113 114 115
static void     gimp_statusbar_shell_status_notify(GimpDisplayShell  *shell,
                                                   const GParamSpec  *pspec,
                                                   GimpStatusbar     *statusbar);
116 117
static guint    gimp_statusbar_get_context_id     (GimpStatusbar     *statusbar,
                                                   const gchar       *context);
118
static gboolean gimp_statusbar_temp_timeout       (GimpStatusbar     *statusbar);
119

120 121
static void     gimp_statusbar_msg_free           (GimpStatusbarMsg  *msg);

122 123 124
static gchar *  gimp_statusbar_vprintf            (const gchar       *format,
                                                   va_list            args);

125

126
G_DEFINE_TYPE_WITH_CODE (GimpStatusbar, gimp_statusbar, GTK_TYPE_STATUSBAR,
127
                         G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS,
128
                                                gimp_statusbar_progress_iface_init))
129

130
#define parent_class gimp_statusbar_parent_class
131 132 133 134 135


static void
gimp_statusbar_class_init (GimpStatusbarClass *klass)
{
136
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
137

138 139
  object_class->dispose  = gimp_statusbar_dispose;
  object_class->finalize = gimp_statusbar_finalize;
140 141
}

142 143 144 145 146 147 148 149 150 151
static void
gimp_statusbar_progress_iface_init (GimpProgressInterface *iface)
{
  iface->start     = gimp_statusbar_progress_start;
  iface->end       = gimp_statusbar_progress_end;
  iface->is_active = gimp_statusbar_progress_is_active;
  iface->set_text  = gimp_statusbar_progress_set_text;
  iface->set_value = gimp_statusbar_progress_set_value;
  iface->get_value = gimp_statusbar_progress_get_value;
  iface->pulse     = gimp_statusbar_progress_pulse;
152
  iface->message   = gimp_statusbar_progress_message;
153 154
}

155 156 157
static void
gimp_statusbar_init (GimpStatusbar *statusbar)
{
158
  GtkWidget     *hbox;
159
  GtkWidget     *image;
160
  GimpUnitStore *store;
161
  GList         *children;
162

163 164 165 166 167 168 169 170
  statusbar->shell          = NULL;
  statusbar->messages       = NULL;
  statusbar->context_ids    = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                     g_free, NULL);
  statusbar->seq_context_id = 1;

  statusbar->temp_context_id =
    gimp_statusbar_get_context_id (statusbar, "gimp-statusbar-temp");
171

172 173 174
  statusbar->cursor_format_str[0]   = '\0';
  statusbar->cursor_format_str_f[0] = '\0';
  statusbar->length_format_str[0]   = '\0';
175

176
  statusbar->progress_active      = FALSE;
177
  statusbar->progress_shown       = FALSE;
178

179 180 181
  /*  remove the message label from the message area  */
  hbox = gtk_statusbar_get_message_area (GTK_STATUSBAR (statusbar));
  gtk_box_set_spacing (GTK_BOX (hbox), HBOX_SPACING);
182

183 184 185
  children = gtk_container_get_children (GTK_CONTAINER (hbox));
  statusbar->label = g_object_ref (children->data);
  g_list_free (children);
186

187
  gtk_container_remove (GTK_CONTAINER (hbox), statusbar->label);
188

189 190 191 192
  g_signal_connect (hbox, "size-request",
                    G_CALLBACK (gimp_statusbar_hbox_size_request),
                    statusbar);

193
  statusbar->cursor_label = gtk_label_new ("8888, 8888");
194
  gtk_misc_set_alignment (GTK_MISC (statusbar->cursor_label), 0.5, 0.5);
195
  gtk_box_pack_start (GTK_BOX (hbox), statusbar->cursor_label, FALSE, FALSE, 0);
196 197
  gtk_widget_show (statusbar->cursor_label);

198
  store = gimp_unit_store_new (2);
199
  statusbar->unit_combo = gimp_unit_combo_box_new_with_model (store);
200 201
  g_object_unref (store);

202
  gtk_widget_set_can_focus (statusbar->unit_combo, FALSE);
203
  g_object_set (statusbar->unit_combo, "focus-on-click", FALSE, NULL);
204
  gtk_box_pack_start (GTK_BOX (hbox), statusbar->unit_combo, FALSE, FALSE, 0);
205
  gtk_widget_show (statusbar->unit_combo);
206

207
  g_signal_connect (statusbar->unit_combo, "changed",
208 209 210
                    G_CALLBACK (gimp_statusbar_unit_changed),
                    statusbar);

211
  statusbar->scale_combo = gimp_scale_combo_box_new ();
212
  gtk_widget_set_can_focus (statusbar->scale_combo, FALSE);
213
  g_object_set (statusbar->scale_combo, "focus-on-click", FALSE, NULL);
214
  gtk_box_pack_start (GTK_BOX (hbox), statusbar->scale_combo, FALSE, FALSE, 0);
215 216 217 218 219 220
  gtk_widget_show (statusbar->scale_combo);

  g_signal_connect (statusbar->scale_combo, "changed",
                    G_CALLBACK (gimp_statusbar_scale_changed),
                    statusbar);

221 222 223 224
  g_signal_connect (statusbar->scale_combo, "entry-activated",
                    G_CALLBACK (gimp_statusbar_scale_activated),
                    statusbar);

225 226
  /*  put the label back into the message area  */
  gtk_box_pack_start (GTK_BOX (hbox), statusbar->label, TRUE, TRUE, 1);
227

228
  g_object_unref (statusbar->label);
229

230
  g_signal_connect_after (statusbar->label, "expose-event",
231
                          G_CALLBACK (gimp_statusbar_label_expose),
232
                          statusbar);
233

234 235 236 237 238 239 240 241
  statusbar->progressbar = g_object_new (GTK_TYPE_PROGRESS_BAR,
                                         "text-xalign", 0.0,
                                         "text-yalign", 0.5,
                                         "ellipsize",   PANGO_ELLIPSIZE_END,
                                         NULL);
  gtk_box_pack_start (GTK_BOX (hbox), statusbar->progressbar, TRUE, TRUE, 0);
  /*  don't show the progress bar  */

242
  statusbar->cancel_button = gtk_button_new ();
243
  gtk_widget_set_can_focus (statusbar->cancel_button, FALSE);
244 245
  gtk_button_set_relief (GTK_BUTTON (statusbar->cancel_button),
                         GTK_RELIEF_NONE);
246
  gtk_widget_set_sensitive (statusbar->cancel_button, FALSE);
247 248 249
  gtk_box_pack_start (GTK_BOX (hbox),
                      statusbar->cancel_button, FALSE, FALSE, 0);
  /*  don't show the cancel button  */
250

251 252 253 254
  image = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU);
  gtk_container_add (GTK_CONTAINER (statusbar->cancel_button), image);
  gtk_widget_show (image);

255 256 257 258 259
  g_signal_connect (statusbar->cancel_button, "clicked",
                    G_CALLBACK (gimp_statusbar_progress_canceled),
                    statusbar);
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273
static void
gimp_statusbar_dispose (GObject *object)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (object);

  if (statusbar->temp_timeout_id)
    {
      g_source_remove (statusbar->temp_timeout_id);
      statusbar->temp_timeout_id = 0;
    }

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

274
static void
275
gimp_statusbar_finalize (GObject *object)
276
{
277
  GimpStatusbar *statusbar = GIMP_STATUSBAR (object);
278

279 280 281 282 283 284
  if (statusbar->icon)
    {
      g_object_unref (statusbar->icon);
      statusbar->icon = NULL;
    }

285
  g_slist_foreach (statusbar->messages, (GFunc) gimp_statusbar_msg_free, NULL);
286 287
  g_slist_free (statusbar->messages);
  statusbar->messages = NULL;
288

289 290 291 292 293
  if (statusbar->context_ids)
    {
      g_hash_table_destroy (statusbar->context_ids);
      statusbar->context_ids = NULL;
    }
294

295
  G_OBJECT_CLASS (parent_class)->finalize (object);
296 297
}

298
static void
299 300 301
gimp_statusbar_hbox_size_request (GtkWidget      *widget,
                                  GtkRequisition *requisition,
                                  GimpStatusbar  *statusbar)
302
{
303 304
  GtkRequisition child_requisition;
  gint           width = 0;
305 306 307

  /*  also consider the children which can be invisible  */

308 309
  gtk_widget_size_request (statusbar->cursor_label, &child_requisition);
  width += child_requisition.width;
310
  requisition->height = MAX (requisition->height,
311
                             child_requisition.height);
312

313
  gtk_widget_size_request (statusbar->unit_combo, &child_requisition);
314
  width += child_requisition.width;
315
  requisition->height = MAX (requisition->height,
316
                             child_requisition.height);
317 318

  gtk_widget_size_request (statusbar->scale_combo, &child_requisition);
319
  width += child_requisition.width;
320
  requisition->height = MAX (requisition->height,
321
                             child_requisition.height);
322 323

  gtk_widget_size_request (statusbar->progressbar, &child_requisition);
324
  requisition->height = MAX (requisition->height,
325
                             child_requisition.height);
326 327

  gtk_widget_size_request (statusbar->cancel_button, &child_requisition);
328
  requisition->height = MAX (requisition->height,
329
                             child_requisition.height);
330

331
  requisition->width = MAX (requisition->width, width + 32);
332 333
}

334 335 336 337 338 339 340 341 342 343 344
static GimpProgress *
gimp_statusbar_progress_start (GimpProgress *progress,
                               const gchar  *message,
                               gboolean      cancelable)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (! statusbar->progress_active)
    {
      GtkWidget *bar = statusbar->progressbar;

345 346 347
      statusbar->progress_active = TRUE;
      statusbar->progress_value  = 0.0;

348
      gimp_statusbar_push (statusbar, "progress", NULL, "%s", message);
349 350 351
      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (bar), 0.0);
      gtk_widget_set_sensitive (statusbar->cancel_button, cancelable);

352
      if (cancelable)
353 354 355 356 357 358 359 360 361 362 363 364
        {
          if (message)
            {
              gchar *tooltip = g_strdup_printf (_("Cancel <i>%s</i>"), message);

              gimp_help_set_help_data_with_markup (statusbar->cancel_button,
                                                   tooltip, NULL);
              g_free (tooltip);
            }

          gtk_widget_show (statusbar->cancel_button);
        }
365

366
      gtk_widget_show (statusbar->progressbar);
367
      gtk_widget_hide (statusbar->label);
368 369 370 371

      /*  This call is needed so that the progress bar is drawn in the
       *  correct place. Probably due a bug in GTK+.
       */
372
      gtk_container_resize_children (GTK_CONTAINER (statusbar));
373

374
      if (! gtk_widget_get_visible (GTK_WIDGET (statusbar)))
375 376 377 378 379
        {
          gtk_widget_show (GTK_WIDGET (statusbar));
          statusbar->progress_shown = TRUE;
        }

380
      if (gtk_widget_is_drawable (bar))
381
        gdk_window_process_updates (gtk_widget_get_window (bar), TRUE);
382

383 384
      gimp_statusbar_override_window_title (statusbar);

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
      return progress;
    }

  return NULL;
}

static void
gimp_statusbar_progress_end (GimpProgress *progress)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (statusbar->progress_active)
    {
      GtkWidget *bar = statusbar->progressbar;

400 401 402 403 404 405
      if (statusbar->progress_shown)
        {
          gtk_widget_hide (GTK_WIDGET (statusbar));
          statusbar->progress_shown = FALSE;
        }

406
      statusbar->progress_active = FALSE;
407
      statusbar->progress_value  = 0.0;
408

409
      gtk_widget_hide (bar);
410
      gtk_widget_show (statusbar->label);
411

412
      gimp_statusbar_pop (statusbar, "progress");
413

414 415
      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (bar), 0.0);
      gtk_widget_set_sensitive (statusbar->cancel_button, FALSE);
416
      gtk_widget_hide (statusbar->cancel_button);
417 418

      gimp_statusbar_restore_window_title (statusbar);
419 420 421
    }
}

422 423 424 425 426 427 428 429
static gboolean
gimp_statusbar_progress_is_active (GimpProgress *progress)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  return statusbar->progress_active;
}

430 431 432 433 434 435 436 437
static void
gimp_statusbar_progress_set_text (GimpProgress *progress,
                                  const gchar  *message)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (statusbar->progress_active)
    {
438 439
      GtkWidget *bar = statusbar->progressbar;

440
      gimp_statusbar_replace (statusbar, "progress", NULL, "%s", message);
441

442
      if (gtk_widget_is_drawable (bar))
443
        gdk_window_process_updates (gtk_widget_get_window (bar), TRUE);
444 445

      gimp_statusbar_override_window_title (statusbar);
446 447 448 449 450 451 452 453 454 455 456
    }
}

static void
gimp_statusbar_progress_set_value (GimpProgress *progress,
                                   gdouble       percentage)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (statusbar->progress_active)
    {
457 458 459 460
      GtkWidget     *bar = statusbar->progressbar;
      GtkAllocation  allocation;

      gtk_widget_get_allocation (bar, &allocation);
461

462
      statusbar->progress_value = percentage;
463

464
      /* only update the progress bar if this causes a visible change */
465
      if (fabs (allocation.width *
466 467 468 469 470
                (percentage -
                 gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (bar)))) > 1.0)
        {
          gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (bar), percentage);

471
          if (gtk_widget_is_drawable (bar))
472
            gdk_window_process_updates (gtk_widget_get_window (bar), TRUE);
473
        }
474 475 476 477 478 479 480 481 482
    }
}

static gdouble
gimp_statusbar_progress_get_value (GimpProgress *progress)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (statusbar->progress_active)
483
    return statusbar->progress_value;
484 485 486 487

  return 0.0;
}

Sven Neumann's avatar
Sven Neumann committed
488 489 490 491 492 493 494 495 496 497 498
static void
gimp_statusbar_progress_pulse (GimpProgress *progress)
{
  GimpStatusbar *statusbar = GIMP_STATUSBAR (progress);

  if (statusbar->progress_active)
    {
      GtkWidget *bar = statusbar->progressbar;

      gtk_progress_bar_pulse (GTK_PROGRESS_BAR (bar));

499
      if (gtk_widget_is_drawable (bar))
500
        gdk_window_process_updates (gtk_widget_get_window (bar), TRUE);
Sven Neumann's avatar
Sven Neumann committed
501 502 503
    }
}

504 505 506 507 508 509 510
static gboolean
gimp_statusbar_progress_message (GimpProgress        *progress,
                                 Gimp                *gimp,
                                 GimpMessageSeverity  severity,
                                 const gchar         *domain,
                                 const gchar         *message)
{
511 512
  GimpStatusbar *statusbar  = GIMP_STATUSBAR (progress);
  PangoLayout   *layout;
513
  const gchar   *stock_id;
514
  gboolean       handle_msg = FALSE;
515

516 517
  /*  don't accept a message if we are already displaying a more severe one  */
  if (statusbar->temp_timeout_id && statusbar->temp_severity > severity)
518
    return FALSE;
519

520
  /*  we can only handle short one-liners  */
521
  layout = gtk_widget_create_pango_layout (statusbar->label, message);
522

523 524
  stock_id = gimp_get_message_stock_id (severity);

525 526
  if (pango_layout_get_line_count (layout) == 1)
    {
527 528 529
      GtkAllocation label_allocation;
      gint          width;

530
      gtk_widget_get_allocation (statusbar->label, &label_allocation);
531 532 533

      pango_layout_get_pixel_size (layout, &width, NULL);

534
      if (width < label_allocation.width)
535
        {
536 537 538 539
          if (stock_id)
            {
              GdkPixbuf *pixbuf;

540
              pixbuf = gtk_widget_render_icon (statusbar->label, stock_id,
541 542
                                               GTK_ICON_SIZE_MENU, NULL);

543
              width += ICON_SPACING + gdk_pixbuf_get_width (pixbuf);
544 545

              g_object_unref (pixbuf);
546

547
              handle_msg = (width < label_allocation.width);
548 549 550 551 552
            }
          else
            {
              handle_msg = TRUE;
            }
553 554
        }
    }
555

556 557 558
  g_object_unref (layout);

  if (handle_msg)
559
    gimp_statusbar_push_temp (statusbar, severity, stock_id, "%s", message);
560 561

  return handle_msg;
562 563
}

564 565 566 567 568 569 570 571
static void
gimp_statusbar_progress_canceled (GtkWidget     *button,
                                  GimpStatusbar *statusbar)
{
  if (statusbar->progress_active)
    gimp_progress_cancel (GIMP_PROGRESS (statusbar));
}

572 573
static void
gimp_statusbar_set_text (GimpStatusbar *statusbar,
574
                         const gchar   *stock_id,
575 576 577
                         const gchar   *text)
{
  if (statusbar->progress_active)
578 579 580 581
    {
      gtk_progress_bar_set_text (GTK_PROGRESS_BAR (statusbar->progressbar),
                                 text);
    }
582
  else
583 584 585 586 587
    {
      if (statusbar->icon)
        g_object_unref (statusbar->icon);

      if (stock_id)
588
        statusbar->icon = gtk_widget_render_icon (statusbar->label,
589 590 591 592 593 594 595 596 597 598 599 600 601
                                                  stock_id,
                                                  GTK_ICON_SIZE_MENU, NULL);
      else
        statusbar->icon = NULL;

      if (statusbar->icon)
        {
          PangoAttrList  *attrs;
          PangoAttribute *attr;
          PangoRectangle  rect;
          gchar          *tmp;

          tmp = g_strconcat (" ", text, NULL);
602
          gtk_label_set_text (GTK_LABEL (statusbar->label), tmp);
603 604 605 606 607
          g_free (tmp);

          rect.x      = 0;
          rect.y      = 0;
          rect.width  = PANGO_SCALE * (gdk_pixbuf_get_width (statusbar->icon) +
608
                                       ICON_SPACING);
609
          rect.height = 0;
610 611 612 613 614 615 616 617

          attrs = pango_attr_list_new ();

          attr = pango_attr_shape_new (&rect, &rect);
          attr->start_index = 0;
          attr->end_index   = 1;
          pango_attr_list_insert (attrs, attr);

618
          gtk_label_set_attributes (GTK_LABEL (statusbar->label), attrs);
619 620 621 622
          pango_attr_list_unref (attrs);
        }
      else
        {
623 624
          gtk_label_set_text (GTK_LABEL (statusbar->label), text);
          gtk_label_set_attributes (GTK_LABEL (statusbar->label), NULL);
625 626
        }
    }
627 628
}

629
static void
630
gimp_statusbar_update (GimpStatusbar *statusbar)
631
{
632
  GimpStatusbarMsg *msg = NULL;
633 634 635

  if (statusbar->messages)
    {
636
      msg = statusbar->messages->data;
637

638 639 640 641 642
      /*  only allow progress messages while the progress is active  */
      if (statusbar->progress_active)
        {
          guint context_id = gimp_statusbar_get_context_id (statusbar,
                                                            "progress");
643

644 645 646
          if (context_id != msg->context_id)
            return;
        }
647 648
    }

649
  if (msg && msg->text)
650
    {
651
      gimp_statusbar_set_text (statusbar, msg->stock_id, msg->text);
652 653 654
    }
  else
    {
655
      gimp_statusbar_set_text (statusbar, NULL, "");
656
    }
657 658
}

659 660 661

/*  public functions  */

662
GtkWidget *
663
gimp_statusbar_new (void)
664
{
665
  return g_object_new (GIMP_TYPE_STATUSBAR, NULL);
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
}

void
gimp_statusbar_set_shell (GimpStatusbar    *statusbar,
                          GimpDisplayShell *shell)
{
  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));

  if (shell == statusbar->shell)
    return;

  if (statusbar->shell)
    {
      g_signal_handlers_disconnect_by_func (statusbar->shell,
                                            gimp_statusbar_shell_scaled,
                                            statusbar);
683 684 685 686

      g_signal_handlers_disconnect_by_func (statusbar->shell,
                                            gimp_statusbar_shell_status_notify,
                                            statusbar);
687 688
    }

689
  statusbar->shell = shell;
690

691
  g_signal_connect_object (statusbar->shell, "scaled",
692 693
                           G_CALLBACK (gimp_statusbar_shell_scaled),
                           statusbar, 0);
694 695 696 697

  g_signal_connect_object (statusbar->shell, "notify::status",
                           G_CALLBACK (gimp_statusbar_shell_status_notify),
                           statusbar, 0);
698 699
}

700 701 702 703 704 705 706 707
gboolean
gimp_statusbar_get_visible (GimpStatusbar *statusbar)
{
  g_return_val_if_fail (GIMP_IS_STATUSBAR (statusbar), FALSE);

  if (statusbar->progress_shown)
    return FALSE;

708
  return gtk_widget_get_visible (GTK_WIDGET (statusbar));
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
}

void
gimp_statusbar_set_visible (GimpStatusbar *statusbar,
                            gboolean       visible)
{
  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));

  if (statusbar->progress_shown)
    {
      if (visible)
        {
          statusbar->progress_shown = FALSE;
          return;
        }
    }

726
  gtk_widget_set_visible (GTK_WIDGET (statusbar), visible);
727 728
}

729 730 731 732 733
void
gimp_statusbar_empty (GimpStatusbar *statusbar)
{
  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));

734
  gtk_widget_hide (statusbar->cursor_label);
735 736 737 738 739 740 741 742 743
  gtk_widget_hide (statusbar->unit_combo);
  gtk_widget_hide (statusbar->scale_combo);
}

void
gimp_statusbar_fill (GimpStatusbar *statusbar)
{
  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));

744
  gtk_widget_show (statusbar->cursor_label);
745 746 747 748
  gtk_widget_show (statusbar->unit_combo);
  gtk_widget_show (statusbar->scale_combo);
}

749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
void
gimp_statusbar_override_window_title (GimpStatusbar *statusbar)
{
  GtkWidget *toplevel;

  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));

  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (statusbar));

  if (gimp_image_window_is_iconified (GIMP_IMAGE_WINDOW (toplevel)))
    {
      const gchar *message = gimp_statusbar_peek (statusbar, "progress");

      if (message)
        gtk_window_set_title (GTK_WINDOW (toplevel), message);
    }
}

void
gimp_statusbar_restore_window_title (GimpStatusbar *statusbar)
{
  GtkWidget *toplevel;

  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));

  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (statusbar));

  if (gimp_image_window_is_iconified (GIMP_IMAGE_WINDOW (toplevel)))
    {
778
      g_object_notify (G_OBJECT (statusbar->shell), "title");
779 780 781
    }
}

782
void
783
gimp_statusbar_push (GimpStatusbar *statusbar,
784
                     const gchar   *context,
785
                     const gchar   *stock_id,
786 787
                     const gchar   *format,
                     ...)
788 789 790 791 792 793 794 795
{
  va_list args;

  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
  g_return_if_fail (context != NULL);
  g_return_if_fail (format != NULL);

  va_start (args, format);
796
  gimp_statusbar_push_valist (statusbar, context, stock_id, format, args);
797 798 799 800 801 802
  va_end (args);
}

void
gimp_statusbar_push_valist (GimpStatusbar *statusbar,
                            const gchar   *context,
803
                            const gchar   *stock_id,
804 805
                            const gchar   *format,
                            va_list        args)
806
{
807 808 809
  GimpStatusbarMsg *msg;
  guint             context_id;
  GSList           *list;
810
  gchar            *message;
811 812

  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
813
  g_return_if_fail (context != NULL);
814 815
  g_return_if_fail (format != NULL);

816
  message = gimp_statusbar_vprintf (format, args);
817 818 819

  context_id = gimp_statusbar_get_context_id (statusbar, context);

820 821 822 823 824 825 826 827 828 829
  if (statusbar->messages)
    {
      msg = statusbar->messages->data;

      if (msg->context_id == context_id && strcmp (msg->text, message) == 0)
        {
          g_free (message);
          return;
        }
    }
830

831
  for (list = statusbar->messages; list; list = g_slist_next (list))
832
    {
833
      msg = list->data;
834

835
      if (msg->context_id == context_id)
836
        {
837
          statusbar->messages = g_slist_remove (statusbar->messages, msg);
838
          gimp_statusbar_msg_free (msg);
839 840

          break;
841 842
        }
    }
843

844
  msg = g_slice_new (GimpStatusbarMsg);
845

846
  msg->context_id = context_id;
847
  msg->stock_id   = g_strdup (stock_id);
848
  msg->text       = message;
849

850 851 852 853
  if (statusbar->temp_timeout_id)
    statusbar->messages = g_slist_insert (statusbar->messages, msg, 1);
  else
    statusbar->messages = g_slist_prepend (statusbar->messages, msg);
854

855
  gimp_statusbar_update (statusbar);
856 857
}

858
void
859 860 861 862 863 864 865 866 867
gimp_statusbar_push_coords (GimpStatusbar       *statusbar,
                            const gchar         *context,
                            const gchar         *stock_id,
                            GimpCursorPrecision  precision,
                            const gchar         *title,
                            gdouble              x,
                            const gchar         *separator,
                            gdouble              y,
                            const gchar         *help)
868
{
869
  GimpDisplayShell *shell;
870

871
  g_return_if_fail (GIMP_IS_STATUSBAR (statusbar));
872 873
  g_return_if_fail (title != NULL);
  g_return_if_fail (separator != NULL);
874

875
  if (help == NULL)
876
    help = "";
877

878
  shell = statusbar->shell;
Sven Neumann's avatar
Sven Neumann committed
879

880 881 882
  switch (precision)
    {
    case GIMP_CURSOR_PRECISION_PIXEL_CENTER:
883 884
      x = (gint) x;
      y = (gint) y;
885 886 887 888 889 890 891 892 893 894 895
      break;

    case GIMP_CURSOR_PRECISION_PIXEL_BORDER:
      x = RINT (x);
      y = RINT (y);
      break;

    case GIMP_CURSOR_PRECISION_SUBPIXEL:
      break;
    }

896
  if (shell->unit == GIMP_UNIT_PIXEL)
897
    {
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
      if (precision == GIMP_CURSOR_PRECISION_SUBPIXEL)
        {
          gimp_statusbar_push (statusbar, context,
                               stock_id,
                               statusbar->cursor_format_str_f,
                               title,
                               x,
                               separator,
                               y,
                               help);
        }
      else
        {
          gimp_statusbar_push (statusbar, context,
                               stock_id,
                               statusbar->cursor_format_str,
                               title,
                               (gint) RINT (x),
                               separator,
                               (gint) RINT (y),
                               help);
        }
920 921 922
    }
  else /* show real world units */
    {
923 924
      gdouble xres;
      gdouble yres;
925

926 927
      gimp_image_get_resolution (gimp_display_get_image (shell->display),
                                 &xres, &yres);
928

929
      gimp_statusbar_push (statusbar, context,