2
* Copyright © 2009 Bastien Nocera <hadess@hadess.net>
4
* Licensed under the GNU General Public License Version 2
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#include "cheese-config.h"
22
#include <glib/gi18n.h>
24
#include "cheese-widget.h"
25
#include "cheese-gconf.h"
26
#include "cheese-camera.h"
27
#include "cheese-enum-types.h"
56
CheeseWidgetState state;
58
} CheeseWidgetPrivate;
60
#define CHEESE_WIDGET_GET_PRIVATE(o) \
61
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CHEESE_TYPE_WIDGET, \
64
G_DEFINE_TYPE (CheeseWidget, cheese_widget, GTK_TYPE_NOTEBOOK);
67
cheese_widget_load_pixbuf (GtkWidget *widget,
68
const char *icon_name,
75
theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
77
/* FIXME special case "no-webcam" and actually use the icon_name */
78
pixbuf = gtk_icon_theme_load_icon (theme, "dialog-error",
79
size, GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_FORCE_SIZE, error);
84
cheese_widget_logo_expose (GtkWidget *w,
85
GdkEventExpose *event,
88
const char *icon_name;
89
GdkPixbuf *pixbuf, *logo;
92
GtkAllocation allocation;
93
guint s_width, s_height, d_width, d_height;
96
gtk_widget_get_allocation (w, &allocation);
98
gdk_draw_rectangle (gtk_widget_get_window (w),
99
gtk_widget_get_style (w)->black_gc, TRUE,
100
0, 0, allocation.width, allocation.height);
101
icon_name = g_object_get_data (G_OBJECT (w), "icon-name");
102
if (icon_name == NULL)
105
cr = gdk_cairo_create (gtk_widget_get_window (w));
106
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
107
cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
109
d_width = allocation.width;
110
d_height = allocation.height - (allocation.height / 3);
112
pixbuf = cheese_widget_load_pixbuf (w, icon_name, d_height, &error);
115
g_warning ("Could not load icon '%s': %s", icon_name, error->message);
116
g_error_free (error);
120
s_width = gdk_pixbuf_get_width (pixbuf);
121
s_height = gdk_pixbuf_get_height (pixbuf);
123
if ((gfloat) d_width / s_width > (gfloat) d_height / s_height)
125
ratio = (gfloat) d_height / s_height;
129
ratio = (gfloat) d_width / s_width;
135
logo = gdk_pixbuf_scale_simple (pixbuf, s_width, s_height, GDK_INTERP_BILINEAR);
137
gdk_cairo_set_source_pixbuf (cr, logo, (allocation.width - s_width) / 2, (allocation.height - s_height) / 2);
141
g_object_unref (logo);
142
g_object_unref (pixbuf);
148
cheese_widget_spinner_invert (GtkWidget *spinner, GtkWidget *parent)
153
for (i = GTK_STATE_NORMAL; i <= GTK_STATE_INSENSITIVE; i++)
157
style = gtk_widget_get_style (spinner);
158
fg = gdk_color_copy (&style->fg[i]);
159
bg = gdk_color_copy (&style->bg[i]);
161
gtk_widget_modify_fg (spinner, i, bg);
162
gtk_widget_modify_bg (spinner, i, fg);
164
gtk_widget_modify_fg (parent, i, bg);
165
gtk_widget_modify_bg (parent, i, fg);
173
cheese_widget_set_problem_page (CheeseWidget *widget,
174
const char *icon_name)
176
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (widget);
178
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), PROBLEM_PAGE);
179
g_object_set_data_full (G_OBJECT (priv->problem),
180
"icon-name", g_strdup (icon_name), g_free);
181
g_signal_connect (priv->problem, "expose-event",
182
G_CALLBACK (cheese_widget_logo_expose), widget);
186
cheese_widget_init (CheeseWidget *widget)
188
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (widget);
191
priv->state = CHEESE_WIDGET_STATE_NONE;
195
* remove this line if you want to debug */
196
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
197
gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
200
priv->spinner = gtk_spinner_new ();
201
box = gtk_event_box_new ();
202
gtk_container_add (GTK_CONTAINER (box), priv->spinner);
203
cheese_widget_spinner_invert (priv->spinner, box);
204
gtk_widget_show_all (box);
206
gtk_notebook_append_page (GTK_NOTEBOOK (widget),
207
box, gtk_label_new ("spinner"));
210
priv->screen = gtk_drawing_area_new ();
211
gtk_widget_show (priv->screen);
212
gtk_notebook_append_page (GTK_NOTEBOOK (widget),
213
priv->screen, gtk_label_new ("webcam"));
216
priv->problem = gtk_drawing_area_new ();
217
gtk_widget_show (priv->problem);
218
gtk_notebook_append_page (GTK_NOTEBOOK (widget),
220
gtk_label_new ("got problems"));
222
priv->gconf = cheese_gconf_new ();
226
cheese_widget_finalize (GObject *object)
228
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (object);
232
g_object_unref (priv->gconf);
237
g_object_unref (priv->webcam);
241
G_OBJECT_CLASS (cheese_widget_parent_class)->finalize (object);
246
cheese_widget_set_property (GObject *object, guint prop_id,
250
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (object);
252
g_return_if_fail (CHEESE_IS_WIDGET (object));
257
priv->state = g_value_get_enum (value);
260
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267
cheese_widget_get_property (GObject *object, guint prop_id,
268
GValue *value, GParamSpec *pspec)
270
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (object);
272
g_return_if_fail (CHEESE_IS_WIDGET (object));
277
g_value_set_enum (value, priv->state);
280
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287
cheese_widget_changed (CheeseWidget *self)
294
setup_camera (CheeseWidget *widget)
296
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (widget);
297
char *webcam_device = NULL;
305
g_object_get (priv->gconf,
306
"gconf_prop_x_resolution", &x_resolution,
307
"gconf_prop_y_resolution", &y_resolution,
308
"gconf_prop_camera", &webcam_device,
309
"gconf_prop_brightness", &brightness,
310
"gconf_prop_contrast", &contrast,
311
"gconf_prop_saturation", &saturation,
312
"gconf_prop_hue", &hue,
315
gdk_threads_enter ();
316
priv->webcam = cheese_camera_new (priv->screen,
320
gdk_threads_leave ();
322
g_free (webcam_device);
324
cheese_camera_setup (priv->webcam, NULL, &priv->error);
326
gdk_threads_enter ();
328
gtk_spinner_stop (GTK_SPINNER (priv->spinner));
330
if (priv->error != NULL)
332
priv->state = CHEESE_WIDGET_STATE_ERROR;
333
g_object_notify (G_OBJECT (widget), "state");
334
cheese_widget_set_problem_page (CHEESE_WIDGET (widget), "error");
338
cheese_camera_set_balance_property (priv->webcam, "brightness", brightness);
339
cheese_camera_set_balance_property (priv->webcam, "contrast", contrast);
340
cheese_camera_set_balance_property (priv->webcam, "saturation", saturation);
341
cheese_camera_set_balance_property (priv->webcam, "hue", hue);
342
priv->state = CHEESE_WIDGET_STATE_READY;
343
g_object_notify (G_OBJECT (widget), "state");
344
cheese_camera_play (priv->webcam);
345
gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), WEBCAM_PAGE);
348
gdk_threads_leave ();
352
cheese_widget_realize (GtkWidget *widget)
355
CheeseWidgetPrivate *priv = CHEESE_WIDGET_GET_PRIVATE (widget);
357
GTK_WIDGET_CLASS (cheese_widget_parent_class)->realize (widget);
359
gtk_spinner_start (GTK_SPINNER (priv->spinner));
361
gtk_widget_realize (priv->screen);
362
window = gtk_widget_get_window (priv->screen);
363
if (!gdk_window_ensure_native (window))
365
/* abort: no native window, no xoverlay, no cheese. */
366
g_warning ("Could not create a native X11 window for the drawing area");
370
gdk_window_set_back_pixmap (gtk_widget_get_window (priv->screen), NULL, FALSE);
371
gtk_widget_set_app_paintable (priv->screen, TRUE);
372
gtk_widget_set_double_buffered (priv->screen, FALSE);
374
if (!g_thread_create ((GThreadFunc) setup_camera, widget, FALSE, &priv->error))
376
g_warning ("Failed to create setup thread: %s", priv->error->message);
380
gtk_widget_set_app_paintable (priv->problem, TRUE);
381
gtk_widget_realize (priv->problem);
382
gdk_window_set_back_pixmap (gtk_widget_get_window (priv->problem), NULL, FALSE);
387
gtk_spinner_stop (GTK_SPINNER (priv->spinner));
388
priv->state = CHEESE_WIDGET_STATE_ERROR;
389
g_object_notify (G_OBJECT (widget), "state");
390
cheese_widget_set_problem_page (CHEESE_WIDGET (widget), "error");
394
cheese_widget_class_init (CheeseWidgetClass *klass)
396
GObjectClass *object_class = G_OBJECT_CLASS (klass);
397
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
399
object_class->finalize = cheese_widget_finalize;
401
object_class->set_property = cheese_widget_set_property;
403
object_class->get_property = cheese_widget_get_property;
404
widget_class->realize = cheese_widget_realize;
407
* CheeseWidget:state:
409
* Current state of the widget.
411
* Connect to notify::state signal to get notified about state
412
* changes. Useful to update other widgets sensitiveness when the
413
* camera is ready or to handle errors if camera setup fails.
415
g_object_class_install_property (object_class, PROP_STATE,
416
g_param_spec_enum ("state",
419
CHEESE_TYPE_WIDGET_STATE,
420
CHEESE_WIDGET_STATE_NONE,
423
g_type_class_add_private (klass, sizeof (CheeseWidgetPrivate));
429
* Returns a new #CheeseWidget widget.
431
* Return value: a #CheeseWidget widget.
434
cheese_widget_new (void)
436
return g_object_new (CHEESE_TYPE_WIDGET, NULL);
440
cheese_widget_get_gconf (CheeseWidget *widget)
442
CheeseWidgetPrivate *priv;
444
g_return_val_if_fail (CHEESE_WIDGET (widget), NULL);
446
priv = CHEESE_WIDGET_GET_PRIVATE (widget);
448
return G_OBJECT (priv->gconf);
452
cheese_widget_get_camera (CheeseWidget *widget)
454
CheeseWidgetPrivate *priv;
456
g_return_val_if_fail (CHEESE_WIDGET (widget), NULL);
458
priv = CHEESE_WIDGET_GET_PRIVATE (widget);
460
return G_OBJECT (priv->webcam);
464
cheese_widget_get_video_area (CheeseWidget *widget)
466
CheeseWidgetPrivate *priv;
468
g_return_val_if_fail (CHEESE_WIDGET (widget), NULL);
470
priv = CHEESE_WIDGET_GET_PRIVATE (widget);
476
* cheese_widget_get_error:
477
* @widget: a #CheeseWidget
478
* @error: return location for the error
480
* Listen for notify::state signals and call this when the current state is %CHEESE_WIDGET_STATE_ERROR.
482
* The returned #GError will contain more details on what went wrong.
486
cheese_widget_get_error (CheeseWidget *widget, GError **error)
488
CheeseWidgetPrivate *priv;
490
g_return_if_fail (CHEESE_WIDGET (widget));
492
priv = CHEESE_WIDGET_GET_PRIVATE (widget);
494
g_propagate_error (error, priv->error);
500
* vim: sw=2 ts=8 cindent noai bs=2