gtkstatusbar.c 21.9 KB
Newer Older
Shawn Amundson's avatar
Shawn Amundson committed
1 2 3 4 5
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 * GtkStatusbar Copyright (C) 1998 Shawn T. Amundson
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Shawn Amundson's avatar
Shawn Amundson committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
13
 * Lesser General Public License for more details.
Shawn Amundson's avatar
Shawn Amundson committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Shawn Amundson's avatar
Shawn Amundson committed
19 20
 */

21
/*
22
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23 24 25 26 27
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Shawn Amundson's avatar
Shawn Amundson committed
28 29
#include "gtkframe.h"
#include "gtklabel.h"
30
#include "gtkmarshalers.h"
Shawn Amundson's avatar
Shawn Amundson committed
31
#include "gtkstatusbar.h"
Owen Taylor's avatar
Owen Taylor committed
32
#include "gtkwindow.h"
33
#include "gtkintl.h"
Shawn Amundson's avatar
Shawn Amundson committed
34

35 36 37 38 39 40 41 42
typedef struct _GtkStatusbarMsg GtkStatusbarMsg;

struct _GtkStatusbarMsg
{
  gchar *text;
  guint context_id;
  guint message_id;
};
43 44 45 46 47 48 49 50

enum
{
  SIGNAL_TEXT_PUSHED,
  SIGNAL_TEXT_POPPED,
  SIGNAL_LAST
};

51 52 53 54 55 56
enum 
{
  PROP_ZERO,
  PROP_HAS_RESIZE_GRIP
};

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
static void     gtk_statusbar_class_init        (GtkStatusbarClass *class);
static void     gtk_statusbar_init              (GtkStatusbar      *statusbar);
static void     gtk_statusbar_destroy           (GtkObject         *object);
static void     gtk_statusbar_update            (GtkStatusbar      *statusbar,
						 guint              context_id,
						 const gchar       *text);
static void     gtk_statusbar_size_allocate     (GtkWidget         *widget,
						 GtkAllocation     *allocation);
static void     gtk_statusbar_realize           (GtkWidget         *widget);
static void     gtk_statusbar_unrealize         (GtkWidget         *widget);
static void     gtk_statusbar_map               (GtkWidget         *widget);
static void     gtk_statusbar_unmap             (GtkWidget         *widget);
static gboolean gtk_statusbar_button_press      (GtkWidget         *widget,
						 GdkEventButton    *event);
static gboolean gtk_statusbar_expose_event      (GtkWidget         *widget,
						 GdkEventExpose    *event);
static void     gtk_statusbar_size_request      (GtkWidget         *widget,
						 GtkRequisition    *requisition);
static void     gtk_statusbar_size_allocate     (GtkWidget         *widget,
						 GtkAllocation     *allocation);
static void     gtk_statusbar_direction_changed (GtkWidget         *widget,
						 GtkTextDirection   prev_dir);
static void     gtk_statusbar_create_window     (GtkStatusbar      *statusbar);
static void     gtk_statusbar_destroy_window    (GtkStatusbar      *statusbar);
static void     gtk_statusbar_get_property      (GObject           *object,
						 guint              prop_id,
						 GValue            *value,
						 GParamSpec        *pspec);
static void     gtk_statusbar_set_property      (GObject           *object,
						 guint              prop_id,
						 const GValue      *value,
						 GParamSpec        *pspec);

Owen Taylor's avatar
Owen Taylor committed
90

Shawn Amundson's avatar
Shawn Amundson committed
91
static GtkContainerClass *parent_class;
92
static guint              statusbar_signals[SIGNAL_LAST] = { 0 };
Shawn Amundson's avatar
Shawn Amundson committed
93

Manish Singh's avatar
Manish Singh committed
94
GType      
95
gtk_statusbar_get_type (void)
Shawn Amundson's avatar
Shawn Amundson committed
96
{
Manish Singh's avatar
Manish Singh committed
97
  static GType statusbar_type = 0;
Shawn Amundson's avatar
Shawn Amundson committed
98 99 100

  if (!statusbar_type)
    {
Manish Singh's avatar
Manish Singh committed
101
      static const GTypeInfo statusbar_info =
Shawn Amundson's avatar
Shawn Amundson committed
102 103
      {
        sizeof (GtkStatusbarClass),
Manish Singh's avatar
Manish Singh committed
104 105 106 107 108 109 110 111
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_statusbar_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkStatusbar),
	0,		/* n_preallocs */
        (GInstanceInitFunc) gtk_statusbar_init,
Shawn Amundson's avatar
Shawn Amundson committed
112 113
      };

114
      statusbar_type = g_type_register_static (GTK_TYPE_HBOX, "GtkStatusbar",
Manish Singh's avatar
Manish Singh committed
115
					       &statusbar_info, 0);
Shawn Amundson's avatar
Shawn Amundson committed
116 117 118
    }

  return statusbar_type;
119
}
Shawn Amundson's avatar
Shawn Amundson committed
120 121 122 123

static void
gtk_statusbar_class_init (GtkStatusbarClass *class)
{
124
  GObjectClass *gobject_class;
Shawn Amundson's avatar
Shawn Amundson committed
125 126 127 128
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

129
  gobject_class = (GObjectClass *) class;
Shawn Amundson's avatar
Shawn Amundson committed
130 131 132 133
  object_class = (GtkObjectClass *) class;
  widget_class = (GtkWidgetClass *) class;
  container_class = (GtkContainerClass *) class;

Manish Singh's avatar
Manish Singh committed
134
  parent_class = g_type_class_peek_parent (class);
135
  
136 137 138
  gobject_class->set_property = gtk_statusbar_set_property;
  gobject_class->get_property = gtk_statusbar_get_property;

139 140
  object_class->destroy = gtk_statusbar_destroy;

Owen Taylor's avatar
Owen Taylor committed
141 142 143 144 145 146 147
  widget_class->realize = gtk_statusbar_realize;
  widget_class->unrealize = gtk_statusbar_unrealize;
  widget_class->map = gtk_statusbar_map;
  widget_class->unmap = gtk_statusbar_unmap;
  
  widget_class->button_press_event = gtk_statusbar_button_press;
  widget_class->expose_event = gtk_statusbar_expose_event;
148 149 150

  widget_class->size_request = gtk_statusbar_size_request;
  widget_class->size_allocate = gtk_statusbar_size_allocate;
151 152

  widget_class->direction_changed = gtk_statusbar_direction_changed;
Owen Taylor's avatar
Owen Taylor committed
153
  
154
  class->messages_mem_chunk = g_mem_chunk_new ("GtkStatusbar messages mem chunk",
155 156 157 158 159 160
					       sizeof (GtkStatusbarMsg),
					       sizeof (GtkStatusbarMsg) * 64,
					       G_ALLOC_AND_FREE);

  class->text_pushed = gtk_statusbar_update;
  class->text_popped = gtk_statusbar_update;
Owen Taylor's avatar
Owen Taylor committed
161
  
162 163 164 165 166 167 168 169 170 171
  /**
   * GtkStatusbar:has-resize-grip:
   *
   * Whether the statusbar has a grip for resizing the toplevel window.
   *
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
				   PROP_HAS_RESIZE_GRIP,
				   g_param_spec_boolean ("has_resize_grip",
172 173
 							 P_("Has Resize Grip"),
 							 P_("Whether the statusbar has a grip for resizing the toplevel"),
174 175
 							 TRUE,
 							 G_PARAM_READWRITE));
176
  statusbar_signals[SIGNAL_TEXT_PUSHED] =
Manish Singh's avatar
Manish Singh committed
177 178 179 180 181 182 183 184 185
    g_signal_new ("text_pushed",
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkStatusbarClass, text_pushed),
		  NULL, NULL,
		  _gtk_marshal_VOID__UINT_STRING,
		  G_TYPE_NONE, 2,
		  G_TYPE_UINT,
		  G_TYPE_STRING);
186
  statusbar_signals[SIGNAL_TEXT_POPPED] =
Manish Singh's avatar
Manish Singh committed
187 188 189 190 191 192 193 194 195
    g_signal_new ("text_popped",
		  G_OBJECT_CLASS_TYPE (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkStatusbarClass, text_popped),
		  NULL, NULL,
		  _gtk_marshal_VOID__UINT_STRING,
		  G_TYPE_NONE, 2,
		  G_TYPE_UINT,
		  G_TYPE_STRING);
196 197 198

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_enum ("shadow_type",
199 200
                                                              P_("Shadow type"),
                                                              P_("Style of bevel around the statusbar text"),
201 202 203
                                                              GTK_TYPE_SHADOW_TYPE,
                                                              GTK_SHADOW_IN,
                                                              G_PARAM_READABLE));
Shawn Amundson's avatar
Shawn Amundson committed
204 205 206 207 208
}

static void
gtk_statusbar_init (GtkStatusbar *statusbar)
{
209
  GtkBox *box;
210 211
  GtkShadowType shadow_type;
  
212 213 214 215
  box = GTK_BOX (statusbar);

  box->spacing = 2;
  box->homogeneous = FALSE;
Shawn Amundson's avatar
Shawn Amundson committed
216

Owen Taylor's avatar
Owen Taylor committed
217
  statusbar->has_resize_grip = TRUE;
218 219

  gtk_widget_style_get (GTK_WIDGET (statusbar), "shadow_type", &shadow_type, NULL);
Owen Taylor's avatar
Owen Taylor committed
220
  
Jay Painter's avatar
Jay Painter committed
221
  statusbar->frame = gtk_frame_new (NULL);
222
  gtk_frame_set_shadow_type (GTK_FRAME (statusbar->frame), shadow_type);
223
  gtk_box_pack_start (box, statusbar->frame, TRUE, TRUE, 0);
Jay Painter's avatar
Jay Painter committed
224
  gtk_widget_show (statusbar->frame);
Shawn Amundson's avatar
Shawn Amundson committed
225

226
  statusbar->label = gtk_label_new ("");
227
  gtk_misc_set_alignment (GTK_MISC (statusbar->label), 0.0, 0.5);
228 229 230
  /* don't expand the size request for the label; if we
   * do that then toplevels weirdly resize
   */
Manish Singh's avatar
Manish Singh committed
231
  gtk_widget_set_size_request (statusbar->label, 1, -1);
232
  gtk_container_add (GTK_CONTAINER (statusbar->frame), statusbar->label);
Jay Painter's avatar
Jay Painter committed
233
  gtk_widget_show (statusbar->label);
Shawn Amundson's avatar
Shawn Amundson committed
234

235 236
  statusbar->seq_context_id = 1;
  statusbar->seq_message_id = 1;
237
  statusbar->messages = NULL;
238
  statusbar->keys = NULL;
Shawn Amundson's avatar
Shawn Amundson committed
239 240 241
}

GtkWidget* 
242
gtk_statusbar_new (void)
Shawn Amundson's avatar
Shawn Amundson committed
243
{
Manish Singh's avatar
Manish Singh committed
244
  return g_object_new (GTK_TYPE_STATUSBAR, NULL);
245 246 247 248
}

static void
gtk_statusbar_update (GtkStatusbar *statusbar,
249
		      guint	    context_id,
250 251 252
		      const gchar  *text)
{
  g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
Shawn Amundson's avatar
Shawn Amundson committed
253

254 255
  if (!text)
    text = "";
Shawn Amundson's avatar
Shawn Amundson committed
256

Owen Taylor's avatar
Owen Taylor committed
257
  gtk_label_set_text (GTK_LABEL (statusbar->label), text);
Shawn Amundson's avatar
Shawn Amundson committed
258 259
}

260 261 262 263 264 265 266 267 268 269 270 271 272
guint
gtk_statusbar_get_context_id (GtkStatusbar *statusbar,
			      const gchar  *context_description)
{
  gchar *string;
  guint *id;
  
  g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
  g_return_val_if_fail (context_description != NULL, 0);

  /* we need to preserve namespaces on object datas */
  string = g_strconcat ("gtk-status-bar-context:", context_description, NULL);

Manish Singh's avatar
Manish Singh committed
273
  id = g_object_get_data (G_OBJECT (statusbar), string);
274 275 276 277
  if (!id)
    {
      id = g_new (guint, 1);
      *id = statusbar->seq_context_id++;
Manish Singh's avatar
Manish Singh committed
278
      g_object_set_data_full (G_OBJECT (statusbar), string, id, g_free);
279 280 281 282 283 284 285 286
      statusbar->keys = g_slist_prepend (statusbar->keys, string);
    }
  else
    g_free (string);

  return *id;
}

287 288
guint
gtk_statusbar_push (GtkStatusbar *statusbar,
289
		    guint	  context_id,
290
		    const gchar  *text)
Shawn Amundson's avatar
Shawn Amundson committed
291 292
{
  GtkStatusbarMsg *msg;
293 294 295 296
  GtkStatusbarClass *class;

  g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), 0);
  g_return_val_if_fail (text != NULL, 0);
Shawn Amundson's avatar
Shawn Amundson committed
297

298
  class = GTK_STATUSBAR_GET_CLASS (statusbar);
299 300
  msg = g_chunk_new (GtkStatusbarMsg, class->messages_mem_chunk);
  msg->text = g_strdup (text);
301 302
  msg->context_id = context_id;
  msg->message_id = statusbar->seq_message_id++;
Shawn Amundson's avatar
Shawn Amundson committed
303

304
  statusbar->messages = g_slist_prepend (statusbar->messages, msg);
Shawn Amundson's avatar
Shawn Amundson committed
305

Manish Singh's avatar
Manish Singh committed
306 307 308 309 310
  g_signal_emit (statusbar,
		 statusbar_signals[SIGNAL_TEXT_PUSHED],
		 0,
		 msg->context_id,
		 msg->text);
Shawn Amundson's avatar
Shawn Amundson committed
311

312
  return msg->message_id;
Shawn Amundson's avatar
Shawn Amundson committed
313 314
}

315
void
316 317
gtk_statusbar_pop (GtkStatusbar *statusbar,
		   guint	 context_id)
Shawn Amundson's avatar
Shawn Amundson committed
318
{
319
  GtkStatusbarMsg *msg;
Shawn Amundson's avatar
Shawn Amundson committed
320

321
  g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
Shawn Amundson's avatar
Shawn Amundson committed
322

323 324
  if (statusbar->messages)
    {
325
      GSList *list;
Owen Taylor's avatar
Owen Taylor committed
326 327 328 329 330 331 332 333 334

      for (list = statusbar->messages; list; list = list->next)
	{
	  msg = list->data;

	  if (msg->context_id == context_id)
	    {
	      GtkStatusbarClass *class;

335
	      class = GTK_STATUSBAR_GET_CLASS (statusbar);
Owen Taylor's avatar
Owen Taylor committed
336 337 338 339 340 341 342 343 344

	      statusbar->messages = g_slist_remove_link (statusbar->messages,
							 list);
	      g_free (msg->text);
	      g_mem_chunk_free (class->messages_mem_chunk, msg);
	      g_slist_free_1 (list);
	      break;
	    }
	}
345 346 347
    }

  msg = statusbar->messages ? statusbar->messages->data : NULL;
Shawn Amundson's avatar
Shawn Amundson committed
348

Manish Singh's avatar
Manish Singh committed
349 350 351 352 353
  g_signal_emit (statusbar,
		 statusbar_signals[SIGNAL_TEXT_POPPED],
		 0,
		 (guint) (msg ? msg->context_id : 0),
		 msg ? msg->text : NULL);
Shawn Amundson's avatar
Shawn Amundson committed
354 355 356
}

void
357 358 359
gtk_statusbar_remove (GtkStatusbar *statusbar,
		      guint	   context_id,
		      guint        message_id)
Shawn Amundson's avatar
Shawn Amundson committed
360
{
361
  GtkStatusbarMsg *msg;
Shawn Amundson's avatar
Shawn Amundson committed
362

363
  g_return_if_fail (GTK_IS_STATUSBAR (statusbar));
364
  g_return_if_fail (message_id > 0);
Shawn Amundson's avatar
Shawn Amundson committed
365

366 367 368
  msg = statusbar->messages ? statusbar->messages->data : NULL;
  if (msg)
    {
369 370 371 372 373
      GSList *list;

      /* care about signal emission if the topmost item is removed */
      if (msg->context_id == context_id &&
	  msg->message_id == message_id)
374
	{
375
	  gtk_statusbar_pop (statusbar, context_id);
376 377 378 379 380 381 382
	  return;
	}
      
      for (list = statusbar->messages; list; list = list->next)
	{
	  msg = list->data;
	  
383 384
	  if (msg->context_id == context_id &&
	      msg->message_id == message_id)
385 386 387
	    {
	      GtkStatusbarClass *class;
	      
388
	      class = GTK_STATUSBAR_GET_CLASS (statusbar);
389
	      statusbar->messages = g_slist_remove_link (statusbar->messages, list);
390 391
	      g_free (msg->text);
	      g_mem_chunk_free (class->messages_mem_chunk, msg);
392
	      g_slist_free_1 (list);
393 394 395 396
	      
	      break;
	    }
	}
Shawn Amundson's avatar
Shawn Amundson committed
397 398 399
    }
}

Owen Taylor's avatar
Owen Taylor committed
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
void
gtk_statusbar_set_has_resize_grip (GtkStatusbar *statusbar,
				   gboolean      setting)
{
  g_return_if_fail (GTK_IS_STATUSBAR (statusbar));

  setting = setting != FALSE;

  if (setting != statusbar->has_resize_grip)
    {
      statusbar->has_resize_grip = setting;
      gtk_widget_queue_draw (GTK_WIDGET (statusbar));

      if (GTK_WIDGET_REALIZED (statusbar))
        {
          if (statusbar->has_resize_grip && statusbar->grip_window == NULL)
            gtk_statusbar_create_window (statusbar);
          else if (!statusbar->has_resize_grip && statusbar->grip_window != NULL)
            gtk_statusbar_destroy_window (statusbar);
        }
420 421

      g_object_notify (G_OBJECT (statusbar), "has_resize_grip");
Owen Taylor's avatar
Owen Taylor committed
422 423 424 425 426 427 428 429 430 431 432
    }
}

gboolean
gtk_statusbar_get_has_resize_grip (GtkStatusbar *statusbar)
{
  g_return_val_if_fail (GTK_IS_STATUSBAR (statusbar), FALSE);

  return statusbar->has_resize_grip;
}

Shawn Amundson's avatar
Shawn Amundson committed
433 434 435 436
static void
gtk_statusbar_destroy (GtkObject *object)
{
  GtkStatusbar *statusbar;
437
  GtkStatusbarClass *class;
438
  GSList *list;
439

Shawn Amundson's avatar
Shawn Amundson committed
440 441 442
  g_return_if_fail (GTK_IS_STATUSBAR (object));

  statusbar = GTK_STATUSBAR (object);
443
  class = GTK_STATUSBAR_GET_CLASS (statusbar);
444 445 446 447 448 449 450 451 452

  for (list = statusbar->messages; list; list = list->next)
    {
      GtkStatusbarMsg *msg;

      msg = list->data;
      g_free (msg->text);
      g_mem_chunk_free (class->messages_mem_chunk, msg);
    }
453
  g_slist_free (statusbar->messages);
454
  statusbar->messages = NULL;
Shawn Amundson's avatar
Shawn Amundson committed
455

456 457 458 459 460
  for (list = statusbar->keys; list; list = list->next)
    g_free (list->data);
  g_slist_free (statusbar->keys);
  statusbar->keys = NULL;

461 462
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
Owen Taylor's avatar
Owen Taylor committed
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
static void
gtk_statusbar_set_property (GObject      *object, 
			    guint         prop_id, 
			    const GValue *value, 
			    GParamSpec   *pspec)
{
  GtkStatusbar *statusbar = GTK_STATUSBAR (object);

  switch (prop_id) 
    {
    case PROP_HAS_RESIZE_GRIP:
      gtk_statusbar_set_has_resize_grip (statusbar, g_value_get_boolean (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_statusbar_get_property (GObject    *object, 
			    guint       prop_id, 
			    GValue     *value, 
			    GParamSpec *pspec)
{
  GtkStatusbar *statusbar = GTK_STATUSBAR (object);
	
  switch (prop_id) 
    {
    case PROP_HAS_RESIZE_GRIP:
      g_value_set_boolean (value, statusbar->has_resize_grip);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
502 503 504 505 506 507 508 509 510 511 512
static GdkWindowEdge
get_grip_edge (GtkStatusbar *statusbar)
{
  GtkWidget *widget = GTK_WIDGET (statusbar);

  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) 
    return GDK_WINDOW_EDGE_SOUTH_EAST; 
  else
    return GDK_WINDOW_EDGE_SOUTH_WEST; 
}

Owen Taylor's avatar
Owen Taylor committed
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
static void
get_grip_rect (GtkStatusbar *statusbar,
               GdkRectangle *rect)
{
  GtkWidget *widget;
  gint w, h;
  
  widget = GTK_WIDGET (statusbar);

  /* These are in effect the max/default size of the grip. */
  w = 18;
  h = 18;

  if (w > (widget->allocation.width))
    w = widget->allocation.width;

  if (h > (widget->allocation.height - widget->style->ythickness))
    h = widget->allocation.height - widget->style->ythickness;
  
  rect->width = w;
  rect->height = h;
Matthias Clasen's avatar
Matthias Clasen committed
534 535 536
  rect->y = widget->allocation.y + widget->allocation.height - h;

  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) 
537
    rect->x = widget->allocation.x + widget->allocation.width - w;
Matthias Clasen's avatar
Matthias Clasen committed
538
  else 
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
    rect->x = widget->allocation.x + widget->style->xthickness;
}

static void
set_grip_cursor (GtkStatusbar *statusbar)
{
  if (statusbar->has_resize_grip)
    {
      GtkWidget *widget = GTK_WIDGET (statusbar);
      GdkDisplay *display = gtk_widget_get_display (widget);
      GdkCursorType cursor_type;
      GdkCursor *cursor;
      
      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
	cursor_type = GDK_BOTTOM_RIGHT_CORNER;
      else
	cursor_type = GDK_BOTTOM_LEFT_CORNER;

      cursor = gdk_cursor_new_for_display (display, cursor_type);
      gdk_window_set_cursor (statusbar->grip_window, cursor);
      gdk_cursor_unref (cursor);
    }
Owen Taylor's avatar
Owen Taylor committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
}

static void
gtk_statusbar_create_window (GtkStatusbar *statusbar)
{
  GtkWidget *widget;
  GdkWindowAttr attributes;
  gint attributes_mask;
  GdkRectangle rect;
  
  g_return_if_fail (GTK_WIDGET_REALIZED (statusbar));
  g_return_if_fail (statusbar->has_resize_grip);
  
  widget = GTK_WIDGET (statusbar);

  get_grip_rect (statusbar, &rect);

  attributes.x = rect.x;
  attributes.y = rect.y;
  attributes.width = rect.width;
  attributes.height = rect.height;
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.wclass = GDK_INPUT_ONLY;
  attributes.event_mask = gtk_widget_get_events (widget) |
    GDK_BUTTON_PRESS_MASK;

  attributes_mask = GDK_WA_X | GDK_WA_Y;

  statusbar->grip_window = gdk_window_new (widget->window,
                                           &attributes, attributes_mask);
  gdk_window_set_user_data (statusbar->grip_window, widget);
592 593 594 595 596 597 598 599 600 601 602

  set_grip_cursor (statusbar);
}

static void
gtk_statusbar_direction_changed (GtkWidget        *widget,
				 GtkTextDirection  prev_dir)
{
  GtkStatusbar *statusbar = GTK_STATUSBAR (widget);

  set_grip_cursor (statusbar);
Owen Taylor's avatar
Owen Taylor committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
}

static void
gtk_statusbar_destroy_window (GtkStatusbar *statusbar)
{
  gdk_window_set_user_data (statusbar->grip_window, NULL);
  gdk_window_destroy (statusbar->grip_window);
  statusbar->grip_window = NULL;
}

static void
gtk_statusbar_realize (GtkWidget *widget)
{
  GtkStatusbar *statusbar;

  statusbar = GTK_STATUSBAR (widget);
  
  (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);

  if (statusbar->has_resize_grip)
    gtk_statusbar_create_window (statusbar);
}

static void
gtk_statusbar_unrealize (GtkWidget *widget)
{
  GtkStatusbar *statusbar;

  statusbar = GTK_STATUSBAR (widget);

  if (statusbar->grip_window)
    gtk_statusbar_destroy_window (statusbar);
  
  (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

static void
gtk_statusbar_map (GtkWidget *widget)
{
  GtkStatusbar *statusbar;

  statusbar = GTK_STATUSBAR (widget);
  
  (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
  
  if (statusbar->grip_window)
    gdk_window_show (statusbar->grip_window);
}

static void
gtk_statusbar_unmap (GtkWidget *widget)
{
  GtkStatusbar *statusbar;

  statusbar = GTK_STATUSBAR (widget);

  if (statusbar->grip_window)
    gdk_window_hide (statusbar->grip_window);
  
  (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
}

static gboolean
gtk_statusbar_button_press (GtkWidget      *widget,
                            GdkEventButton *event)
{
  GtkStatusbar *statusbar;
  GtkWidget *ancestor;
Matthias Clasen's avatar
Matthias Clasen committed
671
  GdkWindowEdge edge;
Owen Taylor's avatar
Owen Taylor committed
672 673 674
  
  statusbar = GTK_STATUSBAR (widget);
  
675 676
  if (!statusbar->has_resize_grip ||
    event->type != GDK_BUTTON_PRESS)
Owen Taylor's avatar
Owen Taylor committed
677 678 679 680 681 682 683
    return FALSE;
  
  ancestor = gtk_widget_get_toplevel (widget);

  if (!GTK_IS_WINDOW (ancestor))
    return FALSE;

Matthias Clasen's avatar
Matthias Clasen committed
684 685
  edge = get_grip_edge (statusbar);

Owen Taylor's avatar
Owen Taylor committed
686 687
  if (event->button == 1)
    gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
Matthias Clasen's avatar
Matthias Clasen committed
688
                                  edge,
Owen Taylor's avatar
Owen Taylor committed
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
                                  event->button,
                                  event->x_root, event->y_root,
                                  event->time);
  else if (event->button == 2)
    gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
                                event->button,
                                event->x_root, event->y_root,
                                event->time);
  else
    return FALSE;
  
  return TRUE;
}

static gboolean
gtk_statusbar_expose_event (GtkWidget      *widget,
                            GdkEventExpose *event)
{
  GtkStatusbar *statusbar;
  GdkRectangle rect;
  
  statusbar = GTK_STATUSBAR (widget);

  GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);

  if (statusbar->has_resize_grip)
    {
Matthias Clasen's avatar
Matthias Clasen committed
716 717 718 719
      GdkWindowEdge edge;
      
      edge = get_grip_edge (statusbar);

Owen Taylor's avatar
Owen Taylor committed
720
      get_grip_rect (statusbar, &rect);
721

Owen Taylor's avatar
Owen Taylor committed
722 723 724 725 726 727
      gtk_paint_resize_grip (widget->style,
                             widget->window,
                             GTK_WIDGET_STATE (widget),
                             NULL,
                             widget,
                             "statusbar",
Matthias Clasen's avatar
Matthias Clasen committed
728
                             edge,
Owen Taylor's avatar
Owen Taylor committed
729 730 731 732 733 734 735 736 737 738
                             rect.x, rect.y,
                             /* don't draw grip over the frame, though you
                              * can click on the frame.
                              */
                             rect.width - widget->style->xthickness,
                             rect.height - widget->style->ythickness);
    }

  return FALSE;
}
739 740 741 742 743 744 745 746 747 748 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 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802

static void
gtk_statusbar_size_request   (GtkWidget      *widget,
                              GtkRequisition *requisition)
{
  GtkStatusbar *statusbar;
  GtkShadowType shadow_type;
  
  statusbar = GTK_STATUSBAR (widget);

  gtk_widget_style_get (GTK_WIDGET (statusbar), "shadow_type", &shadow_type, NULL);  
  gtk_frame_set_shadow_type (GTK_FRAME (statusbar->frame), shadow_type);
  
  GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);

  if (statusbar->has_resize_grip)
    {
      GdkRectangle rect;

      /* x, y in the grip rect depend on size allocation, but
       * w, h do not so this is OK
       */
      get_grip_rect (statusbar, &rect);
      
      requisition->width += rect.width;
      requisition->height = MAX (requisition->height, rect.height);
    }
}

static void
gtk_statusbar_size_allocate  (GtkWidget     *widget,
                              GtkAllocation *allocation)
{
  GtkStatusbar *statusbar;
  
  statusbar = GTK_STATUSBAR (widget);

  if (statusbar->has_resize_grip)
    {
      GdkRectangle rect;
      GtkRequisition saved_req;
      
      widget->allocation = *allocation; /* get_grip_rect needs this info */
      get_grip_rect (statusbar, &rect);
  
      if (statusbar->grip_window)
        gdk_window_move_resize (statusbar->grip_window,
                                rect.x, rect.y,
                                rect.width, rect.height);
      
      /* enter the bad hack zone */      
      saved_req = widget->requisition;
      widget->requisition.width -= rect.width; /* HBox::size_allocate needs this */
      if (widget->requisition.width < 0)
        widget->requisition.width = 0;
      GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
      widget->requisition = saved_req;
    }
  else
    {
      /* chain up normally */
      GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
    }
}