2
* Copyright © 2008 Alexander “weej” Jones <alex@weej.com>
3
* Copyright © 2008 Thomas Perl <thp@thpinfo.com>
4
* Copyright © 2009 daniel g. siegel <dgsiegel@gnome.org>
6
* Licensed under the GNU General Public License Version 2
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24
#include "cheese-camera.h"
25
#include "cheese-flash.h"
28
* SECTION:cheese-flash
29
* @short_description: Flash the screen, like a real camera flash
30
* @stability: Unstable
31
* @include: cheese/cheese-flash.h
33
* #CheeseFlash is a window that you can create and invoke a method "flash" on
34
* to temporarily flood the screen with white.
44
static GParamSpec *properties[PROP_LAST];
46
/* How long to hold the flash for, in milliseconds. */
47
static const guint FLASH_DURATION = 250;
49
/* The factor which defines how much the flash fades per frame */
50
static const gdouble FLASH_FADE_FACTOR = 0.95;
52
/* How many frames per second */
53
static const guint FLASH_ANIMATION_RATE = 50;
55
/* When to consider the flash finished so we can stop fading */
56
static const gdouble FLASH_LOW_THRESHOLD = 0.01;
58
G_DEFINE_TYPE (CheeseFlash, cheese_flash, GTK_TYPE_WINDOW);
60
#define CHEESE_FLASH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_FLASH, CheeseFlashPrivate))
64
* @parent: the parent #GtkWidget, for choosing on which display to fire the
66
* @flash_timeout_tag: signal ID of the timeout to start fading in the flash
67
* @fade_timeout_tag: signal ID of the timeout to start fading out the flash
69
* Private data for #CheeseFlash.
71
struct _CheeseFlashPrivate
75
guint flash_timeout_tag;
76
guint fade_timeout_tag;
80
* cheese_flash_draw_event_cb:
81
* @widget: the #CheeseFlash
82
* @cr: the Cairo context
83
* @user_data: the user data of the signal
90
cheese_flash_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
97
cheese_flash_init (CheeseFlash *self)
99
CheeseFlashPrivate *priv = self->priv = CHEESE_FLASH_GET_PRIVATE (self);
100
cairo_region_t *input_region;
101
GtkWindow *window = GTK_WINDOW (self);
103
priv->flash_timeout_tag = 0;
104
priv->fade_timeout_tag = 0;
106
/* make it so it doesn't look like a window on the desktop (+fullscreen) */
107
gtk_window_set_decorated (window, FALSE);
108
gtk_window_set_skip_taskbar_hint (window, TRUE);
109
gtk_window_set_skip_pager_hint (window, TRUE);
110
gtk_window_set_keep_above (window, TRUE);
112
/* Don't take focus */
113
gtk_window_set_accept_focus (window, FALSE);
114
gtk_window_set_focus_on_map (window, FALSE);
116
/* Don't consume input */
117
gtk_widget_realize (GTK_WIDGET (window));
118
input_region = cairo_region_create ();
119
gdk_window_input_shape_combine_region (gtk_widget_get_window (GTK_WIDGET (window)), input_region, 0, 0);
120
cairo_region_destroy (input_region);
122
g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (cheese_flash_draw_event_cb), NULL);
126
cheese_flash_dispose (GObject *object)
128
CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
130
g_clear_object (&priv->parent);
132
if (G_OBJECT_CLASS (cheese_flash_parent_class)->dispose)
133
G_OBJECT_CLASS (cheese_flash_parent_class)->dispose (object);
137
cheese_flash_finalize (GObject *object)
139
if (G_OBJECT_CLASS (cheese_flash_parent_class)->finalize)
140
G_OBJECT_CLASS (cheese_flash_parent_class)->finalize (object);
144
cheese_flash_set_property (GObject *object,
149
CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
155
object = g_value_get_object (value);
157
priv->parent = g_object_ref (object);
163
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169
cheese_flash_class_init (CheeseFlashClass *klass)
171
GObjectClass *object_class = G_OBJECT_CLASS (klass);
173
g_type_class_add_private (klass, sizeof (CheeseFlashPrivate));
175
object_class->set_property = cheese_flash_set_property;
176
object_class->dispose = cheese_flash_dispose;
177
object_class->finalize = cheese_flash_finalize;
180
* CheeseFlash:parent:
182
* Parent #GtkWidget for the #CheeseFlash. The flash will be fired on the
183
* screen where the parent widget is shown.
185
properties[PROP_PARENT] = g_param_spec_object ("parent",
187
"The flash will be fired on the screen where the parent widget is shown",
190
G_PARAM_STATIC_STRINGS);
192
g_object_class_install_properties (object_class, PROP_LAST, properties);
196
* cheese_flash_opacity_fade:
197
* @data: the #CheeseFlash
199
* Fade the flash out.
201
* Returns: %TRUE if the fade was completed, %FALSE if the flash must continue
205
cheese_flash_opacity_fade (gpointer data)
207
GtkWindow *flash_window = GTK_WINDOW (data);
208
gdouble opacity = gtk_window_get_opacity (flash_window);
210
/* exponentially decrease */
211
gtk_window_set_opacity (flash_window, opacity * FLASH_FADE_FACTOR);
213
if (opacity <= FLASH_LOW_THRESHOLD)
215
/* the flasher has finished when we reach the quit value */
216
gtk_widget_hide (GTK_WIDGET (flash_window));
217
return G_SOURCE_REMOVE;
220
return G_SOURCE_CONTINUE;
224
* cheese_flash_start_fade:
225
* @data: the #CheeseFlash
227
* Add a timeout to start the fade animation.
232
cheese_flash_start_fade (gpointer data)
234
CheeseFlashPrivate *flash_priv = CHEESE_FLASH (data)->priv;
236
GtkWindow *flash_window = GTK_WINDOW (data);
238
/* If the screen is non-composited, just hide and finish up */
239
if (!gdk_screen_is_composited (gtk_window_get_screen (flash_window)))
241
gtk_widget_hide (GTK_WIDGET (flash_window));
242
return G_SOURCE_REMOVE;
245
flash_priv->fade_timeout_tag = g_timeout_add (1000.0 / FLASH_ANIMATION_RATE, cheese_flash_opacity_fade, data);
246
return G_SOURCE_REMOVE;
251
* @flash: a #CheeseFlash
256
cheese_flash_fire (CheeseFlash *flash)
258
CheeseFlashPrivate *flash_priv;
261
GdkRectangle rect, work_rect;
263
GtkWindow *flash_window;
265
g_return_if_fail (CHEESE_IS_FLASH (flash));
267
flash_priv = flash->priv;
269
g_return_if_fail (flash_priv->parent != NULL);
271
flash_window = GTK_WINDOW (flash);
273
if (flash_priv->flash_timeout_tag > 0)
274
g_source_remove (flash_priv->flash_timeout_tag);
275
if (flash_priv->fade_timeout_tag > 0)
276
g_source_remove (flash_priv->fade_timeout_tag);
278
parent = gtk_widget_get_toplevel (flash_priv->parent);
279
screen = gtk_widget_get_screen (parent);
280
monitor = gdk_screen_get_monitor_at_window (screen,
281
gtk_widget_get_window (parent));
283
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
284
gdk_screen_get_monitor_workarea (screen, monitor, &work_rect);
285
gdk_rectangle_intersect (&work_rect, &rect, &rect);
287
gtk_window_set_transient_for (GTK_WINDOW (flash_window), GTK_WINDOW (parent));
288
gtk_window_resize (flash_window, rect.width, rect.height);
289
gtk_window_move (flash_window, rect.x, rect.y);
291
gtk_window_set_opacity (flash_window, 1);
292
gtk_widget_show_all (GTK_WIDGET (flash_window));
293
flash_priv->flash_timeout_tag = g_timeout_add (FLASH_DURATION, cheese_flash_start_fade, (gpointer) flash);
298
* @parent: a parent #GtkWidget
300
* Create a new #CheeseFlash, associated with the @parent widget.
302
* Returns: a new #CheeseFlash
305
cheese_flash_new (GtkWidget *parent)
307
return g_object_new (CHEESE_TYPE_FLASH,
309
"type", GTK_WINDOW_POPUP,