static void status_button_toggled (GtkToggleButton *button, gpointer data) { ZBarGtk *zbar = ZBAR_GTK(data); gboolean opened = zbar_gtk_get_video_opened(zbar); gboolean enabled = zbar_gtk_get_video_enabled(zbar); gboolean active = gtk_toggle_button_get_active(button); if(opened && (active != enabled)) zbar_gtk_set_video_enabled(ZBAR_GTK(data), active); gtk_image_set_from_stock(GTK_IMAGE(status_image), (opened && active) ? GTK_STOCK_YES : GTK_STOCK_NO, GTK_ICON_SIZE_BUTTON); gtk_button_set_label(GTK_BUTTON(button), (!opened) ? "closed" : (active) ? "enabled" : "disabled"); }
static void open_button_clicked (GtkButton *button, gpointer data) { GtkWidget *dialog = gtk_file_chooser_dialog_new("Open Image File", GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog); if(open_file) gtk_file_chooser_set_filename(chooser, open_file); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { gchar *file = gtk_file_chooser_get_filename(chooser); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, NULL); if(pixbuf) zbar_gtk_scan_image(ZBAR_GTK(data), pixbuf); else fprintf(stderr, "ERROR: unable to open image file: %s\n", file); if(open_file && file) g_free(open_file); open_file = file; } gtk_widget_destroy(dialog); }
static void zbar_gtk_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ZBarGtk *self = ZBAR_GTK(object); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); switch(prop_id) { case PROP_VIDEO_DEVICE: if(zbar->video_device) g_value_set_string(value, zbar->video_device); else g_value_set_static_string(value, ""); break; case PROP_VIDEO_ENABLED: g_value_set_boolean(value, zbar->video_enabled); break; case PROP_VIDEO_OPENED: g_value_set_boolean(value, zbar->video_opened); default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } }
static void zbar_gtk_unrealize (GtkWidget *widget) { if(GTK_WIDGET_MAPPED(widget)) gtk_widget_unmap(widget); ZBarGtk *self = ZBAR_GTK(widget); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); if(zbar->video_enabled) { zbar->video_enabled = FALSE; GValue *msg = zbar_gtk_new_value(G_TYPE_INT); g_value_set_int(msg, 0); g_async_queue_push(zbar->queue, msg); } zbar_window_attach(zbar->window, NULL, 0); GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED); gdk_window_set_user_data(widget->window, NULL); gdk_window_destroy(widget->window); widget->window = NULL; }
static void zbar_gtk_realize (GtkWidget *widget) { ZBarGtk *self = ZBAR_GTK(widget); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); GTK_WIDGET_UNSET_FLAGS(widget, GTK_DOUBLE_BUFFERED); GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); GdkWindowAttr attributes; attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = (gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK); widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, GDK_WA_X | GDK_WA_Y); gdk_window_set_user_data(widget->window, widget); gdk_window_set_back_pixmap(widget->window, NULL, TRUE); /* attach zbar_window to underlying X window */ if(zbar_window_attach(zbar->window, gdk_x11_drawable_get_xdisplay(widget->window), gdk_x11_drawable_get_xid(widget->window))) zbar_window_error_spew(zbar->window, 0); }
/* (re)open the video when a new device is selected */ static void video_changed (GtkWidget *widget, gpointer data) { const char *video_device = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)); zbar_gtk_set_video_device(ZBAR_GTK(data), ((video_device && video_device[0] != '<') ? video_device : NULL)); }
static void video_opened (GObject *object, GParamSpec *param, gpointer data) { ZBarGtk *zbar = ZBAR_GTK(object); gboolean opened = zbar_gtk_get_video_opened(zbar); gboolean enabled = zbar_gtk_get_video_enabled(zbar); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data), opened && enabled); gtk_widget_set_sensitive(GTK_WIDGET(data), opened); }
/* update botton state when video state changes */ static void video_enabled (GObject *object, GParamSpec *param, gpointer data) { ZBarGtk *zbar = ZBAR_GTK(object); gboolean enabled = zbar_gtk_get_video_enabled(zbar); gboolean opened = zbar_gtk_get_video_opened(zbar); GtkToggleButton *button = GTK_TOGGLE_BUTTON(data); gboolean active = gtk_toggle_button_get_active(button); if(active != (opened && enabled)) gtk_toggle_button_set_active(button, enabled); }
static gboolean zbar_gtk_expose (GtkWidget *widget, GdkEventExpose *event) { ZBarGtk *self = ZBAR_GTK(widget); if(!self->_private) return(FALSE); ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); if(GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_MAPPED(widget) && zbar_window_redraw(zbar->window)) return(TRUE); return(FALSE); }
static void zbar_gtk_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { ZBarGtk *self = ZBAR_GTK(widget); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); (*GTK_WIDGET_CLASS(zbar_gtk_parent_class)->size_allocate) (widget, allocation); if(zbar->window) zbar_window_resize(zbar->window, allocation->width, allocation->height); }
static void zbar_gtk_size_request (GtkWidget *widget, GtkRequisition *requisition) { ZBarGtk *self = ZBAR_GTK(widget); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); /* use native video size (max) if available, * arbitrary defaults otherwise. * video attributes maintained under main gui thread lock */ requisition->width = zbar->req_width; requisition->height = zbar->req_height; }
static void zbar_gtk_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ZBarGtk *self = ZBAR_GTK(object); switch(prop_id) { case PROP_VIDEO_DEVICE: zbar_gtk_set_video_device(self, g_value_get_string(value)); break; case PROP_VIDEO_ENABLED: zbar_gtk_set_video_enabled(self, g_value_get_boolean(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } }
static void zbar_gtk_dispose (GObject *object) { ZBarGtk *self = ZBAR_GTK(object); if(!self->_private) return; ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); self->_private = NULL; g_free((void*)zbar->video_device); zbar->video_device = NULL; /* signal processor thread to exit */ GValue *msg = zbar_gtk_new_value(G_TYPE_INT); g_value_set_int(msg, -1); g_async_queue_push(zbar->queue, msg); zbar->thread = NULL; /* there are no external references which might call other APIs */ g_async_queue_unref(zbar->queue); g_object_unref(G_OBJECT(zbar)); }
static void *zbar_gtk_processing_thread (void *arg) { ZBarGtk *self = ZBAR_GTK(arg); if(!self->_private) return(NULL); ZBarGtkPrivate *zbar = ZBAR_GTK_PRIVATE(self->_private); g_object_ref(zbar); g_assert(zbar->queue); g_async_queue_ref(zbar->queue); zbar->scanner = zbar_image_scanner_create(); g_assert(zbar->scanner); /* thread side enabled state */ gboolean video_enabled = FALSE; GValue *msg = NULL; while(TRUE) { if(!msg) msg = g_async_queue_pop(zbar->queue); g_assert(G_IS_VALUE(msg)); GType type = G_VALUE_TYPE(msg); if(type == G_TYPE_INT) { /* video state change */ int state = g_value_get_int(msg); if(state < 0) { /* terminate processing thread */ g_value_unset(msg); g_free(msg); msg = NULL; break; } g_assert(state >= 0 && state <= 1); video_enabled = (state != 0); } else if(type == G_TYPE_STRING) { /* open new video device */ const char *video_device = g_value_get_string(msg); video_enabled = zbar_gtk_video_open(self, video_device); } else if(type == GDK_TYPE_PIXBUF) { /* scan provided image and broadcast results */ zbar_image_t *image = zbar_image_create(); GdkPixbuf *pixbuf = GDK_PIXBUF(g_value_dup_object(msg)); if(zbar_gtk_image_from_pixbuf(image, pixbuf)) zbar_gtk_process_image(self, image); else g_object_unref(pixbuf); zbar_image_destroy(image); } else { gchar *dbg = g_strdup_value_contents(msg); g_warning("unknown message type (%x) passed to thread: %s\n", (unsigned)type, dbg); g_free(dbg); } g_value_unset(msg); g_free(msg); msg = NULL; if(video_enabled) { /* release reference to any previous pixbuf */ zbar_window_draw(zbar->window, NULL); if(zbar_video_enable(zbar->video, 1)) { zbar_video_error_spew(zbar->video, 0); video_enabled = FALSE; continue; } zbar_image_scanner_enable_cache(zbar->scanner, 1); while(video_enabled && !(msg = g_async_queue_try_pop(zbar->queue))) { zbar_image_t *image = zbar_video_next_image(zbar->video); if(zbar_gtk_process_image(self, image) < 0) video_enabled = FALSE; if(image) zbar_image_destroy(image); } zbar_image_scanner_enable_cache(zbar->scanner, 0); if(zbar_video_enable(zbar->video, 0)) { zbar_video_error_spew(zbar->video, 0); video_enabled = FALSE; } /* release video image and revert to logo */ if(zbar->window) { zbar_window_draw(zbar->window, NULL); gtk_widget_queue_draw(GTK_WIDGET(self)); } if(!video_enabled) /* must have been an error while streaming */ zbar_gtk_video_open(self, NULL); } } if(zbar->window) zbar_window_draw(zbar->window, NULL); g_object_unref(zbar); return(NULL); }