ScreenShield: add a drop shadow to the animated arrows
Introduce a StShadowHelper to manage drop shadows from JS (which cannot use Cogl directly), and use it in a new StWidget-derived JS class to draw the arrow. https://bugzilla.gnome.org/show_bug.cgi?id=682285
This commit is contained in:
parent
1a6d74fcb2
commit
a76cc79f88
@ -2208,11 +2208,12 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-bottom: 3em;
|
padding-bottom: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-arrows > StDrawingArea {
|
.screen-shield-arrows Gjs_Arrow {
|
||||||
color: white;
|
color: white;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
-arrow-thickness: 12px;
|
-arrow-thickness: 12px;
|
||||||
|
-arrow-shadow: 0 1px 1px rgba(0,0,0,0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock {
|
.screen-shield-clock {
|
||||||
|
@ -274,6 +274,62 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Arrow = new Lang.Class({
|
||||||
|
Name: 'Arrow',
|
||||||
|
Extends: St.Bin,
|
||||||
|
|
||||||
|
_init: function(params) {
|
||||||
|
this.parent(params);
|
||||||
|
this.x_fill = this.y_fill = true;
|
||||||
|
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
||||||
|
|
||||||
|
this._drawingArea = new St.DrawingArea();
|
||||||
|
this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
|
||||||
|
this.child = this._drawingArea;
|
||||||
|
|
||||||
|
this._shadowHelper = null;
|
||||||
|
this._shadowWidth = this._shadowHeight = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_drawArrow: function(arrow) {
|
||||||
|
let cr = arrow.get_context();
|
||||||
|
let [w, h] = arrow.get_surface_size();
|
||||||
|
let node = this.get_theme_node();
|
||||||
|
let thickness = node.get_length('-arrow-thickness');
|
||||||
|
|
||||||
|
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
||||||
|
|
||||||
|
cr.setLineCap(Cairo.LineCap.ROUND);
|
||||||
|
cr.setLineWidth(thickness);
|
||||||
|
|
||||||
|
cr.moveTo(thickness / 2, h - thickness / 2);
|
||||||
|
cr.lineTo(w/2, thickness);
|
||||||
|
cr.lineTo(w - thickness / 2, h - thickness / 2);
|
||||||
|
cr.stroke();
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_style_changed: function() {
|
||||||
|
let node = this.get_theme_node();
|
||||||
|
this._shadow = node.get_shadow('-arrow-shadow');
|
||||||
|
if (this._shadow)
|
||||||
|
this._shadowHelper = St.ShadowHelper.new(this._shadow);
|
||||||
|
else
|
||||||
|
this._shadowHelper = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_paint: function() {
|
||||||
|
if (this._shadowHelper) {
|
||||||
|
this._shadowHelper.update(this._drawingArea);
|
||||||
|
|
||||||
|
let allocation = this._drawingArea.get_allocation_box();
|
||||||
|
let paintOpacity = this._drawingArea.get_paint_opacity();
|
||||||
|
this._shadowHelper.paint(allocation, paintOpacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._drawingArea.paint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To test screen shield, make sure to kill gnome-screensaver.
|
* To test screen shield, make sure to kill gnome-screensaver.
|
||||||
*
|
*
|
||||||
@ -318,8 +374,7 @@ const ScreenShield = new Lang.Class({
|
|||||||
y_expand: true });
|
y_expand: true });
|
||||||
|
|
||||||
for (let i = 0; i < N_ARROWS; i++) {
|
for (let i = 0; i < N_ARROWS; i++) {
|
||||||
let arrow = new St.DrawingArea({ opacity: 0 });
|
let arrow = new Arrow({ opacity: 0 });
|
||||||
arrow.connect('repaint', Lang.bind(this, this._drawArrow));
|
|
||||||
this._arrowContainer.add_actor(arrow);
|
this._arrowContainer.add_actor(arrow);
|
||||||
}
|
}
|
||||||
this._lockScreenContents.add_actor(this._arrowContainer);
|
this._lockScreenContents.add_actor(this._arrowContainer);
|
||||||
@ -384,23 +439,6 @@ const ScreenShield = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_drawArrow: function(arrow) {
|
|
||||||
let cr = arrow.get_context();
|
|
||||||
let [w, h] = arrow.get_surface_size();
|
|
||||||
let node = arrow.get_theme_node();
|
|
||||||
let thickness = node.get_length('-arrow-thickness');
|
|
||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
|
||||||
|
|
||||||
cr.setLineCap(Cairo.LineCap.ROUND);
|
|
||||||
cr.setLineWidth(thickness);
|
|
||||||
|
|
||||||
cr.moveTo(thickness / 2, h - thickness / 2);
|
|
||||||
cr.lineTo(w/2, thickness);
|
|
||||||
cr.lineTo(w - thickness / 2, h - thickness / 2);
|
|
||||||
cr.stroke();
|
|
||||||
},
|
|
||||||
|
|
||||||
_animateArrows: function() {
|
_animateArrows: function() {
|
||||||
let arrows = this._arrowContainer.get_children();
|
let arrows = this._arrowContainer.get_children();
|
||||||
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
|
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "st-shadow.h"
|
#include "st-shadow.h"
|
||||||
|
#include "st-private.h"
|
||||||
|
|
||||||
|
G_DEFINE_BOXED_TYPE (StShadow, st_shadow, st_shadow_ref, st_shadow_unref)
|
||||||
|
G_DEFINE_BOXED_TYPE (StShadowHelper, st_shadow_helper, st_shadow_helper_copy, st_shadow_helper_free)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION: st-shadow
|
* SECTION: st-shadow
|
||||||
@ -175,16 +179,126 @@ st_shadow_get_box (StShadow *shadow,
|
|||||||
+ shadow->blur + shadow->spread;
|
+ shadow->blur + shadow->spread;
|
||||||
}
|
}
|
||||||
|
|
||||||
GType
|
/**
|
||||||
st_shadow_get_type (void)
|
* SECTION:st-shadow-helper:
|
||||||
|
*
|
||||||
|
* An helper for implementing a drop shadow on a actor.
|
||||||
|
* The actor is expected to recreate the helper whenever its contents
|
||||||
|
* or size change. Then, it would call st_shadow_helper_paint() inside
|
||||||
|
* its paint() virtual function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _StShadowHelper {
|
||||||
|
StShadow *shadow;
|
||||||
|
CoglMaterial *material;
|
||||||
|
|
||||||
|
gfloat width;
|
||||||
|
gfloat height;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_shadow_helper_new:
|
||||||
|
* @shadow: a #StShadow representing the shadow properties
|
||||||
|
*
|
||||||
|
* Builds a #StShadowHelper that will build a drop shadow
|
||||||
|
* using @source as the mask.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a new #StShadowHelper
|
||||||
|
*/
|
||||||
|
StShadowHelper *
|
||||||
|
st_shadow_helper_new (StShadow *shadow)
|
||||||
{
|
{
|
||||||
static GType _st_shadow_type = 0;
|
StShadowHelper *helper;
|
||||||
|
|
||||||
if (G_UNLIKELY (_st_shadow_type == 0))
|
helper = g_slice_new0 (StShadowHelper);
|
||||||
_st_shadow_type =
|
helper->shadow = st_shadow_ref (shadow);
|
||||||
g_boxed_type_register_static ("StShadow",
|
|
||||||
(GBoxedCopyFunc) st_shadow_ref,
|
|
||||||
(GBoxedFreeFunc) st_shadow_unref);
|
|
||||||
|
|
||||||
return _st_shadow_type;
|
return helper;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
st_shadow_helper_update (StShadowHelper *helper,
|
||||||
|
ClutterActor *source)
|
||||||
|
{
|
||||||
|
gfloat width, height;
|
||||||
|
|
||||||
|
clutter_actor_get_size (source, &width, &height);
|
||||||
|
|
||||||
|
if (helper->material == NULL ||
|
||||||
|
helper->width != width ||
|
||||||
|
helper->height != height)
|
||||||
|
{
|
||||||
|
if (helper->material)
|
||||||
|
cogl_object_unref (helper->material);
|
||||||
|
|
||||||
|
helper->material = _st_create_shadow_material_from_actor (helper->shadow, source);
|
||||||
|
helper->width = width;
|
||||||
|
helper->height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_shadow_helper_copy:
|
||||||
|
* @helper: the #StShadowHelper to copy
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a copy of @helper
|
||||||
|
*/
|
||||||
|
StShadowHelper *
|
||||||
|
st_shadow_helper_copy (StShadowHelper *helper)
|
||||||
|
{
|
||||||
|
StShadowHelper *copy;
|
||||||
|
|
||||||
|
copy = g_slice_new (StShadowHelper);
|
||||||
|
*copy = *helper;
|
||||||
|
if (copy->material)
|
||||||
|
cogl_object_ref (copy->material);
|
||||||
|
st_shadow_ref (copy->shadow);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_shadow_helper_free:
|
||||||
|
* @helper: a #StShadowHelper
|
||||||
|
*
|
||||||
|
* Free resources associated with @helper.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
st_shadow_helper_free (StShadowHelper *helper)
|
||||||
|
{
|
||||||
|
if (helper->material)
|
||||||
|
cogl_object_unref (helper->material);
|
||||||
|
st_shadow_unref (helper->shadow);
|
||||||
|
|
||||||
|
g_slice_free (StShadowHelper, helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_shadow_helper_paint:
|
||||||
|
* @helper: a #StShadowHelper
|
||||||
|
* @actor_box: the bounding box of the shadow
|
||||||
|
* @paint_opacity: the opacity at which the shadow is painted
|
||||||
|
*
|
||||||
|
* Paints the shadow associated with @helper This must only
|
||||||
|
* be called from the implementation of ClutterActor::paint().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
st_shadow_helper_paint (StShadowHelper *helper,
|
||||||
|
ClutterActorBox *actor_box,
|
||||||
|
guint8 paint_opacity)
|
||||||
|
{
|
||||||
|
ClutterActorBox allocation;
|
||||||
|
float width, height;
|
||||||
|
|
||||||
|
clutter_actor_box_get_size (actor_box, &width, &height);
|
||||||
|
|
||||||
|
allocation.x1 = (width - helper->width) / 2;
|
||||||
|
allocation.y1 = (height - helper->height) / 2;
|
||||||
|
allocation.x2 = allocation.x1 + helper->width;
|
||||||
|
allocation.y2 = allocation.y1 + helper->height;
|
||||||
|
|
||||||
|
_st_paint_shadow_with_opacity (helper->shadow,
|
||||||
|
helper->material,
|
||||||
|
&allocation,
|
||||||
|
paint_opacity);
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,10 @@
|
|||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define ST_TYPE_SHADOW (st_shadow_get_type ())
|
#define ST_TYPE_SHADOW (st_shadow_get_type ())
|
||||||
|
#define ST_TYPE_SHADOW_HELPER (st_shadow_get_type ())
|
||||||
|
|
||||||
typedef struct _StShadow StShadow;
|
typedef struct _StShadow StShadow;
|
||||||
|
typedef struct _StShadowHelper StShadowHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StShadow:
|
* StShadow:
|
||||||
@ -70,6 +72,21 @@ void st_shadow_get_box (StShadow *shadow,
|
|||||||
const ClutterActorBox *actor_box,
|
const ClutterActorBox *actor_box,
|
||||||
ClutterActorBox *shadow_box);
|
ClutterActorBox *shadow_box);
|
||||||
|
|
||||||
|
|
||||||
|
GType st_shadow_helper_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
StShadowHelper *st_shadow_helper_new (StShadow *shadow);
|
||||||
|
|
||||||
|
StShadowHelper *st_shadow_helper_copy (StShadowHelper *helper);
|
||||||
|
void st_shadow_helper_free (StShadowHelper *helper);
|
||||||
|
|
||||||
|
void st_shadow_helper_update (StShadowHelper *helper,
|
||||||
|
ClutterActor *source);
|
||||||
|
|
||||||
|
void st_shadow_helper_paint (StShadowHelper *helper,
|
||||||
|
ClutterActorBox *actor_box,
|
||||||
|
guint8 paint_opacity);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __ST_SHADOW__ */
|
#endif /* __ST_SHADOW__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user