~ubuntu-branches/ubuntu/trusty/gnome-contacts/trusty

« back to all changes in this revision

Viewing changes to src/cheese-flash.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Jeremy Bicha, Michael Biebl
  • Date: 2013-09-19 18:23:06 UTC
  • mfrom: (1.3.10) (0.3.4 experimental)
  • mto: This revision was merged to the branch mainline in revision 40.
  • Revision ID: package-import@ubuntu.com-20130919182306-rcatwotzg94pr884
Tags: 3.8.3-1
[ Jeremy Bicha ]
* debian/control.in:
  - Drop alternate build-depends on valac-0.18 since it's no longer
    in Debian

[ Michael Biebl ]
* New upstream release.
* Loosen Build-Depends on libgnome-desktop-3-dev, we do not strictly require
  version (>= 3.6.0) which is not yet available in unstable.
* Bump Standards-Version to 3.9.4. No further changes.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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>
 
5
 *
 
6
 * Licensed under the GNU General Public License Version 2
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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/>.
 
20
 */
 
21
 
 
22
#include <gtk/gtk.h>
 
23
 
 
24
#include "cheese-camera.h"
 
25
#include "cheese-flash.h"
 
26
 
 
27
/**
 
28
 * SECTION:cheese-flash
 
29
 * @short_description: Flash the screen, like a real camera flash
 
30
 * @stability: Unstable
 
31
 * @include: cheese/cheese-flash.h
 
32
 *
 
33
 * #CheeseFlash is a window that you can create and invoke a method "flash" on
 
34
 * to temporarily flood the screen with white.
 
35
 */
 
36
 
 
37
enum
 
38
{
 
39
  PROP_0,
 
40
  PROP_PARENT,
 
41
  PROP_LAST
 
42
};
 
43
 
 
44
static GParamSpec *properties[PROP_LAST];
 
45
 
 
46
/* How long to hold the flash for, in milliseconds. */
 
47
static const guint FLASH_DURATION = 250;
 
48
 
 
49
/* The factor which defines how much the flash fades per frame */
 
50
static const gdouble FLASH_FADE_FACTOR = 0.95;
 
51
 
 
52
/* How many frames per second */
 
53
static const guint FLASH_ANIMATION_RATE = 50;
 
54
 
 
55
/* When to consider the flash finished so we can stop fading */
 
56
static const gdouble FLASH_LOW_THRESHOLD = 0.01;
 
57
 
 
58
G_DEFINE_TYPE (CheeseFlash, cheese_flash, GTK_TYPE_WINDOW);
 
59
 
 
60
#define CHEESE_FLASH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_FLASH, CheeseFlashPrivate))
 
61
 
 
62
/*
 
63
 * CheeseFlashPrivate:
 
64
 * @parent: the parent #GtkWidget, for choosing on which display to fire the
 
65
 * flash
 
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
 
68
 *
 
69
 * Private data for #CheeseFlash.
 
70
 */
 
71
struct _CheeseFlashPrivate
 
72
{
 
73
  /*< private >*/
 
74
  GtkWidget *parent;
 
75
  guint flash_timeout_tag;
 
76
  guint fade_timeout_tag;
 
77
};
 
78
 
 
79
/*
 
80
 * cheese_flash_draw_event_cb:
 
81
 * @widget: the #CheeseFlash
 
82
 * @cr: the Cairo context
 
83
 * @user_data: the user data of the signal
 
84
 *
 
85
 * Draw the flash.
 
86
 *
 
87
 * Returns: %TRUE
 
88
 */
 
89
static gboolean
 
90
cheese_flash_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 
91
{
 
92
  cairo_fill (cr);
 
93
  return TRUE;
 
94
}
 
95
 
 
96
static void
 
97
cheese_flash_init (CheeseFlash *self)
 
98
{
 
99
  CheeseFlashPrivate *priv = self->priv = CHEESE_FLASH_GET_PRIVATE (self);
 
100
  cairo_region_t *input_region;
 
101
  GtkWindow *window = GTK_WINDOW (self);
 
102
 
 
103
  priv->flash_timeout_tag = 0;
 
104
  priv->fade_timeout_tag  = 0;
 
105
 
 
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);
 
111
 
 
112
  /* Don't take focus */
 
113
  gtk_window_set_accept_focus (window, FALSE);
 
114
  gtk_window_set_focus_on_map (window, FALSE);
 
115
 
 
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);
 
121
 
 
122
  g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (cheese_flash_draw_event_cb), NULL);
 
123
}
 
124
 
 
125
static void
 
126
cheese_flash_dispose (GObject *object)
 
127
{
 
128
  CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
 
129
 
 
130
  g_clear_object (&priv->parent);
 
131
 
 
132
  if (G_OBJECT_CLASS (cheese_flash_parent_class)->dispose)
 
133
    G_OBJECT_CLASS (cheese_flash_parent_class)->dispose (object);
 
134
}
 
135
 
 
136
static void
 
137
cheese_flash_finalize (GObject *object)
 
138
{
 
139
  if (G_OBJECT_CLASS (cheese_flash_parent_class)->finalize)
 
140
    G_OBJECT_CLASS (cheese_flash_parent_class)->finalize (object);
 
141
}
 
142
 
 
143
static void
 
144
cheese_flash_set_property (GObject      *object,
 
145
                           guint         prop_id,
 
146
                           const GValue *value,
 
147
                           GParamSpec   *pspec)
 
148
{
 
149
  CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
 
150
 
 
151
  switch (prop_id)
 
152
  {
 
153
    case PROP_PARENT: {
 
154
      GObject *object;
 
155
      object = g_value_get_object (value);
 
156
      if (object != NULL)
 
157
        priv->parent = g_object_ref (object);
 
158
      else
 
159
        priv->parent = NULL;
 
160
    }
 
161
    break;
 
162
    default:
 
163
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
164
      break;
 
165
  }
 
166
}
 
167
 
 
168
static void
 
169
cheese_flash_class_init (CheeseFlashClass *klass)
 
170
{
 
171
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
172
 
 
173
  g_type_class_add_private (klass, sizeof (CheeseFlashPrivate));
 
174
 
 
175
  object_class->set_property = cheese_flash_set_property;
 
176
  object_class->dispose      = cheese_flash_dispose;
 
177
  object_class->finalize     = cheese_flash_finalize;
 
178
 
 
179
  /**
 
180
   * CheeseFlash:parent:
 
181
   *
 
182
   * Parent #GtkWidget for the #CheeseFlash. The flash will be fired on the
 
183
   * screen where the parent widget is shown.
 
184
   */
 
185
  properties[PROP_PARENT] = g_param_spec_object ("parent",
 
186
                                                 "Parent widget",
 
187
                                                 "The flash will be fired on the screen where the parent widget is shown",
 
188
                                                 GTK_TYPE_WIDGET,
 
189
                                                 G_PARAM_WRITABLE |
 
190
                                                 G_PARAM_STATIC_STRINGS);
 
191
 
 
192
  g_object_class_install_properties (object_class, PROP_LAST, properties);
 
193
}
 
194
 
 
195
/*
 
196
 * cheese_flash_opacity_fade:
 
197
 * @data: the #CheeseFlash
 
198
 *
 
199
 * Fade the flash out.
 
200
 *
 
201
 * Returns: %TRUE if the fade was completed, %FALSE if the flash must continue
 
202
 * to fade
 
203
 */
 
204
static gboolean
 
205
cheese_flash_opacity_fade (gpointer data)
 
206
{
 
207
  GtkWindow *flash_window = GTK_WINDOW (data);
 
208
  gdouble opacity = gtk_window_get_opacity (flash_window);
 
209
 
 
210
  /* exponentially decrease */
 
211
  gtk_window_set_opacity (flash_window, opacity * FLASH_FADE_FACTOR);
 
212
 
 
213
  if (opacity <= FLASH_LOW_THRESHOLD)
 
214
  {
 
215
    /* the flasher has finished when we reach the quit value */
 
216
    gtk_widget_hide (GTK_WIDGET (flash_window));
 
217
    return G_SOURCE_REMOVE;
 
218
  }
 
219
 
 
220
  return G_SOURCE_CONTINUE;
 
221
}
 
222
 
 
223
/*
 
224
 * cheese_flash_start_fade:
 
225
 * @data: the #CheeseFlash
 
226
 *
 
227
 * Add a timeout to start the fade animation.
 
228
 *
 
229
 * Returns: %FALSE
 
230
 */
 
231
static gboolean
 
232
cheese_flash_start_fade (gpointer data)
 
233
{
 
234
  CheeseFlashPrivate *flash_priv = CHEESE_FLASH (data)->priv;
 
235
 
 
236
  GtkWindow *flash_window = GTK_WINDOW (data);
 
237
 
 
238
  /* If the screen is non-composited, just hide and finish up */
 
239
  if (!gdk_screen_is_composited (gtk_window_get_screen (flash_window)))
 
240
  {
 
241
    gtk_widget_hide (GTK_WIDGET (flash_window));
 
242
    return G_SOURCE_REMOVE;
 
243
  }
 
244
 
 
245
  flash_priv->fade_timeout_tag = g_timeout_add (1000.0 / FLASH_ANIMATION_RATE, cheese_flash_opacity_fade, data);
 
246
  return G_SOURCE_REMOVE;
 
247
}
 
248
 
 
249
/**
 
250
 * cheese_flash_fire:
 
251
 * @flash: a #CheeseFlash
 
252
 *
 
253
 * Fire the flash.
 
254
 */
 
255
void
 
256
cheese_flash_fire (CheeseFlash *flash)
 
257
{
 
258
  CheeseFlashPrivate *flash_priv;
 
259
  GtkWidget          *parent;
 
260
  GdkScreen          *screen;
 
261
  GdkRectangle        rect, work_rect;
 
262
  int                 monitor;
 
263
  GtkWindow *flash_window;
 
264
 
 
265
  g_return_if_fail (CHEESE_IS_FLASH (flash));
 
266
 
 
267
  flash_priv = flash->priv;
 
268
 
 
269
  g_return_if_fail (flash_priv->parent != NULL);
 
270
 
 
271
  flash_window = GTK_WINDOW (flash);
 
272
 
 
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);
 
277
 
 
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));
 
282
 
 
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);
 
286
 
 
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);
 
290
 
 
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);
 
294
}
 
295
 
 
296
/**
 
297
 * cheese_flash_new:
 
298
 * @parent: a parent #GtkWidget
 
299
 *
 
300
 * Create a new #CheeseFlash, associated with the @parent widget.
 
301
 *
 
302
 * Returns: a new #CheeseFlash
 
303
 */
 
304
CheeseFlash *
 
305
cheese_flash_new (GtkWidget *parent)
 
306
{
 
307
  return g_object_new (CHEESE_TYPE_FLASH,
 
308
                       "parent", parent,
 
309
                       "type", GTK_WINDOW_POPUP,
 
310
                       NULL);
 
311
}