diff options
-rw-r--r-- | embed/ephy-embed-utils.h | 2 | ||||
-rw-r--r-- | embed/ephy-embed.c | 31 | ||||
-rw-r--r-- | embed/ephy-embed.h | 1 | ||||
-rw-r--r-- | embed/ephy-web-view.c | 99 | ||||
-rw-r--r-- | lib/widgets/Makefile.am | 6 | ||||
-rw-r--r-- | lib/widgets/gedit-overlay.c | 656 | ||||
-rw-r--r-- | lib/widgets/gedit-overlay.h | 72 | ||||
-rw-r--r-- | lib/widgets/gedit-theatrics-animated-widget.c | 263 | ||||
-rw-r--r-- | lib/widgets/gedit-theatrics-animated-widget.h | 64 |
9 files changed, 1096 insertions, 98 deletions
diff --git a/embed/ephy-embed-utils.h b/embed/ephy-embed-utils.h index b1ee9adeb..cb7890002 100644 --- a/embed/ephy-embed-utils.h +++ b/embed/ephy-embed-utils.h @@ -36,7 +36,7 @@ G_BEGIN_DECLS #define EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED(embed) (WEBKIT_WEB_VIEW (ephy_embed_get_web_view (embed))) -#define EPHY_GET_EMBED_FROM_EPHY_WEB_VIEW(view) (EPHY_EMBED (gtk_widget_get_parent (gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (view)))))) +#define EPHY_GET_EMBED_FROM_EPHY_WEB_VIEW(view) (EPHY_EMBED (gtk_widget_get_parent (gtk_widget_get_parent (gtk_widget_get_parent (gtk_widget_get_parent ((GTK_WIDGET (view)))))))) #define EPHY_WEBKIT_BACK_FORWARD_LIMIT 100 diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c index 07e6ed25a..79515cb86 100644 --- a/embed/ephy-embed.c +++ b/embed/ephy-embed.c @@ -43,6 +43,7 @@ #include "ephy-stock-icons.h" #include "ephy-string.h" #include "ephy-web-view.h" +#include "gedit-overlay.h" #include <errno.h> #include <glib/gi18n.h> @@ -72,6 +73,7 @@ struct _EphyEmbedPrivate gboolean inspector_attached; guint is_setting_zoom : 1; GSList *destroy_on_transition_list; + GtkWidget *statusbar_label; }; G_DEFINE_TYPE (EphyEmbed, ephy_embed, GTK_TYPE_VBOX) @@ -840,25 +842,52 @@ download_requested_cb (WebKitWebView *web_view, return TRUE; } +/* FIXME: it probably makes sense to move this stuff completely into + * EphyEmbed now, since it's not an integral part of EphyWebView + * anymore. */ +void +_ephy_embed_set_statusbar_label (EphyEmbed *embed, const char *label) +{ + EphyEmbedPrivate *priv = embed->priv; + gtk_label_set_label (GTK_LABEL (priv->statusbar_label), label); + + if (label == NULL || label[0] == '\0') + gtk_widget_hide (priv->statusbar_label); + else + gtk_widget_show (priv->statusbar_label); +} + static void ephy_embed_constructed (GObject *object) { EphyEmbed *embed = (EphyEmbed*)object; + EphyEmbedPrivate *priv = embed->priv; GtkWidget *scrolled_window; GtkWidget *paned; WebKitWebView *web_view; WebKitWebInspector *inspector; + GtkWidget *overlay; + GtkWidget *frame; /* Skeleton */ web_view = WEBKIT_WEB_VIEW (ephy_web_view_new ()); scrolled_window = GTK_WIDGET (embed->priv->scrolled_window); + overlay = gedit_overlay_new (scrolled_window); + + /* statusbar is hidden by default */ + priv->statusbar_label = gtk_label_new (NULL); + frame = gtk_frame_new (NULL); + gtk_widget_show (frame); + gtk_container_add (GTK_CONTAINER (frame), priv->statusbar_label); + gedit_overlay_add (GEDIT_OVERLAY (overlay), frame, GTK_ORIENTATION_HORIZONTAL, GDK_GRAVITY_SOUTH_WEST, 0, TRUE); + paned = GTK_WIDGET (embed->priv->paned); embed->priv->web_view = web_view; gtk_container_add (GTK_CONTAINER (embed->priv->scrolled_window), GTK_WIDGET (web_view)); - gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (scrolled_window), + gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (overlay), TRUE, FALSE); gtk_box_pack_start (GTK_BOX (embed), diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h index 24d5f2bba..c9fc1a4c8 100644 --- a/embed/ephy-embed.h +++ b/embed/ephy-embed.h @@ -56,6 +56,7 @@ EphyWebView* ephy_embed_get_web_view (EphyEmbed *embed); void ephy_embed_add_top_widget (EphyEmbed *embed, GtkWidget *widget, gboolean destroy_on_transition); void ephy_embed_remove_top_widget (EphyEmbed *embed, GtkWidget *widget); void ephy_embed_auto_download_url (EphyEmbed *embed, const char *url); +void _ephy_embed_set_statusbar_label (EphyEmbed *embed, const char *label); G_END_DECLS diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c index e11eab665..bfa45edfa 100644 --- a/embed/ephy-web-view.c +++ b/embed/ephy-web-view.c @@ -1156,76 +1156,6 @@ ephy_web_view_constructed (GObject *object) } static void -_ephy_web_view_draw_statusbar (GtkWidget *widget, cairo_t *cr) -{ - gint width, height; - guint border_width, statusbar_border_width; - PangoLayout *layout; - GtkAllocation allocation; - GtkStyleContext *context; - EphyWebViewPrivate *priv; - - priv = EPHY_WEB_VIEW (widget)->priv; - - gtk_widget_get_allocation (widget, &allocation); - - layout = gtk_widget_create_pango_layout (widget, priv->text); - pango_layout_set_width (layout, PANGO_SCALE * (allocation.width * 0.9)); - pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); - - pango_layout_get_pixel_size (layout, &width, &height); - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - statusbar_border_width = 4; /* FIXME: what should we use here? */ - - priv->text_rectangle.x = border_width; - priv->text_rectangle.y = allocation.height - height - border_width - (statusbar_border_width * 2); - priv->text_rectangle.width = width + (statusbar_border_width * 2); - priv->text_rectangle.height = height + (statusbar_border_width * 2); - - context = gtk_widget_get_style_context (widget); - gtk_style_context_save (context); - - gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL); - gtk_render_background (context, cr, - priv->text_rectangle.x, - priv->text_rectangle.y, - priv->text_rectangle.width, - priv->text_rectangle.height); - gtk_render_frame (context, cr, - priv->text_rectangle.x, - priv->text_rectangle.y, - priv->text_rectangle.width, - priv->text_rectangle.height); - - gtk_style_context_set_state (context, 0); - gtk_render_layout (context, cr, - priv->text_rectangle.x + statusbar_border_width, - priv->text_rectangle.y + statusbar_border_width, - layout); - - gtk_style_context_restore (context); - - g_object_unref (layout); -} - -static gboolean -ephy_web_view_draw (GtkWidget *widget, cairo_t *cr) -{ - EphyWebViewPrivate *priv; - - GTK_WIDGET_CLASS (ephy_web_view_parent_class)->draw (widget, cr); - - priv = EPHY_WEB_VIEW (widget)->priv; - - if (priv->text && priv->text[0] != '\0') - _ephy_web_view_draw_statusbar (widget, cr); - - return FALSE; -} - -static void ephy_web_view_class_init (EphyWebViewClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); @@ -1239,7 +1169,6 @@ ephy_web_view_class_init (EphyWebViewClass *klass) widget_class->button_press_event = ephy_web_view_button_press_event; widget_class->key_press_event = ephy_web_view_key_press_event; - widget_class->draw = ephy_web_view_draw; /** * EphyWebView:address: @@ -3752,32 +3681,12 @@ ephy_web_view_load_homepage (EphyWebView *view) static void ephy_web_view_statusbar_update (EphyWebView *view, const char *text) { - EphyWebViewPrivate *priv; - GdkWindow *window; - GdkRectangle rect; - - priv = view->priv; - - if (priv->text) - g_free (priv->text); - - priv->text = g_strdup (text); - - /* FIXME: we should invalidate the union of the sizes of the - * rectangles of the previous and next statusbar text */ - window = gtk_widget_get_window (GTK_WIDGET (view)); - if (window) { - GtkAllocation allocation; + EphyEmbed *embed; - gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + g_return_if_fail (EPHY_IS_WEB_VIEW (view)); - rect = priv->text_rectangle; - rect.width = allocation.width; - if (rect.height == 0) - rect.height = allocation.height; - - gdk_window_invalidate_rect (window, &rect, TRUE); - } + embed = EPHY_GET_EMBED_FROM_EPHY_WEB_VIEW (view); + _ephy_embed_set_statusbar_label (embed, text); } /* Portions of the following code based on GTK+. diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am index 48c60e28c..f41adac18 100644 --- a/lib/widgets/Makefile.am +++ b/lib/widgets/Makefile.am @@ -14,7 +14,11 @@ libephywidgets_la_SOURCES = \ ephy-zoom-action.h \ ephy-zoom-action.c \ ephy-zoom-control.c \ - ephy-zoom-control.h + ephy-zoom-control.h \ + gedit-overlay.c \ + gedit-overlay.h \ + gedit-theatrics-animated-widget.c \ + gedit-theatrics-animated-widget.h libephywidgets_la_CPPFLAGS = \ -I$(top_builddir)/lib \ diff --git a/lib/widgets/gedit-overlay.c b/lib/widgets/gedit-overlay.c new file mode 100644 index 000000000..1972adaa1 --- /dev/null +++ b/lib/widgets/gedit-overlay.c @@ -0,0 +1,656 @@ +/* + * gedit-overlay.c + * This file is part of gedit + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * Based on Mike Krüger <mkrueger@novell.com> work. + * + * gedit is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * gedit 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 + * along with gedit; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gedit-overlay.h" +#include "gedit-theatrics-animated-widget.h" + +#define GEDIT_OVERLAY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_OVERLAY, GeditOverlayPrivate)) + +typedef struct _OverlayChild +{ + GtkWidget *child; + GdkGravity gravity; + guint offset; + + guint fixed_position : 1; + guint is_animated : 1; +} OverlayChild; + +struct _GeditOverlayPrivate +{ + GtkWidget *main_widget; + GSList *children; + GtkAllocation main_alloc; + + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; + glong hadjustment_signal_id; + glong vadjustment_signal_id; + + /* GtkScrollablePolicy needs to be checked when + * driving the scrollable adjustment values */ + guint hscroll_policy : 1; + guint vscroll_policy : 1; +}; + +enum +{ + PROP_0, + PROP_MAIN_WIDGET, + PROP_HADJUSTMENT, + PROP_VADJUSTMENT, + PROP_HSCROLL_POLICY, + PROP_VSCROLL_POLICY +}; + +static void gedit_overlay_set_hadjustment (GeditOverlay *overlay, + GtkAdjustment *adjustment); +static void gedit_overlay_set_vadjustment (GeditOverlay *overlay, + GtkAdjustment *adjustment); + +G_DEFINE_TYPE_WITH_CODE (GeditOverlay, gedit_overlay, GTK_TYPE_CONTAINER, + G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL)) + +static void +free_container_child (OverlayChild *child) +{ + g_slice_free (OverlayChild, child); +} + +static void +add_toplevel_widget (GeditOverlay *overlay, + GtkWidget *widget, + gboolean fixed_position, + gboolean is_animated, + GdkGravity gravity, + guint offset) +{ + OverlayChild *child = g_slice_new (OverlayChild); + + child->child = widget; + child->gravity = gravity; + child->fixed_position = fixed_position; + child->is_animated = is_animated; + child->offset = offset; + + gtk_widget_set_parent (widget, GTK_WIDGET (overlay)); + + overlay->priv->children = g_slist_append (overlay->priv->children, + child); +} + +static void +gedit_overlay_finalize (GObject *object) +{ + GeditOverlay *overlay = GEDIT_OVERLAY (object); + + g_slist_free (overlay->priv->children); + + G_OBJECT_CLASS (gedit_overlay_parent_class)->finalize (object); +} + +static void +gedit_overlay_dispose (GObject *object) +{ + GeditOverlay *overlay = GEDIT_OVERLAY (object); + + if (overlay->priv->hadjustment != NULL) + { + g_signal_handler_disconnect (overlay->priv->hadjustment, + overlay->priv->hadjustment_signal_id); + overlay->priv->hadjustment = NULL; + } + + if (overlay->priv->vadjustment != NULL) + { + g_signal_handler_disconnect (overlay->priv->vadjustment, + overlay->priv->vadjustment_signal_id); + overlay->priv->vadjustment = NULL; + } + + G_OBJECT_CLASS (gedit_overlay_parent_class)->dispose (object); +} + +static void +gedit_overlay_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GeditOverlay *overlay = GEDIT_OVERLAY (object); + GeditOverlayPrivate *priv = overlay->priv; + + switch (prop_id) + { + case PROP_MAIN_WIDGET: + g_value_set_object (value, priv->main_widget); + break; + + case PROP_HADJUSTMENT: + g_value_set_object (value, priv->hadjustment); + break; + + case PROP_VADJUSTMENT: + g_value_set_object (value, priv->vadjustment); + break; + + case PROP_HSCROLL_POLICY: + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + g_value_set_enum (value, + gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (priv->main_widget))); + } + else + { + g_value_set_enum (value, priv->hscroll_policy); + } + break; + + case PROP_VSCROLL_POLICY: + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + g_value_set_enum (value, + gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (priv->main_widget))); + } + else + { + g_value_set_enum (value, priv->vscroll_policy); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_overlay_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GeditOverlay *overlay = GEDIT_OVERLAY (object); + GeditOverlayPrivate *priv = overlay->priv; + + switch (prop_id) + { + case PROP_MAIN_WIDGET: + overlay->priv->main_widget = g_value_get_object (value); + add_toplevel_widget (overlay, + overlay->priv->main_widget, + TRUE, FALSE, GDK_GRAVITY_STATIC, + 0); + break; + + case PROP_HADJUSTMENT: + gedit_overlay_set_hadjustment (overlay, + g_value_get_object (value)); + break; + + case PROP_VADJUSTMENT: + gedit_overlay_set_vadjustment (overlay, + g_value_get_object (value)); + break; + + case PROP_HSCROLL_POLICY: + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (priv->main_widget), + g_value_get_enum (value)); + } + else + { + priv->hscroll_policy = g_value_get_enum (value); + gtk_widget_queue_resize (GTK_WIDGET (overlay)); + } + break; + + case PROP_VSCROLL_POLICY: + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (priv->main_widget), + g_value_get_enum (value)); + } + else + { + priv->vscroll_policy = g_value_get_enum (value); + gtk_widget_queue_resize (GTK_WIDGET (overlay)); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_overlay_realize (GtkWidget *widget) +{ + GtkAllocation allocation; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + GtkStyleContext *context; + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + + window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gtk_widget_set_window (widget, window); + gdk_window_set_user_data (window, widget); + + context = gtk_widget_get_style_context (widget); + gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL); + gtk_style_context_set_background (context, window); +} + +static void +gedit_overlay_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GeditOverlayPrivate *priv = GEDIT_OVERLAY (widget)->priv; + OverlayChild *child; + GSList *children; + gint child_min, child_nat; + + *minimum = 0; + *natural = 0; + + for (children = priv->children; children; children = children->next) + { + child = children->data; + + if (!gtk_widget_get_visible (child->child)) + continue; + + gtk_widget_get_preferred_width (child->child, &child_min, &child_nat); + + *minimum = MAX (*minimum, child_min); + *natural = MAX (*natural, child_nat); + } +} + +static void +gedit_overlay_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GeditOverlayPrivate *priv = GEDIT_OVERLAY (widget)->priv; + OverlayChild *child; + GSList *children; + gint child_min, child_nat; + + *minimum = 0; + *natural = 0; + + for (children = priv->children; children; children = children->next) + { + child = children->data; + + if (!gtk_widget_get_visible (child->child)) + continue; + + gtk_widget_get_preferred_height (child->child, &child_min, &child_nat); + + *minimum = MAX (*minimum, child_min); + *natural = MAX (*natural, child_nat); + } +} + +static void +set_children_positions (GeditOverlay *overlay) +{ + GSList *l; + + for (l = overlay->priv->children; l != NULL; l = g_slist_next (l)) + { + GeditOverlayPrivate *priv = overlay->priv; + OverlayChild *child = (OverlayChild *)l->data; + GtkRequisition req; + GtkAllocation alloc; + + if (child->child == priv->main_widget) + continue; + + gtk_widget_get_preferred_size (child->child, &req, NULL); + + /* FIXME: Add all the gravities here */ + switch (child->gravity) + { + /* The gravity is treated as position and not as a gravity */ + case GDK_GRAVITY_NORTH_EAST: + alloc.x = priv->main_alloc.width - req.width - child->offset; + alloc.y = 0; + break; + case GDK_GRAVITY_NORTH_WEST: + alloc.x = child->offset; + alloc.y = 0; + break; + case GDK_GRAVITY_SOUTH_WEST: + alloc.x = child->offset; + alloc.y = priv->main_alloc.height - req.height; + break; + default: + alloc.x = 0; + alloc.y = 0; + } + + if (!child->fixed_position) + { + alloc.x *= gtk_adjustment_get_value (priv->hadjustment); + alloc.y *= gtk_adjustment_get_value (priv->vadjustment); + } + + alloc.width = req.width; + alloc.height = req.height; + + gtk_widget_size_allocate (child->child, &alloc); + } +} + +static void +gedit_overlay_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GeditOverlay *overlay = GEDIT_OVERLAY (widget); + + GTK_WIDGET_CLASS (gedit_overlay_parent_class)->size_allocate (widget, allocation); + + overlay->priv->main_alloc.x = 0; + overlay->priv->main_alloc.y = 0; + overlay->priv->main_alloc.width = allocation->width; + overlay->priv->main_alloc.height = allocation->height; + + gtk_widget_size_allocate (overlay->priv->main_widget, + &overlay->priv->main_alloc); + set_children_positions (overlay); +} + +static void +overlay_add (GtkContainer *overlay, + GtkWidget *widget) +{ + add_toplevel_widget (GEDIT_OVERLAY (overlay), widget, + FALSE, FALSE, GDK_GRAVITY_STATIC, 0); +} + +static void +gedit_overlay_remove (GtkContainer *overlay, + GtkWidget *widget) +{ + GeditOverlay *goverlay = GEDIT_OVERLAY (overlay); + GSList *l; + + for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l)) + { + OverlayChild *child = (OverlayChild *)l->data; + + if (child->child == widget) + { + gtk_widget_unparent (widget); + goverlay->priv->children = g_slist_remove_link (goverlay->priv->children, + l); + free_container_child (child); + break; + } + } +} + +static void +gedit_overlay_forall (GtkContainer *overlay, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GeditOverlay *goverlay = GEDIT_OVERLAY (overlay); + GSList *l; + + for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l)) + { + OverlayChild *child = (OverlayChild *)l->data; + + (* callback) (child->child, callback_data); + } +} + +static GType +gedit_overlay_child_type (GtkContainer *overlay) +{ + return GTK_TYPE_WIDGET; +} + +static void +adjustment_value_changed (GtkAdjustment *adjustment, + GeditOverlay *overlay) +{ + set_children_positions (overlay); +} + +static void +gedit_overlay_set_hadjustment (GeditOverlay *overlay, + GtkAdjustment *adjustment) +{ + GeditOverlayPrivate *priv = overlay->priv; + + if (adjustment && priv->vadjustment == adjustment) + return; + + if (priv->hadjustment != NULL) + { + g_signal_handler_disconnect (priv->hadjustment, + priv->hadjustment_signal_id); + g_object_unref (priv->hadjustment); + } + + if (adjustment == NULL) + { + adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0); + } + + priv->hadjustment_signal_id = + g_signal_connect (adjustment, + "value-changed", + G_CALLBACK (adjustment_value_changed), + overlay); + + priv->hadjustment = g_object_ref_sink (adjustment); + + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + g_object_set (priv->main_widget, + "hadjustment", adjustment, + NULL); + + } + + g_object_notify (G_OBJECT (overlay), "hadjustment"); +} + +static void +gedit_overlay_set_vadjustment (GeditOverlay *overlay, + GtkAdjustment *adjustment) +{ + GeditOverlayPrivate *priv = overlay->priv; + + if (adjustment && priv->vadjustment == adjustment) + return; + + if (priv->vadjustment != NULL) + { + g_signal_handler_disconnect (priv->vadjustment, + priv->vadjustment_signal_id); + g_object_unref (priv->vadjustment); + } + + if (adjustment == NULL) + { + adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0); + } + + overlay->priv->vadjustment_signal_id = + g_signal_connect (adjustment, + "value-changed", + G_CALLBACK (adjustment_value_changed), + overlay); + + priv->vadjustment = g_object_ref_sink (adjustment); + + if (GTK_IS_SCROLLABLE (priv->main_widget)) + { + g_object_set (priv->main_widget, + "vadjustment", adjustment, + NULL); + } + + g_object_notify (G_OBJECT (overlay), "vadjustment"); +} + +static void +gedit_overlay_class_init (GeditOverlayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->finalize = gedit_overlay_finalize; + object_class->dispose = gedit_overlay_dispose; + object_class->get_property = gedit_overlay_get_property; + object_class->set_property = gedit_overlay_set_property; + + widget_class->realize = gedit_overlay_realize; + widget_class->get_preferred_width = gedit_overlay_get_preferred_width; + widget_class->get_preferred_height = gedit_overlay_get_preferred_height; + widget_class->size_allocate = gedit_overlay_size_allocate; + + container_class->add = overlay_add; + container_class->remove = gedit_overlay_remove; + container_class->forall = gedit_overlay_forall; + container_class->child_type = gedit_overlay_child_type; + + g_object_class_install_property (object_class, PROP_MAIN_WIDGET, + g_param_spec_object ("main-widget", + "Main Widget", + "The Main Widget", + GTK_TYPE_WIDGET, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_override_property (object_class, + PROP_HADJUSTMENT, + "hadjustment"); + g_object_class_override_property (object_class, + PROP_VADJUSTMENT, + "vadjustment"); + g_object_class_override_property (object_class, + PROP_HSCROLL_POLICY, + "hscroll-policy"); + g_object_class_override_property (object_class, + PROP_VSCROLL_POLICY, + "vscroll-policy"); + + g_type_class_add_private (object_class, sizeof (GeditOverlayPrivate)); +} + +static void +gedit_overlay_init (GeditOverlay *overlay) +{ + overlay->priv = GEDIT_OVERLAY_GET_PRIVATE (overlay); +} + +GtkWidget * +gedit_overlay_new (GtkWidget *main_widget) +{ + return GTK_WIDGET (g_object_new (GEDIT_TYPE_OVERLAY, + "main-widget", main_widget, + NULL)); +} + +static GeditTheatricsAnimatedWidget * +get_animated_widget (GeditOverlay *overlay, + GtkWidget *widget) +{ + GSList *l; + + for (l = overlay->priv->children; l != NULL; l = g_slist_next (l)) + { + OverlayChild *child = (OverlayChild *)l->data; + GtkWidget *in_widget; + + if (!child->is_animated) + continue; + + g_object_get (child->child, "widget", &in_widget, NULL); + g_assert (in_widget != NULL); + + if (in_widget == widget) + { + return GEDIT_THEATRICS_ANIMATED_WIDGET (child->child); + } + } + + return NULL; +} + +/* Note: see that we use the gravity as a position */ +void +gedit_overlay_add (GeditOverlay *overlay, + GtkWidget *widget, + GtkOrientation orientation, + GdkGravity gravity, + guint offset, + gboolean in) +{ + GeditTheatricsAnimatedWidget *anim_widget; + + anim_widget = get_animated_widget (overlay, widget); + + if (anim_widget == NULL) + { + anim_widget = gedit_theatrics_animated_widget_new (widget, orientation); + gtk_widget_show (GTK_WIDGET (anim_widget)); + + add_toplevel_widget (overlay, GTK_WIDGET (anim_widget), TRUE, + TRUE, gravity, offset); + } +} diff --git a/lib/widgets/gedit-overlay.h b/lib/widgets/gedit-overlay.h new file mode 100644 index 000000000..a5335dd37 --- /dev/null +++ b/lib/widgets/gedit-overlay.h @@ -0,0 +1,72 @@ +/* + * gedit-overlay.h + * This file is part of gedit + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * gedit is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * gedit 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 + * along with gedit; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __GEDIT_OVERLAY_H__ +#define __GEDIT_OVERLAY_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GEDIT_TYPE_OVERLAY (gedit_overlay_get_type ()) +#define GEDIT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay)) +#define GEDIT_OVERLAY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay const)) +#define GEDIT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_OVERLAY, GeditOverlayClass)) +#define GEDIT_IS_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_OVERLAY)) +#define GEDIT_IS_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_OVERLAY)) +#define GEDIT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_OVERLAY, GeditOverlayClass)) + +typedef struct _GeditOverlay GeditOverlay; +typedef struct _GeditOverlayClass GeditOverlayClass; +typedef struct _GeditOverlayPrivate GeditOverlayPrivate; + +struct _GeditOverlay +{ + GtkContainer parent; + + GeditOverlayPrivate *priv; +}; + +struct _GeditOverlayClass +{ + GtkContainerClass parent_class; + + void (* set_scroll_adjustments) (GeditOverlay *overlay, + GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +}; + +GType gedit_overlay_get_type (void) G_GNUC_CONST; + +GtkWidget *gedit_overlay_new (GtkWidget *main_widget); + +void gedit_overlay_add (GeditOverlay *overlay, + GtkWidget *widget, + GtkOrientation orientation, + GdkGravity gravity, + guint offset, + gboolean in); + +G_END_DECLS + +#endif /* __GEDIT_OVERLAY_H__ */ diff --git a/lib/widgets/gedit-theatrics-animated-widget.c b/lib/widgets/gedit-theatrics-animated-widget.c new file mode 100644 index 000000000..8be6a64d0 --- /dev/null +++ b/lib/widgets/gedit-theatrics-animated-widget.c @@ -0,0 +1,263 @@ +/* + * gedit-theatrics-animated-widget.c + * This file is part of gedit + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * Based on Scott Peterson <lunchtimemama@gmail.com> work. + * + * gedit is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * gedit 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 + * along with gedit; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "gedit-theatrics-animated-widget.h" + +#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetPrivate)) + +struct _GeditTheatricsAnimatedWidgetPrivate +{ + GtkWidget *widget; + GtkOrientation orientation; + GtkAllocation widget_alloc; +}; + +enum +{ + PROP_0, + PROP_WIDGET, + PROP_ORIENTATION +}; + +G_DEFINE_TYPE_EXTENDED (GeditTheatricsAnimatedWidget, + gedit_theatrics_animated_widget, + GTK_TYPE_BIN, + 0, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, + NULL)) + +static void +gedit_theatrics_animated_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object); + + switch (prop_id) + { + case PROP_WIDGET: + g_value_set_object (value, aw->priv->widget); + break; + case PROP_ORIENTATION: + g_value_set_enum (value, aw->priv->orientation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_theatrics_animated_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object); + + switch (prop_id) + { + case PROP_WIDGET: + { + gtk_container_add (GTK_CONTAINER (aw), + g_value_get_object (value)); + break; + } + case PROP_ORIENTATION: + aw->priv->orientation = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gedit_theatrics_animated_widget_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + GdkWindow *parent_window; + GdkWindow *window; + GtkStyleContext *context; + + gtk_widget_set_realized (widget, TRUE); + + parent_window = gtk_widget_get_parent_window (widget); + context = gtk_widget_get_style_context (widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.event_mask = GDK_EXPOSURE_MASK; + + window = gdk_window_new (parent_window, &attributes, 0); + gdk_window_set_user_data (window, widget); + gtk_widget_set_window (widget, window); + gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL); + gtk_style_context_set_background (context, window); +} + +static void +gedit_theatrics_animated_widget_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget); + gint width; + + if (aw->priv->widget != NULL) + { + gint child_min, child_nat; + + gtk_widget_get_preferred_width (aw->priv->widget, + &child_min, &child_nat); + aw->priv->widget_alloc.width = child_min; + } + + width = aw->priv->widget_alloc.width; + *minimum = *natural = width; +} + +static void +gedit_theatrics_animated_widget_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget); + gint height; + + if (aw->priv->widget != NULL) + { + gint child_min, child_nat; + + gtk_widget_get_preferred_height (aw->priv->widget, + &child_min, &child_nat); + aw->priv->widget_alloc.height = child_min; + } + + height = aw->priv->widget_alloc.height; + *minimum = *natural = height; +} + +static void +gedit_theatrics_animated_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget); + + GTK_WIDGET_CLASS (gedit_theatrics_animated_widget_parent_class)->size_allocate (widget, allocation); + + if (aw->priv->widget != NULL) + { + if (aw->priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + aw->priv->widget_alloc.height = allocation->height; + aw->priv->widget_alloc.x = 0; + } + + if (aw->priv->widget_alloc.height > 0 && aw->priv->widget_alloc.width > 0) + { + gtk_widget_size_allocate (aw->priv->widget, + &aw->priv->widget_alloc); + } + } +} + +static void +gedit_theatrics_animated_widget_add (GtkContainer *container, + GtkWidget *widget) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container); + + aw->priv->widget = widget; + + GTK_CONTAINER_CLASS (gedit_theatrics_animated_widget_parent_class)->add (container, widget); +} + +static void +gedit_theatrics_animated_widget_remove (GtkContainer *container, + GtkWidget *widget) +{ + GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container); + + aw->priv->widget = NULL; + + GTK_CONTAINER_CLASS (gedit_theatrics_animated_widget_parent_class)->remove (container, widget); +} + +static void +gedit_theatrics_animated_widget_class_init (GeditTheatricsAnimatedWidgetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->get_property = gedit_theatrics_animated_widget_get_property; + object_class->set_property = gedit_theatrics_animated_widget_set_property; + + widget_class->realize = gedit_theatrics_animated_widget_realize; + widget_class->get_preferred_width = gedit_theatrics_animated_widget_get_preferred_width; + widget_class->get_preferred_height = gedit_theatrics_animated_widget_get_preferred_height; + widget_class->size_allocate = gedit_theatrics_animated_widget_size_allocate; + + container_class->add = gedit_theatrics_animated_widget_add; + container_class->remove = gedit_theatrics_animated_widget_remove; + + g_object_class_install_property (object_class, PROP_WIDGET, + g_param_spec_object ("widget", + "Widget", + "The Widget", + GTK_TYPE_WIDGET, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_override_property (object_class, + PROP_ORIENTATION, + "orientation"); + + g_type_class_add_private (object_class, sizeof (GeditTheatricsAnimatedWidgetPrivate)); +} + +static void +gedit_theatrics_animated_widget_init (GeditTheatricsAnimatedWidget *aw) +{ + aw->priv = GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE (aw); + + gtk_widget_set_has_window (GTK_WIDGET (aw), TRUE); + + aw->priv->orientation = GTK_ORIENTATION_HORIZONTAL; +} + +GeditTheatricsAnimatedWidget * +gedit_theatrics_animated_widget_new (GtkWidget *widget, + GtkOrientation orientation) +{ + return g_object_new (GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, + "widget", widget, + "orientation", orientation, + NULL); +} + +/* ex:set ts=8 noet: */ diff --git a/lib/widgets/gedit-theatrics-animated-widget.h b/lib/widgets/gedit-theatrics-animated-widget.h new file mode 100644 index 000000000..5fe82760e --- /dev/null +++ b/lib/widgets/gedit-theatrics-animated-widget.h @@ -0,0 +1,64 @@ +/* + * gedit-theatrics-animated-widget.h + * This file is part of gedit + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * Based on Scott Peterson <lunchtimemama@gmail.com> work. + * + * gedit is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * gedit 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 + * along with gedit; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __GEDIT_THEATRICS_ANIMATED_WIDGET_H__ +#define __GEDIT_THEATRICS_ANIMATED_WIDGET_H__ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET (gedit_theatrics_animated_widget_get_type ()) +#define GEDIT_THEATRICS_ANIMATED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget)) +#define GEDIT_THEATRICS_ANIMATED_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget const)) +#define GEDIT_THEATRICS_ANIMATED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass)) +#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET)) +#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET)) +#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass)) + +typedef struct _GeditTheatricsAnimatedWidget GeditTheatricsAnimatedWidget; +typedef struct _GeditTheatricsAnimatedWidgetClass GeditTheatricsAnimatedWidgetClass; +typedef struct _GeditTheatricsAnimatedWidgetPrivate GeditTheatricsAnimatedWidgetPrivate; + +struct _GeditTheatricsAnimatedWidget +{ + GtkBin parent; + + GeditTheatricsAnimatedWidgetPrivate *priv; +}; + +struct _GeditTheatricsAnimatedWidgetClass +{ + GtkBinClass parent_class; +}; + +GType gedit_theatrics_animated_widget_get_type (void) G_GNUC_CONST; + +GeditTheatricsAnimatedWidget *gedit_theatrics_animated_widget_new (GtkWidget *widget, + GtkOrientation orientation); + +G_END_DECLS + +#endif /* __GEDIT_THEATRICS_ANIMATED_WIDGET_H__ */ |