diff options
-rw-r--r-- | .bzrignore | 29 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | src/Makefile.am | 24 | ||||
-rw-r--r-- | src/idocalendarmenuitem.c | 61 | ||||
-rw-r--r-- | src/idooffscreenproxy.c | 512 | ||||
-rw-r--r-- | src/idooffscreenproxy.h | 62 | ||||
-rw-r--r-- | src/idoscalemenuitem.c | 77 |
7 files changed, 743 insertions, 25 deletions
diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..7d5438e --- /dev/null +++ b/.bzrignore @@ -0,0 +1,29 @@ +compile +gtk-doc.make +libido.pc +libido3-0.1.pc +libido3.pc +build/autotools/gtk-doc.m4 +build/autotools/libtool.m4 +build/autotools/ltoptions.m4 +build/autotools/ltsugar.m4 +build/autotools/ltversion.m4 +build/autotools/lt~obsolete.m4 +build/autotools/shave +build/autotools/shave-libtool +example/.deps +example/.libs +example/menus +example/messagedialog +src/idocalendarmenuitem.lo +src/idoentrymenuitem.lo +src/idomessagedialog.lo +src/idooffscreenproxy.lo +src/idorange.lo +src/idoscalemenuitem.lo +src/idotimeline.lo +src/idotypebuiltins.c +src/idotypebuiltins.h +src/idotypebuiltins.lo +src/libido3-0.1.la +src/stamp-idotypebuiltins.h diff --git a/configure.ac b/configure.ac index 3694e3e..a712bd8 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ # m4_define([ido_major_version], [0]) m4_define([ido_minor_version], [2]) -m4_define([ido_micro_version], [90]) +m4_define([ido_micro_version], [92]) m4_define([ido_api_version], [ido_major_version.ido_minor_version]) @@ -88,6 +88,7 @@ if test "x$with_gtk" = "x2"; then PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.19.7) else PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.0.0) + AC_DEFINE_UNQUOTED(USE_GTK3, , [Use GTK3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) diff --git a/src/Makefile.am b/src/Makefile.am index 5ac5a01..ac34bf4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,13 +20,21 @@ sources_h = \ idorange.h \ idoscalemenuitem.h \ idotimeline.h \ - libido.h + libido.h EXTRA_DIST = \ ido.list \ idotypebuiltins.h.template \ idotypebuiltins.c.template + +if USE_GTK3 +sources_h += idooffscreenproxy.h +else +EXTRA_DIST += idooffscreenproxy.h \ + idooffscreenproxy.c +endif + idotypebuiltins.h: stamp-idotypebuiltins.h stamp-idotypebuiltins.h: $(sources_h) @@ -53,7 +61,8 @@ INCLUDES = \ AM_CPPFLAGS = \ $(GCC_FLAGS) \ $(GTK_CFLAGS) \ - $(MAINTAINER_CFLAGS) + $(MAINTAINER_CFLAGS) \ + -Wall -Werror -Wextra -Wno-unused-parameter libido_0_1_la_SOURCES = \ idotypebuiltins.c \ @@ -62,7 +71,12 @@ libido_0_1_la_SOURCES = \ idomessagedialog.c \ idorange.c \ idoscalemenuitem.c \ - idotimeline.c + idotimeline.c + +if USE_GTK3 +libido_0_1_la_SOURCES += idooffscreenproxy.c +endif + libido3_0_1_la_SOURCES = $(libido_0_1_la_SOURCES) libidoincludedir=$(includedir)/libido$(VER)-0.1/libido @@ -76,6 +90,10 @@ libidoinclude_HEADERS = \ idotimeline.h \ libido.h +if USE_GTK3 +libidoinclude_HEADERS += idooffscreenproxy.h +endif + libido_0_1_la_LIBADD = $(GTK_LIBS) libido_0_1_la_LDFLAGS = $(GTK_LT_LDFLAGS) libido3_0_1_la_LIBADD = $(libido_0_1_la_LIBADD) diff --git a/src/idocalendarmenuitem.c b/src/idocalendarmenuitem.c index 6d5c077..40d96a1 100644 --- a/src/idocalendarmenuitem.c +++ b/src/idocalendarmenuitem.c @@ -196,31 +196,62 @@ static gboolean ido_calendar_menu_item_button_press (GtkWidget *widget, GdkEventButton *event) { - GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; + GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; - if (event->button == 1) - { - if (gtk_widget_get_window (calendar) != NULL) - { - gdk_window_raise (gtk_widget_get_window (calendar)); - } + if (event->button == 1) { + if (gtk_widget_get_window (calendar) != NULL) { + gdk_window_raise (gtk_widget_get_window (calendar)); + } - if (!gtk_widget_has_focus (calendar)) - { - gtk_widget_grab_focus (calendar); - } + if (!gtk_widget_has_focus (calendar)) { + gtk_widget_grab_focus (calendar); + } - return TRUE; - } +#if GTK_CHECK_VERSION (3, 0, 0) + GdkEvent * newevent = gdk_event_copy((GdkEvent *)(event)); + GList * children = gdk_window_get_children(gtk_widget_get_window(calendar)); + GList * child; - return FALSE; + gint root_x = event->x_root; + gint root_y = event->y_root; + + for (child = children; child != NULL; child = g_list_next(child)) { + gint newx, newy; + gint winx, winy; + GdkWindow * newwindow = (GdkWindow*)child->data; + + ((GdkEventButton *)newevent)->window = newwindow; + + gdk_window_get_origin(newwindow, &winx, &winy); + newx = root_x - winx; + newy = root_y - winy; + + if (newx >= 0 && newy >= 0 && newx < gdk_window_get_width(newwindow) && newy < gdk_window_get_height(newwindow)) { + ((GdkEventButton *)newevent)->x = newx; + ((GdkEventButton *)newevent)->y = newy; + + GTK_WIDGET_GET_CLASS(calendar)->button_press_event(GTK_WIDGET(calendar), (GdkEventButton*)newevent); + } + } + + ((GdkEventButton *)newevent)->window = event->window; + gdk_event_free(newevent); +#endif + + return TRUE; + } + + return FALSE; } static gboolean ido_calendar_menu_item_button_release (GtkWidget *widget, GdkEventButton *event) { - // GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; +#if GTK_CHECK_VERSION (3, 0, 0) + GtkWidget *calendar = IDO_CALENDAR_MENU_ITEM (widget)->priv->calendar; + GTK_WIDGET_GET_CLASS(calendar)->button_release_event(GTK_WIDGET(calendar), event); +#endif return TRUE; } diff --git a/src/idooffscreenproxy.c b/src/idooffscreenproxy.c new file mode 100644 index 0000000..50a087d --- /dev/null +++ b/src/idooffscreenproxy.c @@ -0,0 +1,512 @@ +/* + * Copyright 2011 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of either or both of the following licenses: + * + * 1) the GNU Lesser General Public License version 3, as published by the + * Free Software Foundation; and/or + * 2) the GNU Lesser General Public License version 2.1, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 and version 2.1 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authors: + * Robert Carr <racarr@canonical.com> + */ + +#include <gtk/gtk.h> +#include "idooffscreenproxy.h" + +struct _IdoOffscreenProxyPrivate +{ + GtkWidget *child; + + GdkWindow *offscreen_window; +}; + +static void ido_offscreen_proxy_realize (GtkWidget *widget); +static void ido_offscreen_proxy_unrealize (GtkWidget *widget); +static void ido_offscreen_proxy_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural); +static void ido_offscreen_proxy_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); + +static void ido_offscreen_proxy_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gboolean ido_offscreen_proxy_damage (GtkWidget *widget, + GdkEventExpose *event); +static gboolean ido_offscreen_proxy_draw (GtkWidget *widget, + cairo_t *cr); +static void ido_offscreen_proxy_add (GtkContainer *container, + GtkWidget *child); +static void ido_offscreen_proxy_remove (GtkContainer *container, + GtkWidget *widget); +static void ido_offscreen_proxy_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GType ido_offscreen_proxy_child_type (GtkContainer *container); + +static cairo_surface_t * ido_offscreen_proxy_create_alpha_image_surface (GdkWindow *offscreen, gint width, gint height); + + + +G_DEFINE_TYPE (IdoOffscreenProxy, ido_offscreen_proxy, GTK_TYPE_CONTAINER); + +#define IDO_OFFSCREEN_PROXY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), IDO_TYPE_OFFSCREEN_PROXY, IdoOffscreenProxyPrivate)) + +static void +ido_offscreen_proxy_class_init (IdoOffscreenProxyClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IdoOffscreenProxyPrivate)); + + widget_class->realize = ido_offscreen_proxy_realize; + widget_class->unrealize = ido_offscreen_proxy_unrealize; + widget_class->get_preferred_width = ido_offscreen_proxy_get_preferred_width; + widget_class->get_preferred_height = ido_offscreen_proxy_get_preferred_height; + widget_class->size_allocate = ido_offscreen_proxy_size_allocate; + widget_class->draw = ido_offscreen_proxy_draw; + + g_signal_override_class_closure (g_signal_lookup ("damage-event", GTK_TYPE_WIDGET), + IDO_TYPE_OFFSCREEN_PROXY, + g_cclosure_new (G_CALLBACK (ido_offscreen_proxy_damage), + NULL, NULL)); + + container_class->add = ido_offscreen_proxy_add; + container_class->remove = ido_offscreen_proxy_remove; + container_class->forall = ido_offscreen_proxy_forall; + container_class->child_type = ido_offscreen_proxy_child_type; + +} + +static void +ido_offscreen_proxy_init (IdoOffscreenProxy *proxy) +{ + proxy->priv = IDO_OFFSCREEN_PROXY_GET_PRIVATE (proxy); + + gtk_widget_set_has_window (GTK_WIDGET (proxy), TRUE); + + gtk_widget_set_events (GTK_WIDGET(proxy), gtk_widget_get_events (GTK_WIDGET(proxy)) + | GDK_EXPOSURE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_SCROLL_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK); + + gtk_container_set_border_width (GTK_CONTAINER (proxy), 0); +} + +GtkWidget * +ido_offscreen_proxy_new (void) +{ + return g_object_new (IDO_TYPE_OFFSCREEN_PROXY, NULL); +} + +static GdkWindow * +pick_offscreen_child (GdkWindow *offscreen_window, + double widget_x, double widget_y, + IdoOffscreenProxy *proxy) +{ + GtkAllocation child_area; + + if (proxy->priv->child && gtk_widget_get_visible (proxy->priv->child)) + { + gtk_widget_get_allocation (proxy->priv->child, &child_area); + + // if (widget_x >= 0 && widget_x < child_area.width && + // widget_y >= 0 && widget_y < child_area.height) + //return proxy->priv->offscreen_window; + return proxy->priv->offscreen_window; + } + + return NULL; +} + +static void +offscreen_to_parent (GdkWindow *offscreen_window, + double offscreen_x, + double offscreen_y, + double *parent_x, + double *parent_y, + gpointer user_data) +{ + *parent_x = offscreen_x; + *parent_y = offscreen_y; +} + +static void +offscreen_from_parent (GdkWindow *window, + double parent_x, + double parent_y, + double *offscreen_x, + double *offscreen_y, + gpointer user_data) +{ + *offscreen_x = parent_x; + *offscreen_y = parent_y; +} + +static cairo_surface_t * +ido_offscreen_proxy_create_alpha_image_surface (GdkWindow *offscreen, gint width, gint height) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); +} + +static void +proxy_add_css (GtkStyleContext *sc) +{ + GtkCssProvider *provider = gtk_css_provider_new(); + const gchar *proxy_css = ".menu.ido-offscreen { \nborder-width: 0;\nborder-radius:0; \n}\n"; + + gtk_css_provider_load_from_data (provider, proxy_css, -1, NULL); + + gtk_style_context_add_provider (sc, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + +} + +static void +ido_offscreen_proxy_realize (GtkWidget *widget) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (widget); + GtkAllocation allocation, child_area; + GtkStyleContext *context; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + // GtkRequisition child_requisition; + + gtk_widget_set_realized (widget, TRUE); + + gtk_widget_get_allocation (widget, &allocation); + + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_EXPOSURE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_SCROLL_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + attributes.visual = gdk_screen_get_rgba_visual (gdk_screen_get_default ());//gtk_widget_get_visual (widget); + attributes.wclass = GDK_INPUT_OUTPUT; + + 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); + + g_signal_connect (window, "pick-embedded-child", + G_CALLBACK (pick_offscreen_child), proxy); + + attributes.window_type = GDK_WINDOW_OFFSCREEN; + attributes.x = attributes.y = 0; + + if (proxy->priv->child && gtk_widget_get_visible (proxy->priv->child)) + { + gtk_widget_get_allocation (proxy->priv->child, &child_area); + attributes.width = child_area.width; + attributes.height = child_area.height; + } + + proxy->priv->offscreen_window = gdk_window_new (gtk_widget_get_root_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (proxy->priv->offscreen_window, widget); + + if (proxy->priv->child) + gtk_widget_set_parent_window (proxy->priv->child, proxy->priv->offscreen_window); + + gdk_offscreen_window_set_embedder (proxy->priv->offscreen_window, + window); + + g_signal_connect(proxy->priv->offscreen_window, "create-surface", + G_CALLBACK (ido_offscreen_proxy_create_alpha_image_surface), + proxy); + g_signal_connect (proxy->priv->offscreen_window, "to-embedder", + G_CALLBACK (offscreen_to_parent), NULL); + g_signal_connect (proxy->priv->offscreen_window, "from-embedder", + G_CALLBACK (offscreen_from_parent), NULL); + + context = gtk_widget_get_style_context (widget); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM); + gtk_style_context_set_background (context, window); + gtk_style_context_set_background (context, proxy->priv->offscreen_window); + gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM | GTK_JUNCTION_LEFT | GTK_JUNCTION_RIGHT); + + gtk_widget_set_name (widget, "IdoOffscreenProxy"); + gtk_widget_path_iter_set_name (gtk_widget_get_path (widget), -1, "IdoOffscreenProxy"); + + gdk_window_show (proxy->priv->offscreen_window); +} + +static void +ido_offscreen_proxy_unrealize (GtkWidget *widget) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (widget); + + gdk_window_set_user_data (proxy->priv->offscreen_window, NULL); + gdk_window_destroy (proxy->priv->offscreen_window); + proxy->priv->offscreen_window = NULL; + + GTK_WIDGET_CLASS (ido_offscreen_proxy_parent_class)->unrealize (widget); +} + +static GType +ido_offscreen_proxy_child_type (GtkContainer *container) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (container); + + if (proxy->priv->child) + return G_TYPE_NONE; + + return GTK_TYPE_WIDGET; +} + +static void +ido_offscreen_proxy_add (GtkContainer *container, + GtkWidget *child) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (container); + + if (!proxy->priv->child) + { + gtk_widget_set_parent_window (child, proxy->priv->offscreen_window); + gtk_widget_set_parent (child, GTK_WIDGET (proxy)); + proxy->priv->child = child; + } + else + { + g_warning ("IdoOffscreenProxy can only have a single child\n"); + } +} + +static void +ido_offscreen_proxy_remove (GtkContainer *container, + GtkWidget *widget) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (container); + gboolean was_visible; + + was_visible = gtk_widget_get_visible (widget); + + if (proxy->priv->child == widget) + { + gtk_widget_unparent (widget); + proxy->priv->child = NULL; + + if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container))) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +ido_offscreen_proxy_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (container); + + g_return_if_fail (callback != NULL); + + if (proxy->priv->child) + (*callback) (proxy->priv->child, callback_data); +} + +static void +ido_offscreen_proxy_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (widget); + int w, h; + + w = 0; + h = 0; + + if (proxy->priv->child && gtk_widget_get_visible (proxy->priv->child)) + { + GtkRequisition child_requisition; + + gtk_widget_get_preferred_size (proxy->priv->child, + &child_requisition, NULL); + w = child_requisition.width; + h = child_requisition.height; + } + + requisition->width = w; + requisition->height = h; + +} + +static void +ido_offscreen_proxy_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkRequisition requisition; + + ido_offscreen_proxy_size_request (widget, &requisition); + + *minimum = *natural = requisition.width; +} + +static void +ido_offscreen_proxy_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkRequisition requisition; + + ido_offscreen_proxy_size_request (widget, &requisition); + + *minimum = *natural = requisition.height; + +} + +static void +ido_offscreen_proxy_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + IdoOffscreenProxy *proxy; + + proxy = IDO_OFFSCREEN_PROXY (widget); + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) + { + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + } + + if (proxy->priv->child && gtk_widget_get_visible (proxy->priv->child)) + { + GtkRequisition child_requisition; + GtkAllocation child_allocation; + + gtk_widget_get_preferred_size (proxy->priv->child, + &child_requisition, NULL); + + child_allocation.x = child_requisition.width; + child_allocation.y = child_requisition.height; + child_allocation.width = allocation->width; + child_allocation.height = allocation->height; + + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (proxy->priv->offscreen_window, + child_allocation.x, + child_allocation.y, + child_allocation.width+4, + child_allocation.height); + + child_allocation.x = child_allocation.y = 0; + gtk_widget_size_allocate (proxy->priv->child, &child_allocation); + } +} + + +static gboolean +ido_offscreen_proxy_damage (GtkWidget *widget, + GdkEventExpose *event) +{ + gdk_window_invalidate_rect (gtk_widget_get_window (widget), + NULL, FALSE); + return TRUE; +} + +static GtkStyleContext * +get_menu_style_context () +{ + GtkStyleContext *sc; + GtkWidgetPath *path; + + path = gtk_widget_path_new (); + gtk_widget_path_append_type (path, GTK_TYPE_MENU); + + sc = gtk_style_context_new(); + + proxy_add_css (sc); + + gtk_style_context_set_path (sc, path); + gtk_style_context_add_class (sc, GTK_STYLE_CLASS_MENU); + gtk_style_context_add_class (sc, "ido-offscreen"); + + + + gtk_widget_path_free (path); + + return sc; +} + +static gboolean +ido_offscreen_proxy_draw (GtkWidget *widget, + cairo_t *cr) +{ + IdoOffscreenProxy *proxy = IDO_OFFSCREEN_PROXY (widget); + GdkWindow *window; + GtkStyleContext *sc; + + window = gtk_widget_get_window (widget); + + sc = get_menu_style_context(); + + gtk_render_background (sc, cr, + 0, 0, + gdk_window_get_width (window), + gdk_window_get_height (window)); + + g_object_unref (sc); + + + + if (gtk_cairo_should_draw_window (cr, window)) + { + cairo_surface_t *surface; + + if (proxy->priv->child && gtk_widget_get_visible (proxy->priv->child)) + { + surface = gdk_offscreen_window_get_surface (proxy->priv->offscreen_window); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + } + } + else if (gtk_cairo_should_draw_window (cr, proxy->priv->offscreen_window)) + { + + if (proxy->priv->child) + gtk_container_propagate_draw (GTK_CONTAINER (widget), + proxy->priv->child, + cr); + } + + return TRUE; +} diff --git a/src/idooffscreenproxy.h b/src/idooffscreenproxy.h new file mode 100644 index 0000000..3071eab --- /dev/null +++ b/src/idooffscreenproxy.h @@ -0,0 +1,62 @@ +/* + * Copyright 2011 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of either or both of the following licenses: + * + * 1) the GNU Lesser General Public License version 3, as published by the + * Free Software Foundation; and/or + * 2) the GNU Lesser General Public License version 2.1, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 and version 2.1 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authors: + * Robert Carr <racarr@canonical.com> + */ + +#ifndef __IDO_OFFSCREEN_PROXY_H__ +#define __IDO_OFFSCREEN_PROXy_H__ + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define IDO_TYPE_OFFSCREEN_PROXY (ido_offscreen_proxy_get_type ()) +#define IDO_OFFSCREEN_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_OFFSCREEN_PROXY, IdoOffscreenProxy)) +#define IDO_OFFSCREEN_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_OFFSCREEN_PROXY, IdoOffscreenProxyClass)) +#define IDO_IS_OFFSCREEN_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_OFFSCREEN_PROXY)) +#define IDO_IS_OFFSCREEN_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_OFFSCREEN_PROXY)) +#define IDO_OFFSCREEN_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_OFFSCREEN_PROXY, IdoOffscreenProxyClass)) + +typedef struct _IdoOffscreenProxy IdoOffscreenProxy; +typedef struct _IdoOffscreenProxyClass IdoOffscreenProxyClass; +typedef struct _IdoOffscreenProxyPrivate IdoOffscreenProxyPrivate; + +struct _IdoOffscreenProxyClass +{ + GtkBinClass parent_class; +}; + +struct _IdoOffscreenProxy +{ + GtkContainer container; + + IdoOffscreenProxyPrivate *priv; +}; + +GType ido_offscreen_proxy_get_type (void) G_GNUC_CONST; +GtkWidget *ido_offscreen_proxy_new (void); + +G_END_DECLS + +#endif diff --git a/src/idoscalemenuitem.c b/src/idoscalemenuitem.c index 8b9e1ac..8a55299 100644 --- a/src/idoscalemenuitem.c +++ b/src/idoscalemenuitem.c @@ -23,11 +23,18 @@ * Cody Russell <crussell@canonical.com> */ +#include "config.h" + + #include <gtk/gtk.h> #include "idorange.h" #include "idoscalemenuitem.h" #include "idotypebuiltins.h" +#ifdef USE_GTK3 +#include "idooffscreenproxy.h" +#endif + static void ido_scale_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, @@ -57,6 +64,11 @@ static void update_packing (IdoScaleMenuItem struct _IdoScaleMenuItemPrivate { GtkWidget *scale; + +#ifdef USE_GTK3 + GtkWidget *proxy; +#endif + GtkAdjustment *adjustment; GtkWidget *primary_image; GtkWidget *secondary_image; @@ -226,6 +238,14 @@ ido_scale_menu_item_constructed (GObject *object) priv->scale = ido_range_new (adj, range_style); g_object_ref (priv->scale); gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE); + +#ifdef USE_GTK3 + gtk_widget_set_can_focus (priv->scale, FALSE); + + priv->proxy = ido_offscreen_proxy_new (); + g_object_ref (priv->proxy); + gtk_container_add (GTK_CONTAINER (priv->proxy), priv->scale); +#endif hbox = gtk_hbox_new (FALSE, 0); @@ -338,23 +358,39 @@ update_packing (IdoScaleMenuItem *self, IdoScaleMenuItemStyle style, IdoScaleMen switch (old_style) { case IDO_SCALE_MENU_ITEM_STYLE_NONE: - gtk_container_remove (container, priv->scale); +#ifdef USE_GTK3 + gtk_container_remove (container, priv->proxy); +#else + gtk_container_remove (container, priv->scale); +#endif break; case IDO_SCALE_MENU_ITEM_STYLE_IMAGE: gtk_container_remove (container, priv->primary_image); gtk_container_remove (container, priv->secondary_image); - gtk_container_remove (container, priv->scale); +#ifdef USE_GTK3 + gtk_container_remove (container, priv->proxy); +#else + gtk_container_remove (container, priv->scale); +#endif break; case IDO_SCALE_MENU_ITEM_STYLE_LABEL: gtk_container_remove (container, priv->primary_label); gtk_container_remove (container, priv->secondary_label); - gtk_container_remove (container, priv->scale); +#ifdef USE_GTK3 + gtk_container_remove (container, priv->proxy); +#else + gtk_container_remove (container, priv->scale); +#endif break; default: - gtk_container_remove (container, priv->scale); +#ifdef USE_GTK3 + gtk_container_remove (container, priv->proxy); +#else + gtk_container_remove (container, priv->scale); +#endif break; } } @@ -362,23 +398,41 @@ update_packing (IdoScaleMenuItem *self, IdoScaleMenuItemStyle style, IdoScaleMen switch (style) { case IDO_SCALE_MENU_ITEM_STYLE_NONE: +#ifdef USE_GTK3 + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->proxy, FALSE, FALSE, 0); +#else gtk_box_pack_start (GTK_BOX (priv->hbox), priv->scale, FALSE, FALSE, 0); +#endif break; case IDO_SCALE_MENU_ITEM_STYLE_IMAGE: gtk_box_pack_start (GTK_BOX (priv->hbox), priv->primary_image, FALSE, FALSE, 0); + +#ifdef USE_GTK3 + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->proxy, FALSE, FALSE, 0); +#else gtk_box_pack_start (GTK_BOX (priv->hbox), priv->scale, FALSE, FALSE, 0); +#endif + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->secondary_image, FALSE, FALSE, 0); break; case IDO_SCALE_MENU_ITEM_STYLE_LABEL: gtk_box_pack_start (GTK_BOX (priv->hbox), priv->primary_label, FALSE, FALSE, 0); +#ifdef USE_GTK3 + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->proxy, FALSE, FALSE, 0); +#else gtk_box_pack_start (GTK_BOX (priv->hbox), priv->scale, FALSE, FALSE, 0); +#endif gtk_box_pack_start (GTK_BOX (priv->hbox), priv->secondary_label, FALSE, FALSE, 0); break; default: +#ifdef USE_GTK3 + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->proxy, FALSE, FALSE, 0); +#else gtk_box_pack_start (GTK_BOX (priv->hbox), priv->scale, FALSE, FALSE, 0); +#endif break; } @@ -469,8 +523,11 @@ ido_scale_menu_item_button_press_event (GtkWidget *menuitem, GdkEventButton *event) { IdoScaleMenuItemPrivate *priv = GET_PRIVATE (menuitem); - GtkWidget *scale = priv->scale; gdouble x; + +#ifndef USE_GTK3 + GtkWidget *scale = priv->scale; +#endif // can we block emissions of "grab-notify" on parent?? @@ -480,12 +537,16 @@ ido_scale_menu_item_button_press_event (GtkWidget *menuitem, translate_event_coordinates (menuitem, event->x_root, &x); event->x_root = x; +#ifndef USE_GTK3 ubuntu_gtk_widget_set_has_grab (scale, TRUE); +#endif - gtk_widget_event (scale, + gtk_widget_event (priv->scale, ((GdkEvent *)(void*)(event))); +#ifndef USE_GTK3 ubuntu_gtk_widget_set_has_grab (scale, FALSE); +#endif if (!priv->grabbed) { @@ -493,7 +554,11 @@ ido_scale_menu_item_button_press_event (GtkWidget *menuitem, g_signal_emit (menuitem, signals[SLIDER_GRABBED], 0); } +#ifdef USE_GTK3 + return FALSE; +#else return TRUE; +#endif } static gboolean |