summaryrefslogtreecommitdiff
path: root/trunk/src/totem-statusbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/totem-statusbar.c')
-rw-r--r--trunk/src/totem-statusbar.c674
1 files changed, 674 insertions, 0 deletions
diff --git a/trunk/src/totem-statusbar.c b/trunk/src/totem-statusbar.c
new file mode 100644
index 000000000..5fbebcc34
--- /dev/null
+++ b/trunk/src/totem-statusbar.c
@@ -0,0 +1,674 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * TotemStatusbar Copyright (C) 1998 Shawn T. Amundson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * 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/.
+ */
+
+#include "config.h"
+
+#include <gtk/gtkframe.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkvseparator.h>
+#include <gtk/gtkwindow.h>
+#include <glib/gi18n.h>
+
+#include "totem-statusbar.h"
+#include "video-utils.h"
+
+static void totem_statusbar_class_init (TotemStatusbarClass *class);
+static void totem_statusbar_init (TotemStatusbar *statusbar);
+static void totem_statusbar_destroy (GtkObject *object);
+static void totem_statusbar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void totem_statusbar_realize (GtkWidget *widget);
+static void totem_statusbar_unrealize (GtkWidget *widget);
+static void totem_statusbar_map (GtkWidget *widget);
+static void totem_statusbar_unmap (GtkWidget *widget);
+static gboolean totem_statusbar_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean totem_statusbar_expose_event (GtkWidget *widget,
+ GdkEventExpose *event);
+static void totem_statusbar_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void totem_statusbar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void totem_statusbar_create_window (TotemStatusbar *statusbar);
+static void totem_statusbar_destroy_window (TotemStatusbar *statusbar);
+static void totem_statusbar_sync_description (TotemStatusbar *statusbar);
+
+static GtkContainerClass *parent_class;
+
+G_DEFINE_TYPE(TotemStatusbar, totem_statusbar, GTK_TYPE_HBOX)
+
+static void
+totem_statusbar_class_init (TotemStatusbarClass *class)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ object_class = (GtkObjectClass *) class;
+ widget_class = (GtkWidgetClass *) class;
+ container_class = (GtkContainerClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->destroy = totem_statusbar_destroy;
+
+ widget_class->realize = totem_statusbar_realize;
+ widget_class->unrealize = totem_statusbar_unrealize;
+ widget_class->map = totem_statusbar_map;
+ widget_class->unmap = totem_statusbar_unmap;
+
+ widget_class->button_press_event = totem_statusbar_button_press;
+ widget_class->expose_event = totem_statusbar_expose_event;
+
+ widget_class->size_request = totem_statusbar_size_request;
+ widget_class->size_allocate = totem_statusbar_size_allocate;
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_enum ("shadow_type",
+ _("Shadow type"),
+ _("Style of bevel around the statusbar text"),
+ GTK_TYPE_SHADOW_TYPE,
+ GTK_SHADOW_IN,
+ G_PARAM_READABLE));
+}
+
+static void
+totem_statusbar_init (TotemStatusbar *statusbar)
+{
+ GtkBox *box;
+ GtkShadowType shadow_type;
+ GtkWidget *packer, *hbox;
+ AtkObject *obj;
+
+ box = GTK_BOX (statusbar);
+
+ box->spacing = 2;
+ box->homogeneous = FALSE;
+
+ statusbar->has_resize_grip = TRUE;
+ statusbar->time = 0;
+ statusbar->length = -1;
+
+ gtk_widget_style_get (GTK_WIDGET (statusbar), "shadow_type", &shadow_type, NULL);
+
+ statusbar->frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (statusbar->frame), shadow_type);
+ gtk_box_pack_start (box, statusbar->frame, TRUE, TRUE, 0);
+ gtk_widget_show (statusbar->frame);
+ hbox = gtk_hbox_new (FALSE, 4);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
+ gtk_widget_show (hbox);
+
+ statusbar->label = gtk_label_new (_("Stopped"));
+ gtk_misc_set_alignment (GTK_MISC (statusbar->label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), statusbar->label, FALSE, FALSE, 0);
+ gtk_widget_show (statusbar->label);
+
+ /* progressbar for network streams */
+ statusbar->progress = gtk_progress_bar_new ();
+ gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (statusbar->progress),
+ GTK_ORIENTATION_HORIZONTAL);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (statusbar->progress), 0.);
+ gtk_box_pack_start (GTK_BOX (hbox), statusbar->progress, FALSE, TRUE, 0);
+ gtk_widget_set_size_request (statusbar->progress, 150, 10);
+ gtk_widget_hide (statusbar->progress);
+
+ packer = gtk_vseparator_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), packer, FALSE, FALSE, 0);
+ gtk_widget_show (packer);
+
+ statusbar->time_label = gtk_label_new (_("0:00 / 0:00"));
+ gtk_misc_set_alignment (GTK_MISC (statusbar->label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), statusbar->time_label, FALSE, FALSE, 0);
+ gtk_widget_show (statusbar->time_label);
+
+
+ obj = gtk_widget_get_accessible (GTK_WIDGET (box));
+ atk_object_set_role (obj, ATK_ROLE_STATUSBAR);
+ totem_statusbar_sync_description (statusbar);
+
+ /* don't expand the size request for the label; if we
+ * do that then toplevels weirdly resize
+ */
+ gtk_container_add (GTK_CONTAINER (statusbar->frame), hbox);
+}
+
+GtkWidget*
+totem_statusbar_new (void)
+{
+ return g_object_new (TOTEM_TYPE_STATUSBAR, NULL);
+}
+
+GtkWidget *
+totem_statusbar_new_from_glade (gchar *widget_name,
+ gchar *string1, gchar *string2,
+ gint int1, gint int2)
+{
+ GtkWidget *widget;
+
+ widget = totem_statusbar_new ();
+ gtk_widget_show (widget);
+
+ return widget;
+}
+
+static void
+totem_statusbar_update_time (TotemStatusbar *statusbar)
+{
+ char *time, *length, *label;
+
+ time = totem_time_to_string (statusbar->time * 1000);
+
+ if (statusbar->length < 0) {
+ label = g_strdup_printf (_("%s (Streaming)"), time);
+ } else {
+ length = totem_time_to_string
+ (statusbar->length == -1 ? 0 : statusbar->length * 1000);
+
+ if (statusbar->seeking == FALSE)
+ /* Elapsed / Total Length */
+ label = g_strdup_printf (_("%s / %s"), time, length);
+ else
+ /* Seeking to Time / Total Length */
+ label = g_strdup_printf (_("Seek to %s / %s"), time, length);
+
+ g_free (length);
+ }
+ g_free (time);
+
+ gtk_label_set_text (GTK_LABEL (statusbar->time_label), label);
+ g_free (label);
+
+ totem_statusbar_sync_description (statusbar);
+}
+
+void
+totem_statusbar_set_text (TotemStatusbar *statusbar, const char *label)
+{
+ gtk_label_set_text (GTK_LABEL (statusbar->label), label);
+ g_free (statusbar->saved_label);
+ statusbar->saved_label = g_strdup (label);
+
+ totem_statusbar_sync_description (statusbar);
+}
+
+void
+totem_statusbar_set_time (TotemStatusbar *statusbar, gint time)
+{
+ g_return_if_fail (TOTEM_IS_STATUSBAR (statusbar));
+
+ if (statusbar->time == time)
+ return;
+
+ statusbar->time = time;
+ totem_statusbar_update_time (statusbar);
+}
+
+static gboolean
+totem_statusbar_timeout_pop (TotemStatusbar *statusbar)
+{
+ gtk_label_set_text (GTK_LABEL (statusbar->label), statusbar->saved_label);
+ g_free (statusbar->saved_label);
+ statusbar->saved_label = NULL;
+ statusbar->pushed = FALSE;
+ gtk_widget_hide (statusbar->progress);
+
+ totem_statusbar_sync_description (statusbar);
+
+ statusbar->percentage = 101;
+
+ return FALSE;
+}
+
+void
+totem_statusbar_push (TotemStatusbar *statusbar, guint percentage)
+{
+ char *label;
+ statusbar->pushed = TRUE;
+
+ if (statusbar->timeout != 0)
+ {
+ g_source_remove (statusbar->timeout);
+ if (statusbar->percentage == percentage) {
+ statusbar->timeout = g_timeout_add (3000,
+ (GSourceFunc) totem_statusbar_timeout_pop, statusbar);
+ return;
+ }
+ }
+
+ statusbar->percentage = percentage;
+
+ if (statusbar->saved_label == NULL)
+ {
+ statusbar->saved_label = g_strdup
+ (gtk_label_get_text (GTK_LABEL (statusbar->label)));
+ }
+
+ gtk_label_set_text (GTK_LABEL (statusbar->label), _("Buffering"));
+
+ /* eg: 75 % */
+ label = g_strdup_printf (_("%d %%"), percentage);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (statusbar->progress), label);
+ g_free (label);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (statusbar->progress),
+ percentage / 100.);
+ gtk_widget_show (statusbar->progress);
+
+ statusbar->timeout = g_timeout_add (3000,
+ (GSourceFunc) totem_statusbar_timeout_pop, statusbar);
+
+ totem_statusbar_sync_description (statusbar);
+}
+
+void
+totem_statusbar_pop (TotemStatusbar *statusbar)
+{
+ if (statusbar->pushed != FALSE)
+ {
+ g_source_remove (statusbar->timeout);
+ totem_statusbar_timeout_pop (statusbar);
+ }
+}
+
+void
+totem_statusbar_set_time_and_length (TotemStatusbar *statusbar,
+ gint time, gint length)
+{
+ g_return_if_fail (TOTEM_IS_STATUSBAR (statusbar));
+
+ if (time != statusbar->time ||
+ length != statusbar->length) {
+ statusbar->time = time;
+ statusbar->length = length;
+
+ totem_statusbar_update_time (statusbar);
+ }
+}
+
+void
+totem_statusbar_set_seeking (TotemStatusbar *statusbar,
+ gboolean seeking)
+{
+ g_return_if_fail (TOTEM_IS_STATUSBAR (statusbar));
+
+ if (statusbar->seeking == seeking)
+ return;
+
+ statusbar->seeking = seeking;
+
+ totem_statusbar_update_time (statusbar);
+}
+
+static void
+totem_statusbar_sync_description (TotemStatusbar *statusbar)
+{
+ AtkObject *obj;
+ char *text;
+
+ obj = gtk_widget_get_accessible (GTK_WIDGET (statusbar));
+ if (statusbar->pushed == FALSE) {
+ /* eg: Paused, 0:32 / 1:05 */
+ text = g_strdup_printf (_("%s, %s"),
+ gtk_label_get_text (GTK_LABEL (statusbar->label)),
+ gtk_label_get_text (GTK_LABEL (statusbar->time_label)));
+ } else {
+ /* eg: Buffering, 75 % */
+ text = g_strdup_printf (_("%s, %d %%"),
+ gtk_label_get_text (GTK_LABEL (statusbar->label)),
+ statusbar->percentage);
+ }
+
+ atk_object_set_name (obj, text);
+ g_free (text);
+}
+
+void
+totem_statusbar_set_has_resize_grip (TotemStatusbar *statusbar,
+ gboolean setting)
+{
+ g_return_if_fail (TOTEM_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)
+ totem_statusbar_create_window (statusbar);
+ else if (!statusbar->has_resize_grip && statusbar->grip_window != NULL)
+ totem_statusbar_destroy_window (statusbar);
+ }
+ }
+}
+
+gboolean
+totem_statusbar_get_has_resize_grip (TotemStatusbar *statusbar)
+{
+ g_return_val_if_fail (TOTEM_IS_STATUSBAR (statusbar), FALSE);
+
+ return statusbar->has_resize_grip;
+}
+
+static void
+totem_statusbar_destroy (GtkObject *object)
+{
+ TotemStatusbar *statusbar;
+ TotemStatusbarClass *class;
+
+ g_return_if_fail (TOTEM_IS_STATUSBAR (object));
+
+ statusbar = TOTEM_STATUSBAR (object);
+ class = TOTEM_STATUSBAR_GET_CLASS (statusbar);
+
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static GdkWindowEdge
+get_grip_edge (TotemStatusbar *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;
+}
+
+static void
+get_grip_rect (TotemStatusbar *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;
+ rect->y = widget->allocation.y + widget->allocation.height - h;
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ rect->x = widget->allocation.x + widget->allocation.width - w;
+ else
+ rect->x = widget->allocation.x + widget->style->xthickness;
+}
+
+static void
+totem_statusbar_create_window (TotemStatusbar *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);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ statusbar->cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
+ else
+ statusbar->cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
+ gdk_window_set_cursor (statusbar->grip_window, statusbar->cursor);
+}
+
+static void
+totem_statusbar_destroy_window (TotemStatusbar *statusbar)
+{
+ gdk_window_set_user_data (statusbar->grip_window, NULL);
+ gdk_window_destroy (statusbar->grip_window);
+ gdk_cursor_unref (statusbar->cursor);
+ statusbar->cursor = NULL;
+ statusbar->grip_window = NULL;
+}
+
+static void
+totem_statusbar_realize (GtkWidget *widget)
+{
+ TotemStatusbar *statusbar;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+
+ if (statusbar->has_resize_grip)
+ totem_statusbar_create_window (statusbar);
+}
+
+static void
+totem_statusbar_unrealize (GtkWidget *widget)
+{
+ TotemStatusbar *statusbar;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ if (statusbar->grip_window)
+ totem_statusbar_destroy_window (statusbar);
+
+ (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+totem_statusbar_map (GtkWidget *widget)
+{
+ TotemStatusbar *statusbar;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+
+ if (statusbar->grip_window)
+ gdk_window_show (statusbar->grip_window);
+}
+
+static void
+totem_statusbar_unmap (GtkWidget *widget)
+{
+ TotemStatusbar *statusbar;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ if (statusbar->grip_window)
+ gdk_window_hide (statusbar->grip_window);
+
+ (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
+}
+
+static gboolean
+totem_statusbar_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ TotemStatusbar *statusbar;
+ GtkWidget *ancestor;
+ GdkWindowEdge edge;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ if (!statusbar->has_resize_grip ||
+ event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ ancestor = gtk_widget_get_toplevel (widget);
+
+ if (!GTK_IS_WINDOW (ancestor))
+ return FALSE;
+
+ edge = get_grip_edge (statusbar);
+
+ if (event->button == 1)
+ gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
+ edge,
+ 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
+totem_statusbar_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ TotemStatusbar *statusbar;
+ GdkRectangle rect;
+
+ statusbar = TOTEM_STATUSBAR (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+
+ if (statusbar->has_resize_grip)
+ {
+ GdkWindowEdge edge;
+
+ edge = get_grip_edge (statusbar);
+
+ get_grip_rect (statusbar, &rect);
+
+ gtk_paint_resize_grip (widget->style,
+ widget->window,
+ GTK_WIDGET_STATE (widget),
+ NULL,
+ widget,
+ "statusbar",
+ edge,
+ 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;
+}
+
+static void
+totem_statusbar_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ TotemStatusbar *statusbar;
+ GtkShadowType shadow_type;
+
+ statusbar = TOTEM_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
+totem_statusbar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ TotemStatusbar *statusbar;
+
+ statusbar = TOTEM_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);
+ }
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */