From f085407d418daec88dcc23ee5869506bca7cafb6 Mon Sep 17 00:00:00 2001 From: Matthew Allum Date: Fri, 6 May 2005 17:41:15 +0000 Subject: [PATCH] Video widget updates --- ChangeLog | 29 ++ clutter/cltr-button.c | 12 + clutter/cltr-overlay.c | 13 +- clutter/cltr-photo-grid.c | 59 ++-- clutter/cltr-video.c | 687 +++++++++++++++++++++++++++----------- clutter/cltr-video.h | 26 +- clutter/cltr-widget.h | 2 - clutter/cltr-window.c | 35 +- clutter/cltr-window.h | 10 +- clutter/cltr.h | 12 +- clutter/fonts.c | 12 +- configure.ac | 4 +- examples/photos.c | 3 +- examples/player.c | 38 ++- examples/scratch.c | 14 +- 15 files changed, 696 insertions(+), 260 deletions(-) diff --git a/ChangeLog b/ChangeLog index d868a7eb7..4472d8270 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2005-05-06 mallum,,, + + * clutter/cltr-button.c: (cltr_button_new_with_label): + * clutter/cltr-overlay.c: + * clutter/cltr-photo-grid.c: (cltr_photo_grid_cell_new), + (cltr_photo_grid_paint), (cltr_photo_grid_new): + * clutter/cltr-video.c: (cltr_video_print_tag), (got_buffering), + (got_error), (caps_set), (parse_stream_info), (cb_iterate), + (cltr_video_new), (cltr_video_play), (cltr_video_seek), + (cltr_video_seek_time), (cltr_video_stop), (cltr_video_close), + (cltr_video_pause), (cltr_video_can_set_volume), + (cltr_video_set_volume), (cltr_video_get_volume), + (cltr_video_idler), (cltr_video_set_source), (cltr_video_show), + (cltr_video_hide), (cltr_video_handle_xevent), (cltr_video_paint): + * clutter/cltr-video.h: + * clutter/cltr-widget.h: + * clutter/cltr-window.c: (cltr_window_show), (cltr_window_paint), + (cltr_window_handle_xevent), (cltr_window_set_fullscreen), + (cltr_window_focus_widget): + * clutter/cltr-window.h: + * clutter/cltr.h: + * clutter/fonts.c: (get_layout_bitmap), (font_draw), + (font_get_pixel_size): + * configure.ac: + * examples/photos.c: (photo_grid_populate): + * examples/player.c: (handle_xevent), (main): + * examples/scratch.c: (main): + Lots more tweaks, mainly updating video widget. + 2005-04-29 mallum,,, * clutter/cltr-button.c: (cltr_button_new), diff --git a/clutter/cltr-button.c b/clutter/cltr-button.c index be8ea0277..d23019541 100644 --- a/clutter/cltr-button.c +++ b/clutter/cltr-button.c @@ -5,10 +5,13 @@ struct CltrButton { CltrWidget widget; CltrLabel *label; + Pixmap *pixb; + CltrTexture *texture; CltrButtonActivate activate_cb; void *activate_cb_data; + CltrButtonState state; /* may be better in widget ? */ }; @@ -85,6 +88,15 @@ cltr_button_new_with_label(const char *label, return CLTR_WIDGET(button); } +CltrWidget* +cltr_button_new_with_pixbuf(Pixbuf *pixb) +{ + CltrButton *button = NULL; + + button = CLTR_BUTTON(cltr_button_new(-1, -1)); + +} + static void cltr_button_show(CltrWidget *widget) { diff --git a/clutter/cltr-overlay.c b/clutter/cltr-overlay.c index 077a7bdb9..5865900bf 100644 --- a/clutter/cltr-overlay.c +++ b/clutter/cltr-overlay.c @@ -3,7 +3,7 @@ struct CltrOverlay { - CltrWidget widget; + CltrWidget widget; }; static void @@ -49,6 +49,17 @@ cltr_overlay_handle_xevent (CltrWidget *widget, XEvent *xev) static void cltr_overlay_paint(CltrWidget *widget) { + glEnable(GL_BLEND); + glColor4f(0.5, 0.5, 0.5, 1.0); + + cltr_glu_rounded_rect(widget->x, + widget->y, + widget->x + widget->width, + widget->y + widget->height, + widget->width/30, + NULL); + + glDisable(GL_BLEND); } diff --git a/clutter/cltr-photo-grid.c b/clutter/cltr-photo-grid.c index cb836a0c9..fa6a43519 100644 --- a/clutter/cltr-photo-grid.c +++ b/clutter/cltr-photo-grid.c @@ -132,7 +132,6 @@ cltr_photo_grid_cell_new(CltrPhotoGrid *grid, CltrPhotoGridCell *cell = NULL; int maxw = grid->widget.width, maxh = grid->widget.height; int neww = 0, newh = 0; - Pixbuf *tmp_pixb = NULL; cell = g_malloc0(sizeof(CltrPhotoGridCell)); @@ -540,7 +539,6 @@ cltr_photo_grid_paint(CltrWidget *widget) int x = 0, y = 0, rows = 0, cols = 0, i =0; GList *cell_item; - CltrWindow *win = CLTR_WINDOW(widget->parent); CltrPhotoGrid *grid = (CltrPhotoGrid *)widget; rows = grid->n_rows+1; @@ -551,10 +549,7 @@ cltr_photo_grid_paint(CltrWidget *widget) if (grid->cells_tail == NULL) { - /* No pictures to paint yet */ - CltrWindow *win = CLTR_WINDOW(grid->widget.parent); - - glColor3f(0.6, 0.6, 0.62); + glColor3ub(0xc2, 0xc3, 0xc1); glRecti(0, 0, widget->width, widget->height); glPopMatrix(); @@ -607,7 +602,7 @@ cltr_photo_grid_paint(CltrWidget *widget) CltrPhotoGridCell *cell = (CltrPhotoGridCell *)cell_item->data; Pixbuf *pixb = NULL; int x1, x2, y1, y2, thumb_w, thumb_h; - int ns_border, ew_border; + int ns_border, ew_border, selected_offset = 0; pixb = cell->pixb; @@ -636,8 +631,12 @@ cltr_photo_grid_paint(CltrWidget *widget) cell->anim_step = 0; } + if (cell_item == grid->cell_active + && grid->state == CLTR_PHOTO_GRID_STATE_BROWSE) + selected_offset = 2; + ew_border = thumb_w/8; - ns_border = thumb_h/8; + ns_border = (thumb_h/8) + 4; thumb_w -= (2 * ew_border); thumb_h -= (2 * ns_border); @@ -662,10 +661,10 @@ cltr_photo_grid_paint(CltrWidget *widget) g_mutex_lock(grid->mutex); cltr_texture_render_to_gl_quad(cell->texture, - -(thumb_w/2), - -(thumb_h/2), - (thumb_w/2), - (thumb_h/2)); + -(thumb_w/2) - selected_offset, + -(thumb_h/2) - selected_offset, + (thumb_w/2) - selected_offset, + (thumb_h/2) - selected_offset); g_mutex_unlock(grid->mutex); @@ -678,27 +677,47 @@ cltr_photo_grid_paint(CltrWidget *widget) else glColor4f(0.9, 0.95, 0.95, 1.0); + glColor4f(1.0, 1.0, 1.0, 1.0); + /* Draw with origin in center of photo */ - /* - glRecti(-(thumb_w/2)-4, -(thumb_h/2)-4, - (thumb_w/2)+4, (thumb_h/2)+ns_border); - */ + glRecti(-(thumb_w/2)-6 - selected_offset, + -(thumb_h/2)-6 - selected_offset, + (thumb_w/2)+6 - selected_offset, + (thumb_h/2)+ns_border - selected_offset); + + + /* cltr_glu_rounded_rect(-(thumb_w/2)-4, -(thumb_h/2)-4, (thumb_w/2)+4, (thumb_h/2)+ns_border, thumb_w/30, NULL); + */ + + + /* Nice colors */ + /* glColor4ub(0x3c, 0xbb, 0x15, 0xff); */ + /* glColor4ub(0x99, 0x99, 0xff, 0xff); */ + /* glColor4ub(0x99, 0x99, 0x99, 0xff); */ /* shadow */ + glColor4ub(0x99, 0x99, 0x99, 0xff); + glRecti(-(thumb_w/2)-6+2, -(thumb_h/2)-6+2, + (thumb_w/2)+6+2, (thumb_h/2)+ns_border+2); + + + /* glColor4f(0.1, 0.1, 0.1, 0.3); + cltr_glu_rounded_rect(-(thumb_w/2)-4 + 1, -(thumb_h/2)-4 + 1, (thumb_w/2)+4 + 1, (thumb_h/2)+ns_border +1, thumb_w/30, NULL); - + */ + glColor4f(1.0, 1.0, 1.0, 1.0); @@ -725,7 +744,9 @@ cltr_photo_grid_paint(CltrWidget *widget) /* finally paint background */ glDisable(GL_TEXTURE_2D); - glColor3f(0.6, 0.6, 0.62); + + glColor3ub(0xc2, 0xc3, 0xc1); + glRecti(0, 0, widget->width, widget->height); /* reset */ @@ -824,7 +845,7 @@ cltr_photo_grid_new(int width, grid->view_min_y = 0.0; /* Assmes cols == rows */ - grid->zoom_max = /* 1.0 + */ (float) (n_rows * 1.0); // - 0.3; + grid->zoom_max = (float) (n_rows * 1.0); grid->row_offset = 0; diff --git a/clutter/cltr-video.c b/clutter/cltr-video.c index 33565ac65..c55be0f6d 100644 --- a/clutter/cltr-video.c +++ b/clutter/cltr-video.c @@ -1,6 +1,8 @@ #include "cltr-video.h" #include "cltr-private.h" +/* This is all very much based on the totem gst bacon video widget */ + struct CltrVideo { CltrWidget widget; @@ -9,10 +11,20 @@ struct CltrVideo GAsyncQueue *queue; - int video_width, video_height; + gint video_width, video_height; + gdouble video_fps; CltrTexture *frame_texture; -}; + + gboolean has_video, has_audio; + gint64 stream_length; + gint64 current_time_nanos; + gint64 current_time; + float current_position; + + guint update_id; + char *last_error_message; +}; static void @@ -24,6 +36,14 @@ cltr_video_handle_xevent (CltrWidget *widget, XEvent *xev); static void cltr_video_paint(CltrWidget *widget); +static void +parse_stream_info (CltrVideo *video); + +static gboolean +cb_iterate (CltrVideo *video); + +static gboolean +cltr_video_idler (CltrVideo *video); static gint64 length = 0; /* to go */ @@ -59,83 +79,7 @@ cltr_video_print_tag (const GstTagList *list, } static void -cltr_video_got_found_tag (GstPlay *play, - GstElement *source, - GstTagList *tag_list, - CltrVideo *video) -{ - CltrVideoSignal *signal; - - signal = g_new0 (CltrVideoSignal, 1); - signal->signal_id = CLTR_VIDEO_ASYNC_FOUND_TAG; - signal->signal_data.found_tag.source = source; - signal->signal_data.found_tag.tag_list = gst_tag_list_copy (tag_list); - - g_async_queue_push (video->queue, signal); - - /* gst_tag_list_foreach (tag_list, cltr_video_print_tag, NULL); */ -} - -static void -cltr_video_got_time_tick (GstPlay *play, - gint64 time_nanos, - CltrVideo *video) -{ - - - /* - CltrVideoSignal *signal; - - signal = g_new0 (CltrVideoSignal, 1); - signal->signal_id = CLTR_VIDEO_ASYNC_FOUND_TAG; - signal->signal_data.found_tag.source = source; - signal->signal_data.found_tag.tag_list = gst_tag_list_copy (tag_list); - - g_async_queue_push (video->queue, signal); - */ - - g_print ("time tick %f\n", time_nanos / (float) GST_SECOND); -} - -static void -cltr_video_got_stream_length (GstPlay *play, - gint64 length_nanos, - CltrVideo *video) -{ - /* - CltrVideoSignal *signal; - - signal = g_new0 (CltrVideoSignal, 1); - - signal->signal_id = CLTR_VIDEO_ASYNC_VIDEO_SIZE; - signal->signal_data.video_size.width = width; - signal->signal_data.video_size.height = height; - - g_async_queue_push (video->queue, signal); - */ - CLTR_DBG ("got length %" G_GUINT64_FORMAT "\n", length_nanos); - length = length_nanos; -} - -static void -cltr_video_got_video_size (GstPlay *play, - gint width, - gint height, - CltrVideo *video) -{ - CltrVideoSignal *signal; - - signal = g_new0 (CltrVideoSignal, 1); - - signal->signal_id = CLTR_VIDEO_ASYNC_VIDEO_SIZE; - signal->signal_data.video_size.width = width; - signal->signal_data.video_size.height = height; - - g_async_queue_push (video->queue, signal); -} - -static void -cltr_video_got_eos (GstPlay* play, CltrVideo *video) +got_eos (GstPlay* play, CltrVideo *video) { CLTR_DBG ("End Of Stream\n"); @@ -150,60 +94,379 @@ cltr_video_got_eos (GstPlay* play, CltrVideo *video) gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); } -static gboolean -cltr_video_seek_timer (GstPlay * play) +static void +got_stream_length (GstElement *play, + gint64 length_nanos, + CltrVideo *video) { - gst_play_seek_to_time (play, length / 2); - return FALSE; + video->stream_length = (gint64) length_nanos / GST_MSECOND; + + /* fire off some callback here ? */ + + CLTR_DBG("length: %i", video->stream_length); } static void -caps_set (GObject *obj, - GParamSpec *pspec, - CltrVideo *video) +got_time_tick (GstElement *play, + gint64 time_nanos, + CltrVideo *video) { + CLTR_MARK(); + + video->current_time_nanos = time_nanos; + + video->current_time = (gint64) time_nanos / GST_MSECOND; + + if (video->stream_length == 0) + video->current_position = 0; + else + { + video->current_position = (float) video->current_time / video->stream_length; + } + + /* fire off callback here */ +} + + +static void +got_found_tag (GstPlay *play, + GstElement *source, + GstTagList *tag_list, + CltrVideo *video) +{ + CltrVideoSignal *signal; + + CLTR_MARK(); + + signal = g_new0 (CltrVideoSignal, 1); + signal->signal_id = CLTR_VIDEO_ASYNC_FOUND_TAG; + signal->signal_data.found_tag.source = source; + signal->signal_data.found_tag.tag_list = gst_tag_list_copy (tag_list); + + g_async_queue_push (video->queue, signal); + + /* gst_tag_list_foreach (tag_list, cltr_video_print_tag, NULL); */ +} + +static void +got_state_change (GstElement *play, + GstElementState old_state, + GstElementState new_state, + CltrVideo *video) +{ + if (old_state == GST_STATE_PLAYING) + { + if (video->update_id != 0) + { + g_source_remove (video->update_id); + video->update_id = 0; + } + + g_idle_remove_by_data (video); + + } + else if (new_state == GST_STATE_PLAYING) + { + if (video->update_id != 0) + g_source_remove (video->update_id); + + video->update_id = g_timeout_add (200, (GSourceFunc) cb_iterate, video); + + g_idle_add((GSourceFunc) cltr_video_idler, video); + } + + if (old_state <= GST_STATE_READY && new_state >= GST_STATE_PAUSED) + { + parse_stream_info (video); + } + else if (new_state <= GST_STATE_READY && old_state >= GST_STATE_PAUSED) + { + video->has_video = FALSE; + video->has_audio = FALSE; + + /* + if (bvw->priv->tagcache) + { + gst_tag_list_free (bvw->priv->tagcache); + bvw->priv->tagcache = NULL; + } + */ + + video->video_width = 0; + video->video_height = 0; + } +} + + +static void +got_redirect (GstElement *play, + const gchar *new_location, + CltrVideo *bvw) +{ + CLTR_MARK(); + + /* + bvw->priv->got_redirect = TRUE; + + signal = g_new0 (BVWSignal, 1); + signal->signal_id = ASYNC_REDIRECT; + signal->signal_data.redirect.new_location = g_strdup (new_location); + + g_async_queue_push (bvw->priv->queue, signal); + + g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw); + */ +} + + +static void +stream_info_set (GObject *obj, + GParamSpec *pspec, + CltrVideo *video) +{ + + parse_stream_info (video); + + /* + signal = g_new0 (BVWSignal, 1); + signal->signal_id = ASYNC_NOTIFY_STREAMINFO; + + g_async_queue_push (bvw->priv->queue, signal); + + g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw); + */ +} + +static void +got_source (GObject *play, + GParamSpec *pspec, + CltrVideo *video) +{ + GObject *source = NULL; + GObjectClass *klass; + + CLTR_MARK(); + + /* + if (bvw->priv->tagcache) { + gst_tag_list_free (bvw->priv->tagcache); + bvw->priv->tagcache = NULL; + } + + if (!bvw->priv->media_device) + return; + + g_object_get (play, "source", &source, NULL); + if (!source) + return; + + klass = G_OBJECT_GET_CLASS (source); + if (!g_object_class_find_property (klass, "device")) + return; + + g_object_set (source, "device", bvw->priv->media_device, NULL); + */ +} + + +static void +got_buffering (GstElement *play, + gint percentage, + CltrVideo *video) +{ + CLTR_DBG("Buffering with %i", percentage); + #if 0 + BVWSignal *signal; + + g_return_if_fail (bvw != NULL); + g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw)); + + signal = g_new0 (BVWSignal, 1); + signal->signal_id = ASYNC_BUFFERING; + signal->signal_data.buffering.percent = percentage; + + g_async_queue_push (bvw->priv->queue, signal); + + g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw); +#endif +} + + +static void +got_error (GstElement *play, + GstElement *orig, + GError *error, + gchar *debug, + CltrVideo *video) +{ + + /* + XXX TODO cpy the error message to asyc queueu + + */ + + CLTR_MARK(); + +#if 0 + /* since we're opening, we will never enter the mainloop + * until we return, so setting an idle handler doesn't + * help... Anyway, let's prepare a message. */ + if (GST_STATE (play) != GST_STATE_PLAYING) { + g_free (bvw->priv->last_error_message); + bvw->priv->last_error_message = g_strdup (error->message); + return; + } + + signal = g_new0 (BVWSignal, 1); + signal->signal_id = ASYNC_ERROR; + signal->signal_data.error.element = orig; + signal->signal_data.error.error = g_error_copy (error); + if (debug) + signal->signal_data.error.debug_message = g_strdup (debug); + + g_async_queue_push (bvw->priv->queue, signal); + + g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw); +#endif +} + + +static void +caps_set (GObject *obj, + GParamSpec *pspec, + CltrVideo *video) +{ GstPad *pad = GST_PAD (obj); GstStructure *s; if (!GST_PAD_CAPS (pad)) return; - - s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0); - if (s) { + if (s) + { + /* const GValue *par; */ + if (!(gst_structure_get_double (s, "framerate", &video->video_fps) && + gst_structure_get_int (s, "width", &video->video_width) && + gst_structure_get_int (s, "height", &video->video_height))) + return; - const GValue *par; + /* + if ((par = gst_structure_get_value (s, "pixel-aspect-ratio"))) + { + gint num = gst_value_get_fraction_numerator (par), + den = gst_value_get_fraction_denominator (par); - if (!(gst_structure_get_double (s, "framerate", &bvw->priv->video_fps) && - gst_structure_get_int (s, "width", &bvw->priv->video_width) && - gst_structure_get_int (s, "height", &bvw->priv->video_height))) - return; - if ((par = gst_structure_get_value (s, - "pixel-aspect-ratio"))) { - gint num = gst_value_get_fraction_numerator (par), - den = gst_value_get_fraction_denominator (par); + if (num > den) + bvw->priv->video_width *= (gfloat) num / den; + else + bvw->priv->video_height *= (gfloat) den / num; + } - if (num > den) - bvw->priv->video_width *= (gfloat) num / den; - else - bvw->priv->video_height *= (gfloat) den / num; - } - - got_video_size (bvw->priv->play, bvw->priv->video_width, - bvw->priv->video_height, bvw); + got_video_size (bvw->priv->play, bvw->priv->video_width, + bvw->priv->video_height, bvw); + */ } -#endif - - /* and disable ourselves */ - //g_signal_handlers_disconnect_by_func (pad, caps_set, bvw); } +static void +parse_stream_info (CltrVideo *video) +{ + GList *streaminfo = NULL; + GstPad *videopad = NULL; + + g_object_get (G_OBJECT (video->play), "stream-info", &streaminfo, NULL); + + streaminfo = g_list_copy (streaminfo); + + g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL); + + for ( ; streaminfo != NULL; streaminfo = streaminfo->next) + { + GObject *info = streaminfo->data; + gint type; + GParamSpec *pspec; + GEnumValue *val; + + if (!info) + continue; + + g_object_get (info, "type", &type, NULL); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info), "type"); + + val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type); + + if (strstr (val->value_name, "AUDIO")) + { + if (!video->has_audio) { + video->has_audio = TRUE; + /*if (!bvw->priv->media_has_video && + bvw->priv->show_vfx && bvw->priv->vis_element) { + videopad = gst_element_get_pad (bvw->priv->vis_element, "src"); + }*/ + } + } + else if (strstr (val->value_name, "VIDEO")) + { + video->has_video = TRUE; + if (!videopad) + g_object_get (info, "object", &videopad, NULL); + + } + } + + if (videopad) + { + GstPad *real = (GstPad *) GST_PAD_REALIZE (videopad); + + /* handle explicit caps as well - they're set later */ + if (((GstRealPad *) real)->link != NULL && GST_PAD_CAPS (real)) + caps_set (G_OBJECT (real), NULL, video); + + g_signal_connect (real, "notify::caps", G_CALLBACK (caps_set), video); + + } + /* + else if (bvw->priv->show_vfx && bvw->priv->vis_element) + { + fixate_visualization (NULL, NULL, bvw); + } + */ + + g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL); + g_list_free (streaminfo); +} + +static gboolean +cb_iterate (CltrVideo *video) +{ + GstFormat fmt = GST_FORMAT_TIME; + gint64 value; + + /* check length/pos of stream */ + if (gst_element_query (GST_ELEMENT (video->play), + GST_QUERY_TOTAL, &fmt, &value) + && GST_CLOCK_TIME_IS_VALID (value) + && value / GST_MSECOND != video->stream_length) + { + got_stream_length (GST_ELEMENT (video->play), value, video); + } + + if (gst_element_query (GST_ELEMENT (video->play), + GST_QUERY_POSITION, &fmt, &value)) + { + got_time_tick (GST_ELEMENT (video->play), value, video); + } + + return TRUE; +} + CltrWidget* cltr_video_new(int width, int height) { @@ -274,15 +537,14 @@ cltr_video_new(int width, int height) #endif g_signal_connect (G_OBJECT (video->play), "eos", - G_CALLBACK (cltr_video_got_eos), (gpointer) video); - /* - g_signal_connect (G_OBJECT (video->play), "state-change", - G_CALLBACK (state_change), (gpointer) video); - */ - g_signal_connect (G_OBJECT (video->play), "found_tag", - G_CALLBACK (cltr_video_got_found_tag), (gpointer) video); + G_CALLBACK (got_eos), (gpointer) video); + + g_signal_connect (G_OBJECT (video->play), "state-change", + G_CALLBACK (got_state_change), (gpointer) video); + + g_signal_connect (G_OBJECT (video->play), "found_tag", + G_CALLBACK (got_found_tag), (gpointer) video); - /* g_signal_connect (G_OBJECT (video->play), "error", G_CALLBACK (got_error), (gpointer) video); @@ -291,13 +553,18 @@ cltr_video_new(int width, int height) g_signal_connect (G_OBJECT (video->play), "notify::source", G_CALLBACK (got_source), (gpointer) video); + g_signal_connect (G_OBJECT (video->play), "notify::stream-info", G_CALLBACK (stream_info_set), (gpointer) video); + + /* what does this do ? g_signal_connect (G_OBJECT (video->play), "group-switch", G_CALLBACK (group_switch), (gpointer) video); + */ + g_signal_connect (G_OBJECT (video->play), "got-redirect", G_CALLBACK (got_redirect), (gpointer) video); - */ + video->queue = g_async_queue_new (); @@ -305,76 +572,114 @@ cltr_video_new(int width, int height) return CLTR_WIDGET(video); +} -#if 0 - video->play = gst_play_new (&error); +gboolean +cltr_video_play ( CltrVideo *video, GError ** error) +{ + gboolean ret; - if (error) + if (video->last_error_message) { - g_print ("Error: could not create play object:\n%s\n", error->message); - g_error_free (error); - return NULL; + g_free (video->last_error_message); + video->last_error_message = NULL; } - /* Getting default audio and video plugins from GConf */ - video->vis_element = gst_element_factory_make ("goom", "vis_element"); - video->data_src = gst_element_factory_make ("gnomevfssrc", "source"); + ret = (gst_element_set_state (GST_ELEMENT (video->play), + GST_STATE_PLAYING) == GST_STATE_SUCCESS); + if (!ret) + { + g_set_error (error, 0, 0, "%s", video->last_error_message ? + video->last_error_message : "Failed to play; reason unknown"); + } - video->audio_sink = gst_gconf_get_default_audio_sink (); + return ret; +} - if (!GST_IS_ELEMENT (video->audio_sink)) - g_error ("Could not get default audio sink from GConf"); +gboolean +cltr_video_seek (CltrVideo *video, float position, GError **gerror) +{ + gint64 seek_time, length_nanos; - video->video_sink = gst_element_factory_make ("cltrimagesink", "cltr-output"); + /* Resetting last_error_message to NULL */ + if (video->last_error_message) + { + g_free (video->last_error_message); + video->last_error_message = NULL; + } - if (!GST_IS_ELEMENT (video->video_sink)) - g_error ("Could not get clutter video sink"); + length_nanos = (gint64) (video->stream_length * GST_MSECOND); + seek_time = (gint64) (length_nanos * position); - video->queue = g_async_queue_new (); + gst_element_seek (video->play, GST_SEEK_METHOD_SET | + GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME, + seek_time); - gst_element_set(video->video_sink, "queue", video->queue, NULL); + return TRUE; +} - /* Let's send them to GstPlay object */ +gboolean +cltr_video_seek_time (CltrVideo *video, gint64 time, GError **gerror) +{ + if (video->last_error_message) + { + g_free (video->last_error_message); + video->last_error_message = NULL; + } - if (!gst_play_set_audio_sink (video->play, video->audio_sink)) - g_warning ("Could not set audio sink"); - if (!gst_play_set_video_sink (video->play, video->video_sink)) - g_warning ("Could not set video sink"); - if (!gst_play_set_data_src (video->play, video->data_src)) - g_warning ("Could not set data src"); - if (!gst_play_set_visualization (video->play, video->vis_element)) - g_warning ("Could not set visualisation"); + gst_element_seek (video->play, GST_SEEK_METHOD_SET | + GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME, + time * GST_MSECOND); - /* Setting location we want to play */ + return TRUE; +} - /* Uncomment that line to get an XML dump of the pipeline */ - /* gst_xml_write_file (GST_ELEMENT (play), stdout); */ +void +cltr_video_stop ( CltrVideo *video) +{ + gst_element_set_state (GST_ELEMENT (video->play), GST_STATE_READY); +} - g_signal_connect (G_OBJECT (video->play), "time_tick", - G_CALLBACK (cltr_video_got_time_tick), video); - g_signal_connect (G_OBJECT (video->play), "stream_length", - G_CALLBACK (cltr_video_got_stream_length), video); - g_signal_connect (G_OBJECT (video->play), "have_video_size", - G_CALLBACK (cltr_video_got_video_size), video); - g_signal_connect (G_OBJECT (video->play), "found_tag", - G_CALLBACK (cltr_video_got_found_tag), video); - g_signal_connect (G_OBJECT (video->play), "error", - G_CALLBACK (gst_element_default_error), NULL); - g_signal_connect (G_OBJECT (video->play), - "eos", G_CALLBACK (cltr_video_got_eos), video); +void +cltr_video_close ( CltrVideo *video) +{ + gst_element_set_state (GST_ELEMENT (video->play), GST_STATE_READY); + + /* XX close callback here */ +} - g_signal_connect (G_OBJECT (video->video_sink), "notify::caps", - G_CALLBACK (caps_set), video); +void +cltr_video_pause ( CltrVideo *video) +{ + gst_element_set_state (GST_ELEMENT (video->play), GST_STATE_PAUSED); +} -#endif - /* - g_object_set (G_OBJECT (video->play), "volume", - (gdouble) (1. * 0 / 100), NULL); - */ - /* gst_element_set_state (GST_ELEMENT (play), GST_STATE_READY); */ +gboolean +cltr_video_can_set_volume ( CltrVideo *video ) +{ + return TRUE; +} - return CLTR_WIDGET(video); +void +cltr_video_set_volume ( CltrVideo *video, int volume) +{ + if (cltr_video_can_set_volume (video) != FALSE) + { + volume = CLAMP (volume, 0, 100); + g_object_set (G_OBJECT (video->play), "volume", + (gdouble) (1. * volume / 100), NULL); + } +} + +int +cltr_video_get_volume ( CltrVideo *video) +{ + gdouble vol; + + g_object_get (G_OBJECT (video->play), "volume", &vol, NULL); + + return (gint) (vol * 100 + 0.5); } @@ -434,24 +739,6 @@ cltr_video_set_source(CltrVideo *video, char *location) return TRUE; } -void -cltr_video_play(CltrVideo *video) -{ - /* Change state to PLAYING */ - if (gst_element_set_state (GST_ELEMENT (video->play), - GST_STATE_PLAYING) == GST_STATE_FAILURE) - g_error ("Could not set state to PLAYING"); - - g_timeout_add(FPS_TO_TIMEOUT(30), (GSourceFunc) cltr_video_idler, video); -} - -void -cltr_video_pause(CltrVideo *video) -{ - if (gst_element_set_state (GST_ELEMENT (video->play), - GST_STATE_PAUSED) == GST_STATE_FAILURE) - g_error ("Could not set state to PAUSED"); -} static void @@ -482,23 +769,10 @@ cltr_video_paint(CltrWidget *widget) glPushMatrix(); if (video->frame_texture - /* && video->video_height - && video->video_width - */) + && video->video_width) { - int dis_x, dis_y, dis_height, dis_width; - - /* Hack */ - - if (!video->video_height || !video->video_width ) - { - Pixbuf *pixb = cltr_texture_get_pixbuf(video->frame_texture); - - video->video_height = pixb->height; - video->video_width = pixb->width; - } - + int dis_x = 0, dis_y = 0, dis_height = 0, dis_width = 0; if (video->video_width > video->video_height) { @@ -509,12 +783,13 @@ cltr_video_paint(CltrWidget *widget) dis_x = 0; } + + glEnable(GL_BLEND); + glColor4f(1.0, 1.0, 1.0, 1.0); glEnable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); cltr_texture_lock(video->frame_texture); @@ -528,6 +803,10 @@ cltr_video_paint(CltrWidget *widget) cltr_texture_unlock(video->frame_texture); glDisable(GL_TEXTURE_2D); + + glColor4f(1.0, 1.0, 1.0, 0.5); + + // glRecti(100, 100, 600, 600); } glPopMatrix(); diff --git a/clutter/cltr-video.h b/clutter/cltr-video.h index c5da08eba..165af5256 100644 --- a/clutter/cltr-video.h +++ b/clutter/cltr-video.h @@ -66,8 +66,32 @@ cltr_video_new(int width, int height); gboolean cltr_video_set_source(CltrVideo *video, char *location); +gboolean +cltr_video_play ( CltrVideo *video, GError ** Error); + +gboolean +cltr_video_seek (CltrVideo *video, float position, GError **gerror); + +gboolean +cltr_video_seek_time (CltrVideo *video, gint64 time, GError **gerror); + void -cltr_video_play(CltrVideo *video); +cltr_video_stop ( CltrVideo *video); + +void +cltr_video_close ( CltrVideo *video); + +void +cltr_video_pause ( CltrVideo *video); + +gboolean +cltr_video_can_set_volume ( CltrVideo *video ); + +void +cltr_video_set_volume ( CltrVideo *video, int volume); + +int +cltr_video_get_volume ( CltrVideo *video); #endif diff --git a/clutter/cltr-widget.h b/clutter/cltr-widget.h index 87e78562f..c7bb3773d 100644 --- a/clutter/cltr-widget.h +++ b/clutter/cltr-widget.h @@ -1,8 +1,6 @@ #ifndef _HAVE_CLTR_WIDGET_H #define _HAVE_CLTR_WIDGET_H -typedef struct CltrWidget CltrWidget; - #include "cltr.h" #define CLTR_WIDGET(w) ((CltrWidget*)(w)) diff --git a/clutter/cltr-window.c b/clutter/cltr-window.c index 27036cf04..38667f93b 100644 --- a/clutter/cltr-window.c +++ b/clutter/cltr-window.c @@ -12,9 +12,15 @@ cltr_window_paint(CltrWidget *widget); struct CltrWindow { - CltrWidget widget; - Window xwin; - CltrWidget *focused_child; + CltrWidget widget; + Window xwin; + CltrWidget *focused_child; + + CltrCallback *pre_paint_hook, *post_paint_hook; + + CltrXEventCallback xevent_cb; + void *xevent_cb_data; + }; void @@ -86,6 +92,10 @@ static void cltr_window_paint(CltrWidget *widget) { glClear(GL_COLOR_BUFFER_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glClearColor( 0.0, 0.0, 0.0, 0.0 ); /* needed for saturate to work */ } @@ -93,7 +103,6 @@ cltr_window_paint(CltrWidget *widget) static void cltr_window_handle_xconfigure(CltrWindow *win, XConfigureEvent *cxev) { - /* widget.width = cxev->width; widget.height = cxev->height; @@ -120,7 +129,10 @@ cltr_window_handle_xevent (CltrWidget *widget, XEvent *xev) /* XXX Very basic - assumes we are only interested in mouse clicks */ if (win->focused_child) - return cltr_widget_handle_xevent(win->focused_child, xev); + cltr_widget_handle_xevent(win->focused_child, xev); + + if (win->xevent_cb) + (win->xevent_cb)(widget, xev, win->xevent_cb_data); return FALSE; } @@ -157,12 +169,12 @@ cltr_window_set_fullscreen(CltrWindow *win) } -Window +void cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget) { /* XXX Should check widget is an actual child of the window */ - ClutterMainContext *ctx = CLTR_CONTEXT(); + /* ClutterMainContext *ctx = CLTR_CONTEXT(); */ if (win->focused_child) cltr_widget_unfocus(win->focused_child); @@ -172,4 +184,13 @@ cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget) win->focused_child = widget; } +void +cltr_window_on_xevent(CltrWindow *win, + CltrXEventCallback callback, + void *userdata) +{ + win->xevent_cb = callback; + win->xevent_cb_data = userdata; +} + diff --git a/clutter/cltr-window.h b/clutter/cltr-window.h index d3ff82a2b..46c16b724 100644 --- a/clutter/cltr-window.h +++ b/clutter/cltr-window.h @@ -10,9 +10,6 @@ typedef struct CltrWindow CltrWindow; CltrWidget* cltr_window_new(int width, int height); -void -cltr_window_paint(CltrWidget *widget); - void cltr_window_add_widget(CltrWindow *win, CltrWidget *widget, int x, int y); @@ -24,8 +21,13 @@ cltr_window_xwin(CltrWindow *win); void cltr_window_set_fullscreen(CltrWindow *win); -Window +void cltr_window_focus_widget(CltrWindow *win, CltrWidget *widget); +void +cltr_window_on_xevent(CltrWindow *win, + CltrXEventCallback callback, + void *userdata); + #endif diff --git a/clutter/cltr.h b/clutter/cltr.h index bc872a734..5ba2955ed 100644 --- a/clutter/cltr.h +++ b/clutter/cltr.h @@ -21,7 +21,6 @@ #include "pixbuf.h" #include "fonts.h" - typedef enum CltrDirection { CLTR_NORTH, @@ -44,6 +43,17 @@ typedef struct CltrTexture CltrTexture; #define cltr_rect_x2(r) ((r).x + (r).width) #define cltr_rect_y2(r) ((r).y + (r).height) +typedef struct CltrWidget CltrWidget; + + + +typedef void (*CltrCallback) (CltrWidget *widget, void *userdata) ; + +typedef void (*CltrXEventCallback) (CltrWidget *widget, + XEvent *xev, + void *userdata) ; + + /* texture stuff */ /* ******************* */ diff --git a/clutter/fonts.c b/clutter/fonts.c index 880695537..f3b265fc6 100644 --- a/clutter/fonts.c +++ b/clutter/fonts.c @@ -56,6 +56,8 @@ get_layout_bitmap (PangoLayout *layout, pango_layout_get_extents (layout, &ink_rect, NULL); + printf("%s() gave width:%i, height %i\n", __func__, ink->width, ink->height); + /* XXX why the >> 10 */ ink->x = ink_rect.x >> 10; ink->width = ((ink_rect.x + ink_rect.width + 1023) >> 10) - ink->x; @@ -170,14 +172,10 @@ font_draw(ClutterFont *font, layout = pango_layout_new (font->context); - pango_layout_set_width(layout, pixb->width - x ); - pango_layout_set_text (layout, text, -1); - pango_layout_get_pixel_size (layout, - &layout_width, &layout_height); - - /* cant rely on just clip - need to set layout width too */ + /* cant rely on just clip - need to set layout width too ? */ + /* pango_layout_set_width(layout, (pixb->width - x) << 10); */ draw_layout_on_pixbuf (layout, pixb, p, x, y, x, @@ -202,7 +200,7 @@ font_get_pixel_size (ClutterFont *font, pango_layout_get_pixel_size (layout, width, height); - printf("gave width:%i, height %i\n", *width, *height); + printf("%s() gave width:%i, height %i\n", __func__, *width, *height); g_object_unref(G_OBJECT(layout)); } diff --git a/configure.ac b/configure.ac index e1e67427f..c6688f3c7 100644 --- a/configure.ac +++ b/configure.ac @@ -61,8 +61,8 @@ fi dnl ----- Pango, glib etc --------------------------------------------------- -pkg_modules="pangoft2 pango glib-2.0 gthread-2.0" -PKG_CHECK_MODULES(CLTR, pangoft2 pango glib-2.0 gthread-2.0) +pkg_modules="pangoft2 glib-2.0 gthread-2.0" +PKG_CHECK_MODULES(CLTR, pangoft2 glib-2.0 gthread-2.0) dnl ----- Gstreamer --------------------------------------------------------- diff --git a/examples/photos.c b/examples/photos.c index f088a8f92..261cb21a0 100644 --- a/examples/photos.c +++ b/examples/photos.c @@ -55,10 +55,11 @@ photo_grid_populate(gpointer data) cell = cltr_photo_grid_cell_new(grid, pixb); + /* g_snprintf(&buf[0], 24, "%i", i); font_draw(font, cltr_photo_grid_cell_pixbuf(cell), buf, 10, 10, &font_col); - + */ g_mutex_lock(cltr_photo_grid_mutex(grid)); if (!cltr_photo_grid_get_active_cell(grid)) diff --git a/examples/player.c b/examples/player.c index 77f6a15e6..0c6b62f9a 100644 --- a/examples/player.c +++ b/examples/player.c @@ -19,6 +19,34 @@ #include +int Paused = 0; + +void +handle_xevent(CltrWidget *win, XEvent *xev, void *cookie) +{ + KeySym kc; + CltrVideo *video = CLTR_VIDEO(cookie); + + if (xev->type == KeyPress) + { + XKeyEvent *xkeyev = &xev->xkey; + + kc = XKeycodeToKeysym(xkeyev->display, xkeyev->keycode, 0); + + switch (kc) + { + case XK_Return: + if (Paused) + cltr_video_play (video, NULL); + else + cltr_video_pause (video); + Paused ^= 1; + break; + } + } + +} + int main (int argc, char *argv[]) { @@ -26,7 +54,7 @@ main (int argc, char *argv[]) CltrFont *font; PixbufPixel col = { 0xff, 0xff, 0xff, 0x66 }; - pixel_set_vals(&col, 0xff, 0x00, 0x00, 0xff); + pixel_set_vals(&col, 0x00, 0x00, 0x00, 0x99); cltr_init (&argc, &argv); @@ -45,13 +73,15 @@ main (int argc, char *argv[]) cltr_widget_add_child(win, video, 0, 0); - label = cltr_label_new("hello world", font, &col); + // label = cltr_label_new("hello world", font, &col); - cltr_widget_add_child(win, label, 100, 100); + // cltr_widget_add_child(win, label, 100, 300); + + cltr_window_on_xevent(CLTR_WINDOW(win), handle_xevent, video); cltr_widget_show_all(win); - cltr_video_play(CLTR_VIDEO(video)); + cltr_video_play(CLTR_VIDEO(video), NULL); cltr_main_loop(); diff --git a/examples/scratch.c b/examples/scratch.c index d89111d28..49606ba85 100644 --- a/examples/scratch.c +++ b/examples/scratch.c @@ -11,7 +11,7 @@ int main(int argc, char **argv) { int i; - CltrWidget *win = NULL, *grid = NULL, *test = NULL, *test2 = NULL; + CltrWidget *win = NULL, *grid = NULL, *test = NULL, *test2 = NULL, *list; CltrFont *font = NULL; PixbufPixel col = { 0xff, 0, 0, 0xff }; @@ -53,24 +53,23 @@ main(int argc, char **argv) if (want_fullscreen) cltr_window_set_fullscreen(CLTR_WINDOW(win)); - font = font_new("Sans 20"); + font = font_new("Sans Bold 11"); - test = cltr_button_new_with_label("ButtonBoooo\ndsfdsfdsf sss\nsjhsjhsjhs", font, &col); + test = cltr_button_new_with_label("ButtonBoooo\nd sfdsfdsfsss\nsjhsjhsjhs", font, &col); - test2 = cltr_button_new_with_label("Button", font, &col); + test2 = cltr_button_new_with_label("One Two", font, &col); cltr_widget_add_child(win, test, 300, 100); cltr_widget_add_child(win, test2, 100, 100); - cltr_window_focus_widget(CLTR_WINDOW(win), test); + cltr_window_focus_widget(CLTR_WINDOW(win), test2); cltr_widget_set_focus_next(test, test2, CLTR_EAST); cltr_widget_set_focus_next(test, test2, CLTR_WEST); cltr_widget_set_focus_next(test2, test, CLTR_EAST); cltr_widget_set_focus_next(test2, test, CLTR_WEST); - /* test = cltr_scratch_new(300, 100); test2 = cltr_scratch_new(150, 150); @@ -83,12 +82,13 @@ main(int argc, char **argv) /* cltr_widget_add_child(win, test, 320, 240); cltr_widget_add_child(win, test2, 400, 300); + */ list = cltr_list_new(640,480,640, 160); cltr_widget_add_child(win, list, 0, 0); - */ + cltr_window_focus_widget(CLTR_WINDOW(win), list); cltr_widget_show_all(win);