262 lines
7.3 KiB
C
262 lines
7.3 KiB
C
/*
|
|
* mx-floating-widget: always-on-top base actor
|
|
*
|
|
* Copyright 2009 Intel Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU Lesser General Public License,
|
|
* version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Written by: Thomas Wood <thomas.wood@intel.com>
|
|
*
|
|
*/
|
|
|
|
#include "mx-floating-widget.h"
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (MxFloatingWidget, mx_floating_widget, MX_TYPE_WIDGET)
|
|
|
|
#define FLOATING_WIDGET_PRIVATE(o) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_TYPE_FLOATING_WIDGET, MxFloatingWidgetPrivate))
|
|
|
|
struct _MxFloatingWidgetPrivate
|
|
{
|
|
ClutterActor *stage;
|
|
|
|
CoglMatrix paint_matrix;
|
|
CoglMatrix pick_matrix;
|
|
|
|
gulong pick_handler;
|
|
gulong paint_handler;
|
|
};
|
|
|
|
|
|
static void
|
|
mx_floating_widget_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
|
{
|
|
switch (property_id)
|
|
{
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
|
{
|
|
switch (property_id)
|
|
{
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_dispose (GObject *object)
|
|
{
|
|
G_OBJECT_CLASS (mx_floating_widget_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_finalize (GObject *object)
|
|
{
|
|
G_OBJECT_CLASS (mx_floating_widget_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
stage_weak_notify (MxFloatingWidget *widget,
|
|
ClutterStage *stage)
|
|
{
|
|
widget->priv->stage = NULL;
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_pick_from_stage (ClutterActor *stage,
|
|
const ClutterColor *color,
|
|
MxFloatingWidget *widget)
|
|
{
|
|
MxFloatingWidgetClass *klass;
|
|
MxFloatingWidgetPrivate *priv = widget->priv;
|
|
gboolean has_clip;
|
|
|
|
if (!CLUTTER_ACTOR_IS_REACTIVE (widget))
|
|
return;
|
|
|
|
klass = MX_FLOATING_WIDGET_CLASS (G_OBJECT_GET_CLASS (widget));
|
|
|
|
cogl_push_matrix ();
|
|
|
|
cogl_set_modelview_matrix (&(priv->pick_matrix));
|
|
|
|
has_clip = clutter_actor_has_clip (CLUTTER_ACTOR (widget));
|
|
|
|
if (has_clip)
|
|
{
|
|
gfloat x, y, w, h;
|
|
clutter_actor_get_clip (CLUTTER_ACTOR (widget), &x, &y, &w, &h);
|
|
cogl_clip_push_rectangle (x, y, x + w, y + h);
|
|
}
|
|
|
|
if (klass->floating_pick)
|
|
klass->floating_pick (CLUTTER_ACTOR (widget), color);
|
|
|
|
if (has_clip)
|
|
cogl_clip_pop ();
|
|
|
|
cogl_pop_matrix ();
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_paint_from_stage (ClutterActor *stage,
|
|
MxFloatingWidget *widget)
|
|
{
|
|
MxFloatingWidgetClass *klass;
|
|
MxFloatingWidgetPrivate *priv = widget->priv;
|
|
gboolean has_clip;
|
|
|
|
klass = MX_FLOATING_WIDGET_CLASS (G_OBJECT_GET_CLASS (widget));
|
|
|
|
cogl_push_matrix ();
|
|
|
|
cogl_set_modelview_matrix (&(priv->paint_matrix));
|
|
|
|
has_clip = clutter_actor_has_clip (CLUTTER_ACTOR (widget));
|
|
|
|
if (has_clip)
|
|
{
|
|
gfloat x, y, w, h;
|
|
clutter_actor_get_clip (CLUTTER_ACTOR (widget), &x, &y, &w, &h);
|
|
cogl_clip_push_rectangle (x, y, x + w, y + h);
|
|
}
|
|
|
|
if (klass->floating_paint)
|
|
klass->floating_paint (CLUTTER_ACTOR (widget));
|
|
|
|
if (has_clip)
|
|
cogl_clip_pop ();
|
|
|
|
cogl_pop_matrix ();
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_map (ClutterActor *actor)
|
|
{
|
|
MxFloatingWidgetPrivate *priv = MX_FLOATING_WIDGET (actor)->priv;
|
|
|
|
CLUTTER_ACTOR_CLASS (mx_floating_widget_parent_class)->map (actor);
|
|
|
|
/* connect after the paint and pick signals on the stage have run, so that
|
|
* we can be sure to be painted and picked above all other actors else */
|
|
priv->stage = clutter_actor_get_stage (actor);
|
|
g_object_weak_ref (G_OBJECT (priv->stage), (GWeakNotify) stage_weak_notify,
|
|
actor);
|
|
|
|
priv->paint_handler =
|
|
g_signal_connect_after (priv->stage,
|
|
"paint",
|
|
G_CALLBACK (mx_floating_widget_paint_from_stage),
|
|
actor);
|
|
|
|
priv->pick_handler =
|
|
g_signal_connect_after (priv->stage,
|
|
"pick",
|
|
G_CALLBACK (mx_floating_widget_pick_from_stage),
|
|
actor);
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_unmap (ClutterActor *actor)
|
|
{
|
|
MxFloatingWidgetPrivate *priv = MX_FLOATING_WIDGET (actor)->priv;
|
|
|
|
CLUTTER_ACTOR_CLASS (mx_floating_widget_parent_class)->unmap (actor);
|
|
|
|
if (priv->stage)
|
|
{
|
|
g_signal_handler_disconnect (priv->stage, priv->paint_handler);
|
|
priv->paint_handler = 0;
|
|
|
|
g_signal_handler_disconnect (priv->stage, priv->pick_handler);
|
|
priv->pick_handler = 0;
|
|
|
|
g_object_weak_unref (G_OBJECT (priv->stage),
|
|
(GWeakNotify) stage_weak_notify,
|
|
actor);
|
|
priv->stage = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_paint_null (ClutterActor *actor)
|
|
{
|
|
/* store the matrix for later
|
|
* the widget is painted after the stage has painted, so that it appears above
|
|
* everything else */
|
|
cogl_get_modelview_matrix (&(MX_FLOATING_WIDGET (actor)->priv->paint_matrix));
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_pick_null (ClutterActor *actor,
|
|
const ClutterColor *color)
|
|
{
|
|
/* store the matrix for later
|
|
* the widget is picked after the stage has picked, so that it appears above
|
|
* everything else */
|
|
cogl_get_modelview_matrix (&(MX_FLOATING_WIDGET (actor)->priv->pick_matrix));
|
|
}
|
|
|
|
|
|
static void
|
|
mx_floating_widget_floating_pick (ClutterActor *widget,
|
|
const ClutterColor *color)
|
|
{
|
|
/* default implementation is to chain up to the original pick */
|
|
CLUTTER_ACTOR_CLASS (mx_floating_widget_parent_class)->pick (widget, color);
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_floating_paint (ClutterActor *widget)
|
|
{
|
|
/* default implementation is to chain up to the original paint */
|
|
CLUTTER_ACTOR_CLASS (mx_floating_widget_parent_class)->paint (widget);
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_class_init (MxFloatingWidgetClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
|
MxFloatingWidgetClass *float_class = MX_FLOATING_WIDGET_CLASS (klass);
|
|
|
|
g_type_class_add_private (klass, sizeof (MxFloatingWidgetPrivate));
|
|
|
|
object_class->get_property = mx_floating_widget_get_property;
|
|
object_class->set_property = mx_floating_widget_set_property;
|
|
object_class->dispose = mx_floating_widget_dispose;
|
|
object_class->finalize = mx_floating_widget_finalize;
|
|
|
|
actor_class->map = mx_floating_widget_map;
|
|
actor_class->unmap = mx_floating_widget_unmap;
|
|
actor_class->pick = mx_floating_widget_pick_null;
|
|
actor_class->paint = mx_floating_widget_paint_null;
|
|
|
|
float_class->floating_pick = mx_floating_widget_floating_pick;
|
|
float_class->floating_paint = mx_floating_widget_floating_paint;
|
|
}
|
|
|
|
static void
|
|
mx_floating_widget_init (MxFloatingWidget *self)
|
|
{
|
|
self->priv = FLOATING_WIDGET_PRIVATE (self);
|
|
}
|
|
|