From: Gordon Williams Date: Wed, 11 Feb 2009 11:00:00 +0000 (+0000) Subject: * src/hildon.h * src/hildon-remote-texture.c * src/hildon-remote-texture.h * src... X-Git-Tag: 2.1.66-1~164 X-Git-Url: https://vcs.maemo.org/git/?a=commitdiff_plain;h=a759f06a3a43282f0a765435691e2f3a5c546cf3;p=hildon * src/hildon.h * src/hildon-remote-texture.c * src/hildon-remote-texture.h * src/hildon-remote-texture-private.h * src/Makefile.am Added remote texture widget (for Clutter shared memory textures) * examples/hildon-remote-texture-example.c * examples/Makefile.am Added example file for remote texture usage --- diff --git a/ChangeLog b/ChangeLog index f13b9bf..4376b37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-02-11 Gordon Williams + + * src/hildon.h + * src/hildon-remote-texture.c + * src/hildon-remote-texture.h + * src/hildon-remote-texture-private.h + * src/Makefile.am + Added remote texture widget (for Clutter shared memory textures) + + * examples/hildon-remote-texture-example.c + * examples/Makefile.am + Added example file for remote texture usage + 2009-02-10 Claudio Saavedra * configure.ac: post release version bump. diff --git a/examples/Makefile.am b/examples/Makefile.am index 72d1b3e..efc840a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -35,7 +35,8 @@ EXAMPLES = hildon-window-example \ hildon-touch-selector-example \ hildon-touch-selector-multi-cells-example \ hildon-touch-selector-entry-example \ - hildon-progress-indicator-example + hildon-progress-indicator-example \ + hildon-remote-texture-example if USE_MAEMO_GTK MAEMO_GTK_EXAMPLES = hildon-pannable-area-touch-list-example \ hildon-pannable-area-touch-grid-example @@ -441,4 +442,10 @@ hildon_progress_indicator_example_CFLAGS = $(HILDON_OBJ_CFLAGS) \ $(EXTRA_CFLAGS) hildon_progress_indicator_example_SOURCES = hildon-progress-indicator-example.c +# Hildon remote texture +hildon_remote_texture_example_LDADD = $(HILDON_OBJ_LIBS) +hildon_remote_texture_example_CFLAGS = $(HILDON_OBJ_CFLAGS) \ + $(EXTRA_CFLAGS) +hildon_remote_texture_example_SOURCES = hildon-remote-texture-example.c + endif diff --git a/examples/hildon-remote-texture-example.c b/examples/hildon-remote-texture-example.c new file mode 100644 index 0000000..927ecae --- /dev/null +++ b/examples/hildon-remote-texture-example.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "hildon.h" + +#define W 800 +#define H 480 + +/* Press and drag to pan around, or tap to move between zoom levels. + * A file must be specified on the command-line, and it must be > 640x480. + * + * This file will be loaded and placed into a shared memory area, which will + * be read by hildon-desktop. + * An area 640x480 in the top-left corner will be updated with an animation + * to show how to modify the area. */ + +#define ANIM_X 0 +#define ANIM_Y 0 +#define ANIM_WIDTH 640 +#define ANIM_HEIGHT 480 +#define ANIM_FRAMES 64 + +static key_t shm_key = 0xCAFEBEEF; +static gint bpp, width, height; +static guchar *shm = 0; /* shared mem */ +static int anim_frame = 0; + +static double scale = 1; +static double scale_smooth = 1; +static double x = 0; +static double y = 0; +static double x_inc = 0; +static double y_inc = 0; +static double cursor_move = 0; + +static int last_x, last_y, pressed = 0; + +static void timeout_cb (void *obj) +{ + HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE (obj); + + if (shm) { + gint x,y; + + for (y=0;yx; + last_y = event->y; + cursor_move = 0; +} + +static void release_cb (GtkWidget *widget, + GdkEventButton *event, gpointer obj) +{ + pressed = FALSE; + last_x = event->x; + last_y = event->y; + + if (cursor_move < 40) + { + scale = scale * 1.5; + if (scale>8) scale=0.125; + /* scale smooth will actually do the update */ + } +} + +static void motion_cb (GtkWidget *widget, + GdkEventMotion *event, gpointer data) +{ + HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE(data); + + if (pressed) + { + x_inc = event->x - last_x; + y_inc = event->y - last_y; + cursor_move += fabs(x_inc) + fabs(y_inc); + + x_inc /= scale; + y_inc /= scale; + + x += x_inc; + y += y_inc; + hildon_remote_texture_set_position (actor, x, y); + } + + last_x = event->x; + last_y = event->y; +} + +int +main (int argc, char **argv) +{ + gtk_init (&argc, &argv); + + GdkPixbuf *pixbuf; + GError *error = 0; + guchar *gpixels; + + if (argc!=2) + { + printf("USAGE: hildon-remote-texture-example image.png\n"); + printf("NB. Image should be 640x480 in size or greater\n"); + return EXIT_FAILURE; + } + + g_debug("Loading Image %s...", argv[1]); + pixbuf = gdk_pixbuf_new_from_file (argv[1], &error); + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + bpp = gdk_pixbuf_get_n_channels (pixbuf); /* assume 8 bit */ + gpixels = gdk_pixbuf_get_pixels (pixbuf); + g_debug("Creating Shared Memory"); + + + size_t shm_size = width*height*bpp; + int shmid; + + /* + * Create the segment, attach it to our data space, and copy in the + * texture we loaded + */ + if ((shmid = shmget(shm_key, shm_size, IPC_CREAT | 0666)) < 0) { + perror("shmget"); + exit(1); + } + + if ((shm = shmat(shmid, NULL, 0)) == (guchar *) -1) { + perror("shmat"); + exit(1); + } + + memcpy(shm, gpixels, shm_size); + + g_debug("Done."); + + + + HildonProgram *program = hildon_program_get_instance (); + + HildonWindow *window = HILDON_WINDOW( + hildon_window_new()); + hildon_program_add_window (program, window); + gtk_window_set_decorated (GTK_WINDOW (window), FALSE); + gtk_widget_show (GTK_WIDGET(window)); + + HildonRemoteTexture *actor = HILDON_REMOTE_TEXTURE + (hildon_remote_texture_new ()); + gtk_window_resize(GTK_WINDOW(actor), W, H); + + g_set_application_name ("Animation"); + + g_signal_connect (G_OBJECT (actor), + "delete_event", + G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (G_OBJECT (actor), + "button-press-event", + G_CALLBACK (press_cb), + actor); + g_signal_connect (G_OBJECT (actor), + "button-release-event", + G_CALLBACK (release_cb), + actor); + g_signal_connect (G_OBJECT (actor), + "motion-notify-event", + G_CALLBACK (motion_cb), + actor); + gtk_widget_add_events (GTK_WIDGET(actor), + GDK_BUTTON_PRESS_MASK| + GDK_BUTTON_MOTION_MASK| + GDK_BUTTON_RELEASE_MASK); + + + gtk_widget_show_all (GTK_WIDGET (actor)); + gdk_flush (); + + hildon_remote_texture_set_parent(actor, GTK_WINDOW(window)); + hildon_remote_texture_set_image(actor, shm_key, width, height, bpp); + hildon_remote_texture_set_position (actor, x, y); + hildon_remote_texture_set_show (actor, 1); + + g_timeout_add (25, (GSourceFunc)timeout_cb, actor); + + printf ("going to gtk_main ()\n"); + gtk_main (); + return 0; +} diff --git a/src/Makefile.am b/src/Makefile.am index 350d187..07dd516 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,6 +70,7 @@ libhildon_@API_VERSION_MAJOR@_la_SOURCES = \ hildon-stackable-window.c \ hildon-window-stack.c \ hildon-animation-actor.c \ + hildon-remote-texture.c \ hildon-program.c \ hildon-code-dialog.c \ hildon-enum-types.c \ @@ -141,6 +142,7 @@ libhildon_@API_VERSION_MAJOR@_public_headers = \ hildon-stackable-window.h \ hildon-window-stack.h \ hildon-animation-actor.h \ + hildon-remote-texture.h \ hildon-wizard-dialog.h \ hildon-calendar.h \ hildon-pannable-area.h \ @@ -189,6 +191,7 @@ noinst_HEADERS = hildon-banner-private.h \ hildon-stackable-window-private.h \ hildon-window-stack-private.h \ hildon-animation-actor-private.h \ + hildon-remote-texture-private.h \ hildon-wizard-dialog-private.h \ hildon-calendar-private.h \ hildon-app-menu-private.h \ diff --git a/src/hildon-remote-texture-private.h b/src/hildon-remote-texture-private.h new file mode 100644 index 0000000..a9a30eb --- /dev/null +++ b/src/hildon-remote-texture-private.h @@ -0,0 +1,78 @@ +/* + * This file is a part of hildon + * + * Copyright (C) 2008 Nokia Corporation, all rights reserved. + * + * Contact: Rodrigo Novo + * + * 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; version 2.1 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __HILDON_REMOTE_TEXTURE_PRIVATE_H__ +#define __HILDON_REMOTE_TEXTURE_PRIVATE_H__ + + +#include +#include + +G_BEGIN_DECLS + +typedef struct _HildonRemoteTexturePrivate HildonRemoteTexturePrivate; + +#define HILDON_REMOTE_TEXTURE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + HILDON_TYPE_REMOTE_TEXTURE, HildonRemoteTexturePrivate)); + +struct _HildonRemoteTexturePrivate +{ + guint ready : 1; + + guint set_shm : 1; + guint set_damage : 1; + guint set_show : 1; + guint set_position : 1; + guint set_scale : 1; + guint set_parent : 1; + + key_t shm_key; + guint shm_width; + guint shm_height; + guint shm_bpp; + + gint damage_x1; + gint damage_y1; + gint damage_x2; + gint damage_y2; + + guint show; + guint opacity; + + double position_x; + double position_y; + + double scale_x; + double scale_y; + + GtkWindow* parent; + gulong parent_map_event_cb_id; + + gulong map_event_cb_id; +}; + +G_END_DECLS + +#endif /* __HILDON_REMOTE_TEXTURE_PRIVATE_H__ */ diff --git a/src/hildon-remote-texture.c b/src/hildon-remote-texture.c new file mode 100644 index 0000000..cc8f607 --- /dev/null +++ b/src/hildon-remote-texture.c @@ -0,0 +1,850 @@ +/* + * This file is a part of hildon + * + * Copyright (C) 2008 Nokia Corporation, all rights reserved. + * + * Contact: Rodrigo Novo + * + * 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; version 2.1 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + * SECTION:hildon-remote-texture + * @short_description: Widget representing a Clutter/GLES texture created + * from a shared memory area. + * + * The #HildonRemoteTexture is a GTK+ widget which allows the rendering of + * a shared memory area within hildon-desktop. It allows the memory area to + * be positioned and scaled, without altering its' contents. + */ + +#include +#include + +#include "hildon-remote-texture.h" +#include "hildon-remote-texture-private.h" +#include "hildon-program.h" +#include "hildon-window-private.h" +#include "hildon-program-private.h" + +G_DEFINE_TYPE (HildonRemoteTexture, hildon_remote_texture, GTK_TYPE_WINDOW); + +static GdkFilterReturn +hildon_remote_texture_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data); +static void +hildon_remote_texture_update_ready (HildonRemoteTexture *self); +static void +hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self); +static void +hildon_remote_texture_send_all_messages (HildonRemoteTexture *self); +static gboolean +hildon_remote_texture_parent_map_event (GtkWidget *parent, + GdkEvent *event, + gpointer user_data); +static gboolean +hildon_remote_texture_map_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data); + +static guint32 shm_atom; +static guint32 damage_atom; +static guint32 show_atom; +static guint32 position_atom; +static guint32 scale_atom; +static guint32 parent_atom; +static guint32 ready_atom; + +static gboolean atoms_initialized = FALSE; + +static void +hildon_remote_texture_realize (GtkWidget *widget) +{ + GdkDisplay *display; + Atom wm_type, applet_type; + + GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->realize (widget); + + /* Set remote texture window type. */ + + display = gdk_drawable_get_display (widget->window); + + wm_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"); + applet_type = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_REMOTE_TEXTURE"); + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), wm_type, + XA_ATOM, 32, PropModeReplace, + (unsigned char *) &applet_type, 1); + + /* This is a bit of a hack, but for the sake of speed (it is assumed that + * once HildonRemoteTexture is created, a lot of ClientMessages will + * follow), we cache all ClientMessages atoms in static variables. */ + + if (!atoms_initialized) + { + shm_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHM"); + damage_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_DAMAGE"); + show_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SHOW"); + position_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_POSITION"); + scale_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_SCALE"); + parent_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_MESSAGE_PARENT"); + ready_atom = + gdk_x11_get_xatom_by_name_for_display + (display, "_HILDON_TEXTURE_CLIENT_READY"); +#if 0 + g_debug ("shm atom = %lu\n", shm_atom); + g_debug ("damage atom = %lu\n", damage_atom); + g_debug ("show atom = %lu\n", show_atom); + g_debug ("position atom = %lu\n", position_atom); + g_debug ("scale atom = %lu\n", scale_atom); + g_debug ("parent atom = %lu\n", parent_atom); + g_debug ("ready atom = %lu\n", ready_atom); +#endif + + atoms_initialized = TRUE; + } + + /* Wait for a ready message */ + + gdk_window_add_filter (widget->window, + hildon_remote_texture_event_filter, + widget); +} + +static void +hildon_remote_texture_unrealize (GtkWidget *widget) +{ + gdk_window_remove_filter (widget->window, + hildon_remote_texture_event_filter, + widget); + + GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->unrealize (widget); +} + +static void +hildon_remote_texture_show (GtkWidget *widget) +{ + HildonRemoteTexture *self = HILDON_REMOTE_TEXTURE (widget); + + GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->show (widget); + hildon_remote_texture_set_show (self, 1); +} + +static void +hildon_remote_texture_hide (GtkWidget *widget) +{ + HildonRemoteTexture *self = HILDON_REMOTE_TEXTURE (widget); + + hildon_remote_texture_set_show (self, 0); + GTK_WIDGET_CLASS (hildon_remote_texture_parent_class)->hide (widget); +} + +static void +hildon_remote_texture_class_init (HildonRemoteTextureClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->realize = hildon_remote_texture_realize; + widget_class->unrealize = hildon_remote_texture_unrealize; + widget_class->show = hildon_remote_texture_show; + widget_class->hide = hildon_remote_texture_hide; + + g_type_class_add_private (klass, sizeof (HildonRemoteTexturePrivate)); +} + +static void +hildon_remote_texture_init (HildonRemoteTexture *self) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + /* Default non-zero values for the private variables */ + + priv->scale_x = 1; + priv->scale_y = 1; + priv->opacity = 0xff; +} + +/** + * hildon_remote_texture_new: + * + * Creates a new #HildonRemoteTexture. + * + * Return value: A #HildonRemoteTexture + **/ +GtkWidget* +hildon_remote_texture_new (void) +{ + HildonRemoteTexture *newwindow = g_object_new (HILDON_TYPE_REMOTE_TEXTURE, NULL); + + gtk_window_set_decorated (GTK_WINDOW (newwindow), FALSE); + + return GTK_WIDGET (newwindow); +} + +/* + * An filter for GDK X11 events, waiting for PropertyNotify (window property + * changes) events, keeping track of remote texture ready atom. + * Having the ready atom set on the window by the window manager will trigger + * updates of actor parameters (position/rotation/etc...) to be sent off + * to the window manager for processing. + */ +static GdkFilterReturn +hildon_remote_texture_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + HildonRemoteTexture *self = HILDON_REMOTE_TEXTURE (data); + XAnyEvent *any = xevent; + + if (any->type == PropertyNotify) + { + XPropertyEvent *property = xevent; + + if (property->atom == ready_atom) + { + hildon_remote_texture_update_ready (self); + } + } + + return GDK_FILTER_CONTINUE; +} + +/* + * Check for the ready atom on the remote texture X11 window. + * If present, send all pending remote texture messages to the + * window manager. + */ +static void +hildon_remote_texture_update_ready (HildonRemoteTexture *self) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + Display *display = GDK_WINDOW_XDISPLAY (widget->window); + Window window = GDK_WINDOW_XID (widget->window); + + int status; + gint xerror; + + Atom actual_type; + int actual_format; + unsigned long nitems, bytes_after; + unsigned char *prop = NULL; + + /* Check for the "ready" property */ + + gdk_error_trap_push (); + status = XGetWindowProperty (display, window, + ready_atom, 0, 32, + False, XA_ATOM, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop); + xerror = gdk_error_trap_pop(); + + if (prop) + { + /* We do not actually use the property value for anything, + * it is enough that the property is set. */ + + XFree (prop); + } + + if (xerror || + (status != Success) || (actual_type != XA_ATOM) || + (actual_format != 32) || (nitems != 1)) + { + priv->ready = 0; + return; + } + + if (priv->ready) + { + /* The ready flag has been set once already. This means that + * the WM has restarted. Trigger re-mapping of the widget to + * update the texture actor first. Then push all remote + * texture settings anew. */ + + priv->map_event_cb_id = + g_signal_connect (G_OBJECT (self), + "map-event", + G_CALLBACK(hildon_remote_texture_map_event), + self); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (self))) + { + gtk_widget_unmap (GTK_WIDGET (self)); + gtk_widget_map (GTK_WIDGET (self)); + } + + return; + } + + priv->ready = 1; + + /* Send all pending messages */ + + hildon_remote_texture_send_pending_messages (self); +} + +static void +hildon_remote_texture_send_pending_messages (HildonRemoteTexture *self) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + if (priv->set_shm) + hildon_remote_texture_set_image(self, + priv->shm_key, + priv->shm_width, priv->shm_height, + priv->shm_bpp); + + if (priv->set_damage) + hildon_remote_texture_update_area (self, + priv->damage_x1, + priv->damage_y1, + priv->damage_x2 - priv->damage_x1, + priv->damage_y2 - priv->damage_y1); + + if (priv->set_position) + hildon_remote_texture_set_position (self, + priv->position_x, + priv->position_y); + + if (priv->set_scale) + hildon_remote_texture_set_scale (self, + priv->scale_x, + priv->scale_y); + + if (priv->set_parent) + hildon_remote_texture_set_parent (self, + priv->parent); + + if (priv->set_show) + hildon_remote_texture_set_show_full (self, + priv->show, priv->opacity); +} + +static void +hildon_remote_texture_send_all_messages (HildonRemoteTexture *self) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + priv->set_shm = 1; + priv->set_damage = 1; + priv->set_position = 1; + priv->set_scale = 1; + priv->set_parent = 1; + priv->set_show = 1; + + hildon_remote_texture_send_pending_messages (self); +} + +/* ------------------------------------------------------------- */ + +/** + * hildon_remote_texture_send_message: + * @self: A #HildonRemoteTexture + * @message_type: Message id for the remote texture message. + * @l0: 1st remote texture message parameter. + * @l1: 2nd remote texture message parameter. + * @l2: 3rd remote texture message parameter. + * @l3: 4th remote texture message parameter. + * @l4: 5th remote texture message parameter. + * + * Sends an X11 ClientMessage event to the window manager with + * the specified parameters -- id (@message_type) and data (@l0, + * @l1, @l2, @l3, @l4). + * + * This is an internal utility function that application will + * not need to call directly. + **/ +void +hildon_remote_texture_send_message (HildonRemoteTexture *self, + guint32 message_type, + guint32 l0, + guint32 l1, + guint32 l2, + guint32 l3, + guint32 l4) +{ + GtkWidget *widget = GTK_WIDGET (self); + Display *display = GDK_WINDOW_XDISPLAY (widget->window); + Window window = GDK_WINDOW_XID (widget->window); + + XEvent event = { 0 }; + + event.xclient.type = ClientMessage; + event.xclient.window = window; + event.xclient.message_type = (Atom)message_type; + event.xclient.format = 32; + event.xclient.data.l[0] = l0; + event.xclient.data.l[1] = l1; + event.xclient.data.l[2] = l2; + event.xclient.data.l[3] = l3; + event.xclient.data.l[4] = l4; + +#if 0 + g_debug ("%lu (%lu %lu %lu %lu %lu) -> %lu\n", + message_type, + l0, l1, l2, l3, l4, + window); +#endif + + XSendEvent (display, window, True, + StructureNotifyMask, + (XEvent *)&event); +} + +/** + * hildon_remote_texture_set_image: + * @self: A #HildonRemoteTexture + * @key: The key that would be used with shmget in hildon-desktop. The key + * should probably be created with ftok, and the relevant shared memory + * area should be created before this call. + * @width: width of image in pixels + * @height: height of image in pixels + * @bpp: BYTES per pixel - usually 2,3 or 4 + */ +void +hildon_remote_texture_set_image (HildonRemoteTexture *self, + key_t key, + guint width, + guint height, + guint bpp) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + priv->set_shm = 1; + priv->shm_key = key; + priv->shm_width = width; + priv->shm_height = height; + priv->shm_bpp = bpp; + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + hildon_remote_texture_send_message (self, + shm_atom, + priv->shm_key, + priv->shm_width, + priv->shm_height, + priv->shm_bpp, + 0); + priv->set_shm = 0; + } +} + +/** + * hildon_remote_texture_update_area: + * @self: A #HildonRemoteTexture + * @x: offset of damaged area in pixels + * @y: offset of damaged area in pixels + * @width: width of damaged area in pixels + * @height: height of damaged area in pixels + * + * This signals to hildon-desktop that a specific region of the memory area + * has changed. This will trigger a redraw and will update the relevant tiles + * of the texture. + */ +void +hildon_remote_texture_update_area (HildonRemoteTexture *self, + gint x, + gint y, + gint width, + gint height) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + if (priv->damage_x1==priv->damage_x2 || priv->damage_y1==priv->damage_y2) + { + priv->damage_x1 = x; + priv->damage_y1 = y; + priv->damage_x2 = x+width; + priv->damage_y2 = y+height; + } + else + { + if (xdamage_x1) priv->damage_x1 = x; + if (ydamage_y1) priv->damage_y1 = y; + if (x+width>priv->damage_x2) priv->damage_x2 = x+width; + if (y+height>priv->damage_y2) priv->damage_y2 = y+height; + } + priv->set_damage = 1; + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + hildon_remote_texture_send_message (self, + damage_atom, + priv->damage_x1, + priv->damage_y1, + priv->damage_x2 - priv->damage_x1, + priv->damage_y2 - priv->damage_y1, + 0); + priv->set_damage = 0; + priv->damage_x1 = 0; + priv->damage_y1 = 0; + priv->damage_x2 = 0; + priv->damage_y2 = 0; + } +} + +/** + * hildon_remote_texture_set_show_full: + * @self: A #HildonRemoteTexture + * @show: A boolean flag setting the visibility of the remote texture. + * @opacity: Desired opacity setting + * + * Send a message to the window manager setting the visibility of + * the remote texture. This will only affect the visibility of + * the remote texture set by the compositing window manager in its own + * rendering pipeline, after X has drawn the window to the off-screen + * buffer. This setting, naturally, has no effect if the #HildonRemoteTexture + * widget is not visible in X11 terms (i.e. realized and mapped). + * + * Furthermore, if a widget is parented, its final visibility will be + * affected by that of the parent window. + * + * The opacity setting ranges from zero (0), being completely transparent + * to 255 (0xff) being fully opaque. + * + * If the remote texture WM-counterpart is not ready, the show message + * will be queued until the WM is ready for it. + **/ +void +hildon_remote_texture_set_show_full (HildonRemoteTexture *self, + gint show, + gint opacity) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + if (opacity > 255) + opacity = 255; + + if (opacity < 0) + opacity = 0; + + priv->show = show; + priv->opacity = opacity; + priv->set_show = 1; + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + /* Defer show messages until the remote texture is parented + * and the parent window is mapped */ + + if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent))) + return; + + hildon_remote_texture_send_message (self, + show_atom, + show, opacity, + 0, 0, 0); + priv->set_show = 0; + } +} + +/** + * hildon_remote_texture_set_show: + * @self: A #HildonRemoteTexture + * @show: A boolean flag setting the visibility of the remote texture. + * + * This function is a shortcut for hildon_remote_texture_set_show_full(), + * setting the overall actor visibility without changing it's opacity + * setting. + **/ +void +hildon_remote_texture_set_show (HildonRemoteTexture *self, + gint show) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + hildon_remote_texture_set_show_full (self, + show, priv->opacity); +} + +/** + * hildon_remote_texture_set_opacity: + * @self: A #HildonRemoteTexture + * @opacity: Desired opacity setting + * + * This function is a shortcut for hildon_remote_texture_set_show_full(), + * setting actor opacity without changing it's overall visibility. + * + * See hildon_remote_texture_set_show_full() for description of the range + * of values @opacity argument takes. + **/ +void +hildon_remote_texture_set_opacity (HildonRemoteTexture *self, + gint opacity) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + hildon_remote_texture_set_show_full (self, + priv->show, opacity); +} + +/** + * hildon_remote_texture_set_position_full: + * @self: A #HildonRemoteTexture + * @x: Desired X coordinate + * @y: Desired Y coordinate + * @depth: Desired window depth (Z coordinate) + * + * Send a message to the window manager setting the offset of the remote + * texture in the window (in Remote texture's pixels). The texture + * is also subject to the animation effects rendered by the compositing + * window manager on that window (like those by task switcher). + * + * If the remote texture WM-counterpart is not ready, the show message + * will be queued until the WM is ready for it. + **/ +void +hildon_remote_texture_set_position (HildonRemoteTexture *self, + double x, + double y) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + priv->position_x = x; + priv->position_y = y; + priv->set_position = 1; + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + hildon_remote_texture_send_message (self, + position_atom, + (gint)(x*65536), (gint)(y*65536), + 0, 0, 0); + priv->set_position = 0; + } +} + +/** + * hildon_remote_texture_set_scalex: + * @self: A #HildonRemoteTexture + * @x_scale: The scale factor for the memory area to be rendered in the X-axis + * @y_scale: The scale factor for the memory area to be rendered in the X-axis + **/ +void +hildon_remote_texture_set_scale (HildonRemoteTexture *self, + double x_scale, + double y_scale) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + priv->scale_x = x_scale; + priv->scale_y = y_scale; + priv->set_scale = 1; + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + hildon_remote_texture_send_message (self, + scale_atom, + priv->scale_x * (1 << 16), + priv->scale_y * (1 << 16), + 0, 0, 0); + priv->set_scale = 0; + } +} + +/* + * This callback will be triggered by the parent widget of + * an remote texture when it is mapped. The compositing + * window manager is now ready to parent the remote texture + * into the target parent window. + */ +static gboolean +hildon_remote_texture_parent_map_event (GtkWidget *parent, + GdkEvent *event, + gpointer user_data) +{ + hildon_remote_texture_set_parent (HILDON_REMOTE_TEXTURE (user_data), + GTK_WINDOW (parent)); + return FALSE; +} + +/* + * This callback will be triggered by the widget re-mapping + * itself in case of WM restarting. The point is to push all + * remote texture parameters anew to the WM. + */ +static gboolean +hildon_remote_texture_map_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + HildonRemoteTexture + *self = HILDON_REMOTE_TEXTURE (user_data); + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + + hildon_remote_texture_send_all_messages (self); + + /* Disconnect the "map-event" handler after the "emergency resend all + * actor parameters" drill is over. */ + + if (priv->map_event_cb_id) + { + g_signal_handler_disconnect (self, + priv->map_event_cb_id); + priv->map_event_cb_id = 0; + } + + return FALSE; +} + +/** + * hildon_remote_texture_set_parent: + * @self: A #HildonRemoteTexture + * @parent: A #GtkWindow that the actor will be parented to. + * + * Send a message to the window manager setting the parent window + * for the remote texture. Parenting an actor will not affect the + * X window that the HildonRemoteTexture represents, but it's off-screen + * bitmap as it is handled by the compositing window manager. + * + * Parenting an remote texture will affect its visibility as set + * by the gtk_widget_show(), gtk_widget_hide() and + * hildon_remote_texture_set_show(). The remote texture will only be + * visible when the top-level window it is parented is visible. + * + * Passing %NULL as a @parent argument will unparent the remote texture. + * This will restore the actor's visibility if it was suppressed by + * being unparented or parented to an unmapped window. + * + * If the remote texture WM-counterpart is not ready, the show message + * will be queued until the WM is ready for it. + **/ +void +hildon_remote_texture_set_parent (HildonRemoteTexture *self, + GtkWindow *parent) +{ + HildonRemoteTexturePrivate + *priv = HILDON_REMOTE_TEXTURE_GET_PRIVATE (self); + GtkWidget *widget = GTK_WIDGET (self); + + gtk_window_set_transient_for (GTK_WINDOW (self), parent); + + if (priv->parent != parent) + { + /* Setting a new parent */ + + if (priv->parent) + { + if (priv->parent_map_event_cb_id) + g_signal_handler_disconnect (priv->parent, + priv->parent_map_event_cb_id); + + /* Might need a synchronized "parent(0)" or "parent(new parent)" + * message here before we can safely decrease the reference count. */ + + g_object_unref (priv->parent); + } + + priv->parent = parent; + priv->set_parent = 1; + + if (parent != 0) + { + /* The widget is being (re)parented, not unparented. */ + + g_object_ref (parent); + + priv->parent_map_event_cb_id = + g_signal_connect (G_OBJECT (priv->parent), + "map-event", + G_CALLBACK(hildon_remote_texture_parent_map_event), + self); + } + else + { + priv->parent_map_event_cb_id = 0; + } + } + + if (GTK_WIDGET_MAPPED (widget) && priv->ready) + { + Window win = 0; + + /* If the remote texture is being unparented or parented to an + * unmapped widget, force its visibility to "hidden". */ + + if (!priv->parent || !GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent))) + { + hildon_remote_texture_send_message (self, + show_atom, + 0, priv->opacity, + 0, 0, 0); + } + + /* If the widget is being parented (parent != 0), only proceed when + * the parent widget is realized, since we need the X window id of + * the parent. If the widget is being unparented (parent == 0), pass + * the "special" window id of 0 in the message. */ + + if (priv->parent) + { + if (!GTK_WIDGET_MAPPED (GTK_WIDGET (priv->parent))) + return; + + GdkWindow *gdk = GTK_WIDGET (parent)->window; + win = GDK_WINDOW_XID (gdk); + } + + hildon_remote_texture_send_message (self, + parent_atom, + win, + 0, 0, 0, 0); + priv->set_parent = 0; + + /* Set remote texture visibility to desired value (in case it was + * forced off when the actor was parented into an unmapped widget). */ + + hildon_remote_texture_send_message (self, + show_atom, + priv->show, priv->opacity, + 0, 0, 0); + priv->set_show = 0; + } +} + diff --git a/src/hildon-remote-texture.h b/src/hildon-remote-texture.h new file mode 100644 index 0000000..5889122 --- /dev/null +++ b/src/hildon-remote-texture.h @@ -0,0 +1,130 @@ +/* + * This file is a part of hildon + * + * Copyright (C) 2008 Nokia Corporation, all rights reserved. + * + * Contact: Rodrigo Novo + * + * 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; version 2.1 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __HILDON_REMOTE_TEXTURE_H__ +#define __HILDON_REMOTE_TEXTURE_H__ + +#include "hildon-window.h" +#include +#include + +G_BEGIN_DECLS + +#define HILDON_TYPE_REMOTE_TEXTURE \ + (hildon_remote_texture_get_type()) + +#define HILDON_REMOTE_TEXTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + HILDON_TYPE_REMOTE_TEXTURE, \ + HildonRemoteTexture)) + +#define HILDON_REMOTE_TEXTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + HILDON_TYPE_REMOTE_TEXTURE, \ + HildonRemoteTextureClass)) + +#define HILDON_IS_REMOTE_TEXTURE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + HILDON_TYPE_REMOTE_TEXTURE)) + +#define HILDON_IS_REMOTE_TEXTURE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + HILDON_TYPE_REMOTE_TEXTURE)) + +#define HILDON_REMOTE_TEXTURE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + HILDON_TYPE_REMOTE_TEXTURE, \ + HildonRemoteTextureClass)) + +typedef struct _HildonRemoteTexture HildonRemoteTexture; +typedef struct _HildonRemoteTextureClass HildonRemoteTextureClass; + +struct _HildonRemoteTextureClass +{ + GtkWindowClass parent_class; + + /* Padding for future extension */ + void (*_hildon_reserved1)(void); + void (*_hildon_reserved2)(void); + void (*_hildon_reserved3)(void); + void (*_hildon_reserved4)(void); +}; + +struct _HildonRemoteTexture +{ + GtkWindow parent; +}; + +GType +hildon_remote_texture_get_type (void) G_GNUC_CONST; + +GtkWidget* +hildon_remote_texture_new (void); + +void +hildon_remote_texture_send_message (HildonRemoteTexture *self, + guint32 message_type, + guint32 l0, + guint32 l1, + guint32 l2, + guint32 l3, + guint32 l4); + +void +hildon_remote_texture_set_image (HildonRemoteTexture *self, + key_t key, + guint width, + guint height, + guint bpp); +void +hildon_remote_texture_update_area (HildonRemoteTexture *self, + gint x, + gint y, + gint width, + gint height); +void +hildon_remote_texture_set_show_full (HildonRemoteTexture *self, + gint show, + gint opacity); +void +hildon_remote_texture_set_show (HildonRemoteTexture *self, + gint show); +void +hildon_remote_texture_set_opacity (HildonRemoteTexture *self, + gint opacity); +void +hildon_remote_texture_set_position (HildonRemoteTexture *self, + double x, + double y); +void +hildon_remote_texture_set_scale (HildonRemoteTexture *self, + double x_scale, + double y_scale); +void +hildon_remote_texture_set_parent (HildonRemoteTexture *self, + GtkWindow *parent); + +G_END_DECLS + +#endif /* __HILDON_REMOTE_TEXTURE_H__ */ diff --git a/src/hildon.h b/src/hildon.h index 221e675..41c0e12 100644 --- a/src/hildon.h +++ b/src/hildon.h @@ -71,6 +71,7 @@ #include "hildon-stackable-window.h" #include "hildon-window-stack.h" #include "hildon-animation-actor.h" +#include "hildon-remote-texture.h" #include "hildon-wizard-dialog.h" #include "hildon-calendar.h" #include "hildon-bread-crumb-trail.h" @@ -84,4 +85,4 @@ #include "hildon-dialog.h" #include "hildon-main.h" -#endif +#endif