summaryrefslogtreecommitdiff
path: root/src/cheese-flash.c
diff options
context:
space:
mode:
authorJonh Wendell <jonh.wendell@intel.com>2013-07-10 16:09:14 -0300
committerJonh Wendell <jonh.wendell@intel.com>2013-07-10 16:09:14 -0300
commite404c5583b93fd0d5220d540922470e599936976 (patch)
tree1c3e7ec95fbde2494898109f40ba76e88a4a3d35 /src/cheese-flash.c
parent64243a9d75900cff2d85edb7342a0f1c5d28eec0 (diff)
downloadgnome-contacts-e404c5583b93fd0d5220d540922470e599936976.tar.gz
Sync cheese-flash.[ch]
And properly modify callers to the new API. Old code was creating a window with the size of the screen. Thus, when taking a photo, the gnome-shell panel was then "hidden" by this big window. This has been fixed in "upstream" cheese, so, grab the latest code and make small modifications to fit the new API. https://bugzilla.gnome.org/show_bug.cgi?id=702177
Diffstat (limited to 'src/cheese-flash.c')
-rw-r--r--src/cheese-flash.c244
1 files changed, 170 insertions, 74 deletions
diff --git a/src/cheese-flash.c b/src/cheese-flash.c
index 131c9b3..fd46818 100644
--- a/src/cheese-flash.c
+++ b/src/cheese-flash.c
@@ -19,46 +19,75 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* This is a "flash" object that you can create and invoke a method "flash" on to
- * flood the screen with white temporarily */
-
#include <gtk/gtk.h>
+#include "cheese-camera.h"
#include "cheese-flash.h"
-#ifdef GDK_WINDOWING_X11
-#include <X11/Xproto.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <gdk/gdkx.h>
-#endif /* GDK_WINDOWING_X11 */
+/**
+ * SECTION:cheese-flash
+ * @short_description: Flash the screen, like a real camera flash
+ * @stability: Unstable
+ * @include: cheese/cheese-flash.h
+ *
+ * #CheeseFlash is a window that you can create and invoke a method "flash" on
+ * to temporarily flood the screen with white.
+ */
+
+enum
+{
+ PROP_0,
+ PROP_PARENT,
+ PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
-/* How long to hold the flash for */
-#define FLASH_DURATION 150
+/* How long to hold the flash for, in milliseconds. */
+static const guint FLASH_DURATION = 250;
/* The factor which defines how much the flash fades per frame */
-#define FLASH_FADE_FACTOR 0.95
+static const gdouble FLASH_FADE_FACTOR = 0.95;
/* How many frames per second */
-#define FLASH_ANIMATION_RATE 120
+static const guint FLASH_ANIMATION_RATE = 50;
/* When to consider the flash finished so we can stop fading */
-#define FLASH_LOW_THRESHOLD 0.01
+static const gdouble FLASH_LOW_THRESHOLD = 0.01;
-G_DEFINE_TYPE (CheeseFlash, cheese_flash, G_TYPE_OBJECT);
+G_DEFINE_TYPE (CheeseFlash, cheese_flash, GTK_TYPE_WINDOW);
#define CHEESE_FLASH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_FLASH, CheeseFlashPrivate))
-typedef struct
+/*
+ * CheeseFlashPrivate:
+ * @parent: the parent #GtkWidget, for choosing on which display to fire the
+ * flash
+ * @flash_timeout_tag: signal ID of the timeout to start fading in the flash
+ * @fade_timeout_tag: signal ID of the timeout to start fading out the flash
+ *
+ * Private data for #CheeseFlash.
+ */
+struct _CheeseFlashPrivate
{
- GtkWindow *window;
+ /*< private >*/
+ GtkWidget *parent;
guint flash_timeout_tag;
guint fade_timeout_tag;
-} CheeseFlashPrivate;
+};
+/*
+ * cheese_flash_draw_event_cb:
+ * @widget: the #CheeseFlash
+ * @cr: the Cairo context
+ * @user_data: the user data of the signal
+ *
+ * Draw the flash.
+ *
+ * Returns: %TRUE
+ */
static gboolean
-cheese_flash_window_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
+cheese_flash_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
cairo_fill (cr);
return TRUE;
@@ -67,57 +96,38 @@ cheese_flash_window_draw_event_cb (GtkWidget *widget, cairo_t *cr, gpointer user
static void
cheese_flash_init (CheeseFlash *self)
{
- CheeseFlashPrivate *priv = CHEESE_FLASH_GET_PRIVATE (self);
+ CheeseFlashPrivate *priv = self->priv = CHEESE_FLASH_GET_PRIVATE (self);
cairo_region_t *input_region;
- GtkWindow *window;
- GdkScreen *screen;
- GdkVisual *visual;
+ GtkWindow *window = GTK_WINDOW (self);
priv->flash_timeout_tag = 0;
priv->fade_timeout_tag = 0;
- window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_POPUP));
-
/* make it so it doesn't look like a window on the desktop (+fullscreen) */
gtk_window_set_decorated (window, FALSE);
gtk_window_set_skip_taskbar_hint (window, TRUE);
gtk_window_set_skip_pager_hint (window, TRUE);
gtk_window_set_keep_above (window, TRUE);
- gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
/* Don't take focus */
gtk_window_set_accept_focus (window, FALSE);
gtk_window_set_focus_on_map (window, FALSE);
- /* no shadow */
- screen = gtk_widget_get_screen (GTK_WIDGET (window));
- visual = gdk_screen_get_rgba_visual (screen);
- if (visual == NULL)
- visual = gdk_screen_get_system_visual (screen);
-
- gtk_widget_set_visual (GTK_WIDGET (window), visual);
-
/* Don't consume input */
gtk_widget_realize (GTK_WIDGET (window));
-
input_region = cairo_region_create ();
gdk_window_input_shape_combine_region (gtk_widget_get_window (GTK_WIDGET (window)), input_region, 0, 0);
cairo_region_destroy (input_region);
- g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (cheese_flash_window_draw_event_cb), NULL);
- priv->window = window;
+ g_signal_connect (G_OBJECT (window), "draw", G_CALLBACK (cheese_flash_draw_event_cb), NULL);
}
static void
cheese_flash_dispose (GObject *object)
{
- CheeseFlashPrivate *priv = CHEESE_FLASH_GET_PRIVATE (object);
+ CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
- if (priv->window != NULL)
- {
- gtk_widget_destroy (GTK_WIDGET (priv->window));
- priv->window = NULL;
- }
+ g_clear_object (&priv->parent);
if (G_OBJECT_CLASS (cheese_flash_parent_class)->dispose)
G_OBJECT_CLASS (cheese_flash_parent_class)->dispose (object);
@@ -131,23 +141,71 @@ cheese_flash_finalize (GObject *object)
}
static void
+cheese_flash_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CheeseFlashPrivate *priv = CHEESE_FLASH (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PARENT: {
+ GObject *object;
+ object = g_value_get_object (value);
+ if (object != NULL)
+ priv->parent = g_object_ref (object);
+ else
+ priv->parent = NULL;
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
cheese_flash_class_init (CheeseFlashClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (CheeseFlashPrivate));
+ object_class->set_property = cheese_flash_set_property;
object_class->dispose = cheese_flash_dispose;
object_class->finalize = cheese_flash_finalize;
+
+ /**
+ * CheeseFlash:parent:
+ *
+ * Parent #GtkWidget for the #CheeseFlash. The flash will be fired on the
+ * screen where the parent widget is shown.
+ */
+ properties[PROP_PARENT] = g_param_spec_object ("parent",
+ "Parent widget",
+ "The flash will be fired on the screen where the parent widget is shown",
+ GTK_TYPE_WIDGET,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
}
+/*
+ * cheese_flash_opacity_fade:
+ * @data: the #CheeseFlash
+ *
+ * Fade the flash out.
+ *
+ * Returns: %TRUE if the fade was completed, %FALSE if the flash must continue
+ * to fade
+ */
static gboolean
cheese_flash_opacity_fade (gpointer data)
{
- CheeseFlash *flash = data;
- CheeseFlashPrivate *flash_priv = CHEESE_FLASH_GET_PRIVATE (flash);
- GtkWindow *flash_window = flash_priv->window;
- double opacity = gtk_window_get_opacity (flash_window);
+ GtkWindow *flash_window = GTK_WINDOW (data);
+ gdouble opacity = gtk_window_get_opacity (flash_window);
/* exponentially decrease */
gtk_window_set_opacity (flash_window, opacity * FLASH_FADE_FACTOR);
@@ -156,60 +214,98 @@ cheese_flash_opacity_fade (gpointer data)
{
/* the flasher has finished when we reach the quit value */
gtk_widget_hide (GTK_WIDGET (flash_window));
- return FALSE;
+ return G_SOURCE_REMOVE;
}
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
+/*
+ * cheese_flash_start_fade:
+ * @data: the #CheeseFlash
+ *
+ * Add a timeout to start the fade animation.
+ *
+ * Returns: %FALSE
+ */
static gboolean
cheese_flash_start_fade (gpointer data)
{
- CheeseFlash *self = data;
- CheeseFlashPrivate *flash_priv = CHEESE_FLASH_GET_PRIVATE (self);
- GtkWindow *flash_window = flash_priv->window;
+ CheeseFlashPrivate *flash_priv = CHEESE_FLASH (data)->priv;
+
+ GtkWindow *flash_window = GTK_WINDOW (data);
/* If the screen is non-composited, just hide and finish up */
if (!gdk_screen_is_composited (gtk_window_get_screen (flash_window)))
{
gtk_widget_hide (GTK_WIDGET (flash_window));
- return FALSE;
+ return G_SOURCE_REMOVE;
}
- flash_priv->fade_timeout_tag =
- g_timeout_add_full (G_PRIORITY_DEFAULT,
- 1000.0 / FLASH_ANIMATION_RATE,
- cheese_flash_opacity_fade,
- g_object_ref (self), g_object_unref);
- return FALSE;
+ flash_priv->fade_timeout_tag = g_timeout_add (1000.0 / FLASH_ANIMATION_RATE, cheese_flash_opacity_fade, data);
+ return G_SOURCE_REMOVE;
}
+/**
+ * cheese_flash_fire:
+ * @flash: a #CheeseFlash
+ *
+ * Fire the flash.
+ */
void
-cheese_flash_fire (CheeseFlash *flash,
- GdkRectangle *rect)
+cheese_flash_fire (CheeseFlash *flash)
{
- CheeseFlashPrivate *flash_priv = CHEESE_FLASH_GET_PRIVATE (flash);
- GtkWindow *flash_window = flash_priv->window;
+ CheeseFlashPrivate *flash_priv;
+ GtkWidget *parent;
+ GdkScreen *screen;
+ GdkRectangle rect, work_rect;
+ int monitor;
+ GtkWindow *flash_window;
+
+ g_return_if_fail (CHEESE_IS_FLASH (flash));
+
+ flash_priv = flash->priv;
+
+ g_return_if_fail (flash_priv->parent != NULL);
+
+ flash_window = GTK_WINDOW (flash);
if (flash_priv->flash_timeout_tag > 0)
g_source_remove (flash_priv->flash_timeout_tag);
if (flash_priv->fade_timeout_tag > 0)
g_source_remove (flash_priv->fade_timeout_tag);
- gtk_window_resize (flash_window, rect->width, rect->height);
- gtk_window_move (flash_window, rect->x, rect->y);
+ parent = gtk_widget_get_toplevel (flash_priv->parent);
+ screen = gtk_widget_get_screen (parent);
+ monitor = gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (parent));
+
+ gdk_screen_get_monitor_geometry (screen, monitor, &rect);
+ gdk_screen_get_monitor_workarea (screen, monitor, &work_rect);
+ gdk_rectangle_intersect (&work_rect, &rect, &rect);
+
+ gtk_window_set_transient_for (GTK_WINDOW (flash_window), GTK_WINDOW (parent));
+ gtk_window_resize (flash_window, rect.width, rect.height);
+ gtk_window_move (flash_window, rect.x, rect.y);
- gtk_window_set_opacity (flash_window, 0.99);
+ gtk_window_set_opacity (flash_window, 1);
gtk_widget_show_all (GTK_WIDGET (flash_window));
- flash_priv->flash_timeout_tag =
- g_timeout_add_full (G_PRIORITY_DEFAULT,
- FLASH_DURATION,
- cheese_flash_start_fade,
- g_object_ref (flash), g_object_unref);
+ flash_priv->flash_timeout_tag = g_timeout_add (FLASH_DURATION, cheese_flash_start_fade, (gpointer) flash);
}
+/**
+ * cheese_flash_new:
+ * @parent: a parent #GtkWidget
+ *
+ * Create a new #CheeseFlash, associated with the @parent widget.
+ *
+ * Returns: a new #CheeseFlash
+ */
CheeseFlash *
-cheese_flash_new (void)
+cheese_flash_new (GtkWidget *parent)
{
- return g_object_new (CHEESE_TYPE_FLASH, NULL);
+ return g_object_new (CHEESE_TYPE_FLASH,
+ "parent", parent,
+ "type", GTK_WINDOW_POPUP,
+ NULL);
}