File pinpoint-speakerview.patch of Package pinpoint
Subject: pinpoint speakerview patch
This is a diff from the upstream git tree v0.1.2 to commit
719837eb3150062bc8d82e466218348cfd467f18 to provide speakerview support
and lots of other fixes that haven't made it into a release yet.
Note, pdf output seems to be broken at the moment.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/.vimrc b/.vimrc
new file mode 100644
index 0000000..899811a
--- /dev/null
+++ b/.vimrc
@@ -0,0 +1,5 @@
+set tabstop=8
+set softtabstop=2
+set shiftwidth=2
+set expandtab
+set cinoptions=>4,n-2,{2,^-2,:0,=2,g0,h2,t0,+2,(0,u0,w1,m1
diff --git a/Makefile.am b/Makefile.am
index d100ac1..41442a7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,8 +1,8 @@
SUBDIRS=transitions
bin_PROGRAMS=pinpoint
-AM_CFLAGS = $(DEPS_CFLAGS) $(MAINTAINER_FLAGS) -D_GNU_SOURCE -DPKGDATADIR=\"$(pkgdatadir)/\"
-ACLOCAL_AMFLAGS = -I m4
+AM_CFLAGS = $(DEPS_CFLAGS) $(MAINTAINER_CFLAGS) -D_GNU_SOURCE -DPKGDATADIR=\"$(pkgdatadir)/\"
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
if USE_DAX
DAX_SOURCES = pp-super-aa.c pp-super-aa.h
diff --git a/README b/README
index 941d95e..435bba5 100644
--- a/README
+++ b/README
@@ -5,7 +5,7 @@ Pinpoint a simple presentation tool that hopes to avoid audience death by
bullet point and instead encourage presentations containing beautiful images
and small amounts of concise text in slides.
-Pinpoints main web-presence is a page in the GNOME wiki:
+Pinpoint’s main web presence is a page on the GNOME wiki:
http://live.gnome.org/Pinpoint
diff --git a/configure.ac b/configure.ac
index 641b9d7..0ca3092 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.53)
-AC_INIT(pinpoint, [0.1.2], [])
+AC_INIT(pinpoint, [0.1.3], [])
AC_CONFIG_SRCDIR(pinpoint.c)
AC_CONFIG_AUX_DIR([build])
AM_INIT_AUTOMAKE([foreign -Wno-portability no-define])
@@ -13,6 +13,12 @@ AC_HEADER_STDC
PINPOINT_DEPS="clutter-1.0 >= 1.4 gio-2.0 cairo-pdf pangocairo gdk-pixbuf-2.0"
AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [-Wall])
+AC_SUBST(MAINTAINER_CFLAGS)
+
+# Do we have clutter compiled for x11?
+PKG_CHECK_EXISTS([clutter-x11-1.0],
+ [AC_DEFINE([HAVE_CLUTTER_X11], [1],
+ [Whether clutter is compiled for x11])])
# PDF output support
AC_ARG_ENABLE([pdf],
diff --git a/gst-video-thumbnailer.c b/gst-video-thumbnailer.c
index fa2fbe2..ee0a340 100644
--- a/gst-video-thumbnailer.c
+++ b/gst-video-thumbnailer.c
@@ -17,6 +17,7 @@
*/
#include <config.h>
+
#ifdef USE_CLUTTER_GST
#include <string.h>
@@ -60,9 +61,9 @@ convert_buffer_to_pixbuf (GstBuffer *buffer,
GstElement *src, *sink, *colorspace, *scale, *filter;
GstBus *bus;
GstMessage *msg;
- GstStateChangeReturn state;
+ GstStateChangeReturn state G_GNUC_UNUSED;
gboolean ret;
- int width, height, dw, dh, i;
+ int dw, dh, i;
GstStructure *s;
s = gst_caps_get_structure (GST_BUFFER_CAPS (buffer), 0);
@@ -259,63 +260,4 @@ gst_video_thumbnailer_get_shot (const gchar *location,
return shot;
}
-
-static gboolean
-is_interesting (GdkPixbuf *pixbuf)
-{
- int width, height, r, rowstride;
- gboolean has_alpha;
- guint32 histogram[4][4][4] = {{{0,},},};
- guchar *pixels;
- int pxl_count = 0, count, i;
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
-
- pixels = gdk_pixbuf_get_pixels (pixbuf);
- for (r = 0; r < height; r++) {
- guchar *row = pixels + (r * rowstride);
- int c;
-
- for (c = 0; c < width; c++) {
- guchar r, g, b;
-
- r = row[0];
- g = row[1];
- b = row[2];
-
- histogram[r / 64][g / 64][b / 64]++;
-
- if (has_alpha) {
- row += 4;
- } else {
- row += 3;
- }
-
- pxl_count++;
- }
- }
-
- count = 0;
- for (i = 0; i < 4; i++) {
- int j;
- for (j = 0; j < 4; j++) {
- int k;
-
- for (k = 0; k < 4; k++) {
- /* Count how many bins have more than
- 1% of the pixels in the histogram */
- if (histogram[i][j][k] > pxl_count / 100) {
- count++;
- }
- }
- }
- }
-
- /* Image is boring if there is only 1 bin with > 1% of pixels */
- return count > 1;
-}
-
-#endif
+#endif /* USE_CLUTTER_GST */
diff --git a/introduction.pin b/introduction.pin
old mode 100755
new mode 100644
index a11c49e..bdf04b5
--- a/introduction.pin
+++ b/introduction.pin
@@ -1,18 +1,21 @@
#!/usr/bin/env pinpoint
-[font=Sans 50px]
-[bg.jpg]
-- The bits above this point are defaults for every slide in the presentation
+[bg.jpg]
+[font=Sans 50px]
+[duration=5.000000]
+-- [duration=4.448699]
Welcome to pinpoint
-- lines starting with - are slide separators.
+-- [duration=3.393199]
A tool for making excellent presentations
-- [bowls.jpg] You can override the defaults with with per-slide properties
+-- [bowls.jpg] [duration=4.322308]
It has a simple text source
-# The source can include witty comment lines
-
-- [font=monospace 18px] [shading-opacity=1.0]
+#The source can include witty comment lines!
+#These comments should fit on screen
+#The comments wrap
+#Using up/down should overstrike the speaker points?
+-- [font=monospace 18px] [shading-opacity=1.000000] [duration=23.560078]
The current presentation thus far:
#!/usr/bin/env pinpoint
[font=Sans 50px]
@@ -30,8 +33,8 @@ The current presentation thus far:
- [font=monospace 18px] [shading-opacity=1.0]
The current presentation thus far:
-
-- [text-align=center]
+#Should break this into smaller bits/slides
+-- [text-align=center] [duration=12.553503]
You start by writing down the core concepts that you will be talking about. Then sort and format
them as a pinpoint presentation in a text editor of your choice.
@@ -42,98 +45,97 @@ Pinpoint reloads the presentation when it changes on disk, very useful when you'
so keep both pinpoint and your text editor open. And remember, the less text you have, the happier
your audience will be ;-)
-
-- You can add '\n' before and after the slide text to keep the file tidy and slides seperated
+-- [duration=3.136431]
Let's use some of the more
esoteric features of pinpoint
-- [bowls.jpg] [text-align=center]
-\- [filename.jpg]
+-- [bowls.jpg] [text-align=center] [duration=5.757168]
+- [filename.jpg]
set a custom background for an individual slide
-- [bunny.ogg] [fill]
+-- [bunny.ogv] [fill] [duration=24.458597]
You can put <b>anything</b> in the background
-- [linus.jpg] [fill] [bottom-left]
+-- [linus.jpg] [fill] [bottom-left] [duration=3.724967]
But, slides with cat pictures are best
--[top-right] [text-align=right]
+-- [text-align=right] [top-right] [duration=1.879800]
position text in the
[top-right]
-- [right]
+-- [right] [duration=1.031598]
[right]
-- [bottom-right]
+-- [bottom-right] [duration=1.064696]
[bottom-right]
-- [bottom]
+-- [bottom] [duration=1.047646]
[bottom]
-- [bottom-left]
+-- [bottom-left] [duration=1.132064]
[bottom-left]
-- [left]
+-- [left] [duration=1.014935]
[left]
-- [top-left]
+-- [top-left] [duration=1.214729]
[top-left]
-- [top]
+-- [top] [duration=1.747087]
[top]
-- [center] [text-align=center]
+-- [text-align=center] [duration=4.109942]
and even in the
[center]
(which is the default)
-- [font=Monospace 100px][white][text-color=black][shading-opacity=0.0][bottom]
+-- [white] [bottom] [font=Monospace 100px] [text-color=black] [shading-opacity=0.000000] [duration=7.491852]
Make text big!
[font=Monospace 100px]
[white][text-color=black]
[shading-opacity=0.0][bottom]
--
+-- [duration=2.912952]
<s>use</s> <b>pango</b> <i
><span foreground='red'>m<u
>ar</u>k<sup>up</sup></span></i> for style
-- [no-markup]
+-- [duration=4.263503] [no-markup]
[no-markup]
<s>don't use</s> <b>pango</b> <i
><span foreground='red'>m<u
>ar</u>k<sup>up</sup></span></i>
-- [transition=page-curl-both][bowls.jpg]
+-- [bowls.jpg] [transition=page-curl-both] [duration=4.935558]
need bullets?
❥ use the power of unicode
• ✽ ✩ ✔ ☃ ◦
-- [transition=text-slide-up]
+-- [transition=text-slide-up] [duration=6.881204]
$ pinpoint presentation.txt -o output.pdf
Export to PDF. Handy.
-- [fill]
+-- [fill] [duration=3.903439]
[fill]
Fill the slide with your background
(the default is [fit])
-- [transition=swing]
+-- [transition=swing] [duration=2.679214]
Keybindings:
-- [transition=sheet]
+-- [transition=sheet] [duration=2.913154]
right, down or space - next slide
-- [transition=slide-left]
+-- [transition=slide-left] [duration=4.702688]
left or up - previous slide
-- [transition=slide-up]
-F11 - toggle fullscreen
+-- [transition=slide-up] [duration=3.435221]
+F11 - toggle fullscreen!
-- [transition=text-slide-down]
+-- [transition=text-slide-down] [duration=2.167284]
Escape - quit pinpoint
-- [transition=slide-in-left] [command=killall xeyes ; xeyes] [fill]
+-- [fill] [transition=slide-in-left] [command=killall xeyes ; xeyes] [duration=16.965691]
Enter - Run command
Tab - Edit command
[command=killall xeyes ; xeyes]
@@ -142,9 +144,9 @@ N.B. run pinpoint with the -m option
and hidden or auto-hiding panels, to
allow window management in fullscreen.
-- [linus.jpg] [fill] [bottom-right]
+-- [linus.jpg] [fill] [bottom-right] [duration=7.079270]
That's pretty much everything.
Told you it was simple.
-- [black] [font=Sans 100px] [transition=spin-text]
+-- [black] [font=Sans 100px] [transition=spin-text]
FIN
diff --git a/pinpoint.c b/pinpoint.c
index 9e732eb..fa98b9b 100644
--- a/pinpoint.c
+++ b/pinpoint.c
@@ -31,13 +31,20 @@
#include "pinpoint.h"
+#ifdef USE_CLUTTER_GST
+#include <clutter-gst/clutter-gst.h>
+#endif
+
+/* Probably time to create a PinPointPresentation type */
+
GList *pp_slides = NULL; /* list of slide text */
GList *pp_slidep = NULL; /* current slide */
+GFile *pp_basedir = NULL; /* basedir to resolve relative paths against */
typedef struct
{
const char *name;
- int value;
+ int value;
} EnumDescription;
static EnumDescription PPTextAlign_desc[] =
@@ -50,7 +57,8 @@ static EnumDescription PPTextAlign_desc[] =
#define PINPOINT_RENDERER(renderer) ((PinPointRenderer *) renderer)
-static PinPointPoint default_point = {
+/* pinpoint defaults */
+static PinPointPoint pin_default_point = {
.stage_color = "black",
.bg = "NULL",
@@ -64,17 +72,32 @@ static PinPointPoint default_point = {
.text_align = PP_TEXT_LEFT,
.use_markup = TRUE,
+ .duration = 30,
+
+ .speaker_notes = NULL,
+
.shading_color = "black",
.shading_opacity = 0.66,
- .transition = NULL,
+ .transition = "fade",
.command = NULL,
+
+ .camera_framerate = 0, /* auto */
+ .camera_resolution = {0, 0}, /* auto */
+
.data = NULL,
};
-char *pp_output_filename;
-gboolean pp_fullscreen = FALSE;
-gboolean pp_maximized = FALSE;
+static PinPointPoint default_point;
+
+PinPointPoint *point_defaults = &default_point;
+
+char *pp_output_filename = NULL;
+gboolean pp_fullscreen = FALSE;
+gboolean pp_maximized = FALSE;
+gboolean pp_speakermode = FALSE;
+gboolean pp_rehearse = FALSE;
+char *pp_camera_device = NULL;
static GOptionEntry entries[] =
{
@@ -85,9 +108,15 @@ static GOptionEntry entries[] =
" [command=] spawned apps.", NULL},
{ "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &pp_fullscreen,
"Start in fullscreen mode", NULL},
+ { "speakermode", 's', 0, G_OPTION_ARG_NONE, &pp_speakermode,
+ "Show speakermode window", NULL},
+ { "rehearse", 'r', 0, G_OPTION_ARG_NONE, &pp_rehearse,
+ "Rehearse timings", NULL},
{ "output", 'o', 0, G_OPTION_ARG_STRING, &pp_output_filename,
"Output presentation to FILE\n"
" (formats supported: pdf)", "FILE" },
+ { "camera", 'c', 0, G_OPTION_ARG_STRING, &pp_camera_device,
+ "Device to use for [camera] background", "DEVICE" },
{ NULL }
};
@@ -95,16 +124,58 @@ PinPointRenderer *pp_clutter_renderer (void);
#ifdef HAVE_PDF
PinPointRenderer *pp_cairo_renderer (void);
#endif
+static char * pp_serialize (void);
+
+void pp_rehearse_init (void)
+{
+ GList *iter;
+ for (iter = pp_slides; iter; iter=iter->next)
+ {
+ PinPointPoint *point = iter->data;
+ point->new_duration = 0.0;
+ }
+}
+
+
+static char *pinfile = NULL;
+
+static void pp_rehearse_save (void)
+{
+ GError *error = NULL;
+ char *content = pp_serialize ();
+ if (!g_file_set_contents (pinfile, content, -1, &error))
+ {
+ printf ("Failed to save to %s %s\n", pinfile, error->message);
+ }
+ else
+ {
+ printf ("saved to %s\n", pinfile);
+ }
+ g_free (content);
+}
+
+
+void pp_rehearse_done (void)
+{
+ GList *iter;
+ for (iter = pp_slides; iter; iter=iter->next)
+ {
+ PinPointPoint *point = iter->data;
+ point->duration = point->new_duration;
+ }
+ pp_rehearse_save ();
+}
int
main (int argc,
char **argv)
{
PinPointRenderer *renderer;
- GOptionContext *context;
+ GOptionContext *context;
GError *error = NULL;
- char *text = NULL;
+ char *text = NULL;
+ memcpy (&default_point, &pin_default_point, sizeof (default_point));
renderer = pp_clutter_renderer ();
context = g_option_context_new ("- Presentations made easy");
@@ -117,16 +188,20 @@ main (int argc,
return EXIT_FAILURE;
}
- if (!argv[1])
+ pinfile = argv[1];
+
+ if (!pinfile)
{
g_print ("usage: %s [options] <presentation>\n", argv[0]);
- text = g_strdup ("[no-markup][transition=sheet][red]\n--\nusage: pinpoint [options] <presentation.txt>\n");
+ text = g_strdup ("[no-markup][transition=sheet][red]\n"
+ "--\n"
+ "usage: pinpoint [options] <presentation.txt>\n");
}
else
{
- if (!g_file_get_contents (argv[1], &text, NULL, NULL))
+ if (!g_file_get_contents (pinfile, &text, NULL, NULL))
{
- g_print ("failed to load presentation from %s\n", argv[1]);
+ g_print ("failed to load presentation from %s\n", pinfile);
return -1;
}
}
@@ -153,15 +228,35 @@ main (int argc,
#endif
}
- renderer->init (renderer, argv[1]);
+ if (!pinfile)
+ pp_rehearse = FALSE;
+
+ if (pinfile)
+ {
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg (pinfile);
+ pp_basedir = g_file_get_parent (file);
+ g_object_unref (file);
+ }
+ renderer->init (renderer, pinfile);
pp_parse_slides (renderer, text);
g_free (text);
+ if (pp_rehearse)
+ {
+ pp_rehearse_init ();
+ printf ("Running in rehearsal mode, press ctrl+C to abort without saving timings back to %s\n", pinfile);
+ }
renderer->run (renderer);
renderer->finalize (renderer);
if (renderer->source)
g_free (renderer->source);
+#if 0
+ if (pp_rehearse)
+ pp_rehearse_save ();
+#endif
g_list_free (pp_slides);
@@ -265,6 +360,7 @@ pp_get_text_position_scale (PinPointPoint *point,
x = (stage_width - w * sx) / 2;
break;
}
+
switch (point->position)
{
case CLUTTER_GRAVITY_SOUTH:
@@ -312,13 +408,22 @@ pp_get_shading_position_size (float stage_width,
void pp_parse_slides (PinPointRenderer *renderer,
const char *slide_src);
+
/*
* Parsing
*/
static void
+parse_resolution (PPResolution *r,
+ const gchar *str)
+{
+ if (sscanf (str, "%dx%d", &r->width, &r->height) != 2)
+ r->width = r->height = 0;
+}
+
+static void
parse_setting (PinPointPoint *point,
- const gchar *setting)
+ const char *setting)
{
/* C Preprocessor macros implemeting a mini language for interpreting
* pinpoint key=value pairs
@@ -329,9 +434,11 @@ parse_setting (PinPointPoint *point,
#define END_PARSER }
#define IF_PREFIX(prefix) } else if (g_str_has_prefix (setting, prefix)) {
#define IF_EQUAL(string) } else if (g_str_equal (setting, string)) {
-#define char g_intern_string (strchrnul (setting, '=') + 1)
-#define float g_ascii_strtod (strchrnul (setting, '=') + 1, NULL);
-#define enum(r,t,s) \
+#define STRING g_intern_string (strchr (setting, '=') + 1)
+#define INT atoi (strchr (setting, '=') + 1)
+#define FLOAT g_ascii_strtod (strchr (setting, '=') + 1, NULL)
+#define RESOLUTION(r) parse_resolution (&r, strchr (setting, '=') + 1)
+#define ENUM(r,t,s) \
do { \
int _i; \
EnumDescription *_d = t##_desc; \
@@ -342,14 +449,17 @@ parse_setting (PinPointPoint *point,
} while (0)
START_PARSER
- IF_PREFIX("stage-color=") point->stage_color = char;
- IF_PREFIX("font=") point->font = char;
- IF_PREFIX("text-color=") point->text_color = char;
- IF_PREFIX("text-align=") enum(point->text_align, PPTextAlign, char);
- IF_PREFIX("shading-color=") point->shading_color = char;
- IF_PREFIX("shading-opacity=") point->shading_opacity = float;
- IF_PREFIX("command=") point->command = char;
- IF_PREFIX("transition=") point->transition = char;
+ IF_PREFIX("stage-color=") point->stage_color = STRING;
+ IF_PREFIX("font=") point->font = STRING;
+ IF_PREFIX("text-color=") point->text_color = STRING;
+ IF_PREFIX("text-align=") ENUM(point->text_align, PPTextAlign, STRING);
+ IF_PREFIX("shading-color=") point->shading_color = STRING;
+ IF_PREFIX("shading-opacity=") point->shading_opacity = FLOAT;
+ IF_PREFIX("duration=") point->duration = FLOAT;
+ IF_PREFIX("command=") point->command = STRING;
+ IF_PREFIX("transition=") point->transition = STRING;
+ IF_PREFIX("camera-framerate=") point->camera_framerate = INT;
+ IF_PREFIX("camera-resolution=") RESOLUTION (point->camera_resolution);
IF_EQUAL("fill") point->bg_scale = PP_BG_FILL;
IF_EQUAL("fit") point->bg_scale = PP_BG_FIT;
IF_EQUAL("stretch") point->bg_scale = PP_BG_STRETCH;
@@ -368,22 +478,24 @@ parse_setting (PinPointPoint *point,
DEFAULT point->bg = g_intern_string (setting);
END_PARSER
-/* undefine all the overrides, returning us to regular C */
+/* undefine the overrides, returning us to regular C */
#undef START_PARSER
#undef END_PARSER
#undef DEFAULT
#undef IF_PREFIX
#undef IF_EQUAL
-#undef float
-#undef char
-#undef enum
+#undef FLOAT
+#undef STRING
+#undef INT
+#undef ENUM
+#undef RESOLUTION
}
static void
parse_config (PinPointPoint *point,
const char *config)
{
- GString *str = g_string_new ("");
+ GString *str = g_string_new ("");
const char *p;
for (p = config; *p; p++)
@@ -411,6 +523,10 @@ pin_point_free (PinPointRenderer *renderer,
{
if (renderer->free_data)
renderer->free_data (renderer, point->data);
+ if (point->speaker_notes)
+ {
+ g_free (point->speaker_notes);
+ }
g_free (point);
}
@@ -435,17 +551,184 @@ pp_is_color (const char *string)
return clutter_color_from_string (&color, string);
}
+static gboolean
+str_has_video_suffix (const char *string)
+{
+ char *video_extensions[] =
+ {".avi", ".ogg", ".ogv", ".mpg", ".flv", ".mpeg",
+ ".mov", ".mp4", ".wmv", ".webm", ".mkv", NULL};
+ char **ext;
+
+ for (ext = video_extensions; *ext; ext ++)
+ if (g_str_has_suffix (string, *ext))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void serialize_slide_config (GString *str,
+ PinPointPoint *point,
+ PinPointPoint *reference,
+ const char *separator)
+{
+#define STRING(v,n) \
+ if (point->v != reference->v) \
+ g_string_append_printf (str, "%s[" n "%s]", separator, point->v)
+#define INT(v,n) \
+ if (point->v != reference->v) \
+ g_string_append_printf (str, "%s[" n "%d]", separator, point->v)
+#define FLOAT(v,n) \
+ if (point->v != reference->v) \
+ g_string_append_printf (str, "%s[" n "%f]", separator, point->v)
+
+ STRING(stage_color, "stage-color=");
+ STRING(bg, "");
+
+ if (point->bg_scale != reference->bg_scale)
+ {
+ g_string_append (str, separator);
+ switch (point->bg_scale)
+ {
+ case PP_BG_FILL: g_string_append (str, "[fill]"); break;
+ case PP_BG_FIT: g_string_append (str, "[fit]"); break;
+ case PP_BG_STRETCH: g_string_append (str, "[stretch]"); break;
+ case PP_BG_UNSCALED: g_string_append (str, "[unscaled]"); break;
+ }
+ }
+
+ if (point->text_align != reference->text_align)
+ {
+ g_string_append (str, separator);
+ switch (point->text_align)
+ {
+ case PP_TEXT_LEFT: g_string_append (str, "[text-align=left]");break;
+ case PP_TEXT_CENTER:g_string_append (str, "[text-align=center]");break;
+ case PP_TEXT_RIGHT: g_string_append (str, "[text-align=right]");break;
+ }
+ }
+
+ if (point->position != reference->position)
+ {
+ g_string_append (str, separator);
+ switch (point->position)
+ {
+ case CLUTTER_GRAVITY_NONE:
+ break;
+ case CLUTTER_GRAVITY_CENTER:
+ g_string_append (str, "[center]");break;
+ case CLUTTER_GRAVITY_NORTH:
+ g_string_append (str, "[top]");break;
+ case CLUTTER_GRAVITY_SOUTH:
+ g_string_append (str, "[bottom]");break;
+ case CLUTTER_GRAVITY_WEST:
+ g_string_append (str, "[left]");break;
+ case CLUTTER_GRAVITY_EAST:
+ g_string_append (str, "[right]");break;
+ case CLUTTER_GRAVITY_NORTH_WEST:
+ g_string_append (str, "[top-left]");break;
+ case CLUTTER_GRAVITY_NORTH_EAST:
+ g_string_append (str, "[top-right]");break;
+ case CLUTTER_GRAVITY_SOUTH_WEST:
+ g_string_append (str, "[bottom-left]");break;
+ case CLUTTER_GRAVITY_SOUTH_EAST:
+ g_string_append (str, "[bottom-right]");break;
+ }
+ }
+
+ STRING(font,"font=");
+ STRING(text_color,"text-color=");
+ STRING(shading_color,"shading-color=");
+ FLOAT(shading_opacity, "shading-opacity=");
+
+ STRING(transition,"transition=");
+ STRING(command,"command=");
+ if (point->duration != 0.0)
+ FLOAT(duration, "duration="); /* XXX: probably needs special treatment */
+
+ INT(camera_framerate, "camera-framerate=");
+ if (point->camera_resolution.width != reference->camera_resolution.width &&
+ point->camera_resolution.height != reference->camera_resolution.height)
+ {
+ g_string_append_printf (str, "[camera-resolution=%dx%d]",
+ point->camera_resolution.width,
+ point->camera_resolution.height);
+ }
+
+ if (point->use_markup != reference->use_markup)
+ {
+ g_string_append (str, separator);
+ if (point->use_markup)
+ g_string_append (str, "[markup]");
+ else
+ g_string_append (str, "[no-markup]");
+ }
+
+#undef FLOAT
+#undef INT
+#undef STRING
+}
+
+
+static void serialize_slide (GString *str,
+ PinPointPoint *point)
+{
+ g_string_append_c (str, '\n');
+ g_string_append (str, "--");
+ serialize_slide_config (str, point, &default_point, " ");
+ g_string_append (str, "\n");
+
+ g_string_append_printf (str, "%s\n", point->text);
+
+ if (point->speaker_notes)
+ {
+ char *p;
+ g_string_append_c (str, '#');
+ for (p = point->speaker_notes; *p; p++)
+ {
+ if (*p == '\n')
+ {
+ g_string_append_c (str, '\n');
+ if (*(p+1))
+ g_string_append_c (str, '#');
+ }
+ else
+ {
+ g_string_append_c (str, *p);
+ }
+ }
+ }
+}
+
+static char * pp_serialize (void)
+{
+ GString *str = g_string_new ("#!/usr/bin/env pinpoint\n");
+ char *ret;
+ GList *iter;
+
+ serialize_slide_config (str, &default_point, &pin_default_point, "\n");
+
+ for (iter = pp_slides; iter; iter = iter->next)
+ {
+ serialize_slide (str, iter->data);
+ }
+ ret = str->str;
+ g_string_free (str, FALSE);
+ return ret;
+}
+
void
pp_parse_slides (PinPointRenderer *renderer,
const char *slide_src)
{
const char *p;
- int slideno = 0;
- gboolean done = FALSE;
+ int slideno = 0;
+ gboolean done = FALSE;
gboolean startofline = TRUE;
- gboolean gotconfig = FALSE;
- GString *slide_str = g_string_new ("");
+ gboolean gotconfig = FALSE;
+ GString *slide_str = g_string_new ("");
GString *setting_str = g_string_new ("");
+ GString *notes_str = g_string_new ("");
GList *s;
PinPointPoint *point, *next_point;
@@ -456,7 +739,9 @@ pp_parse_slides (PinPointRenderer *renderer,
int lineno=0;
/* compute slide no that has changed */
for (pos = 0, slideno = 0;
- slide_src[pos] && renderer->source[pos] && slide_src[pos]==renderer->source[pos]
+ slide_src[pos] &&
+ renderer->source[pos] &&
+ slide_src[pos]==renderer->source[pos]
; pos ++)
{
switch (slide_src[pos])
@@ -472,7 +757,7 @@ pp_parse_slides (PinPointRenderer *renderer,
start_of_line = FALSE;
}
}
- slideno--;
+ slideno-=1;
g_free (renderer->source);
}
renderer->source = g_strdup (slide_src);
@@ -484,127 +769,130 @@ pp_parse_slides (PinPointRenderer *renderer,
pp_slides = NULL;
point = pin_point_new (renderer);
- /* parse the slides, constructing lists of objects, adding all generated
- * actors to the stage
+ /* parse the slides, constructing lists of slide/point objects
*/
for (p = slide_src; *p; p++)
{
switch (*p)
- {
- case '\\': /* escape the next char */
- p++;
- startofline = FALSE;
- if (*p)
+ {
+ case '\\': /* escape the next char */
+ p++;
+ startofline = FALSE;
+ if (*p)
+ g_string_append_c (slide_str, *p);
+ break;
+ case '\n':
+ startofline = TRUE;
g_string_append_c (slide_str, *p);
- break;
- case '\n':
- startofline = TRUE;
- g_string_append_c (slide_str, *p);
- break;
- case '-': /* slide seperator */
- close_last_slide:
- if (startofline)
- {
- startofline = FALSE;
- next_point = pin_point_new (renderer);
-
- g_string_assign (setting_str, "");
- while (*p && *p!='\n') /* until newline */
- {
- g_string_append_c (setting_str, *p);
- p++;
- }
- parse_config (next_point, setting_str->str);
+ break;
+ case '-': /* slide seperator */
+ close_last_slide:
+ if (startofline)
+ {
+ startofline = FALSE;
+ next_point = pin_point_new (renderer);
- if (!gotconfig)
- {
- parse_config (&default_point, slide_str->str);
- /* copy the default point except the per-slide allocated
- * data (void *) */
- memcpy (point, &default_point,
- sizeof (PinPointPoint) - sizeof (void *));
- parse_config (point, setting_str->str);
- gotconfig = TRUE;
- g_string_assign (slide_str, "");
- g_string_assign (setting_str, "");
- }
- else
- {
- if (point->bg && point->bg[0])
- {
- gchar *filename = g_strdup (point->bg);
- int i = 0;
-
- while (filename[i])
- {
- filename[i] = tolower(filename[i]);
- i++;
- }
- if (g_str_has_suffix (filename, ".avi")
- || g_str_has_suffix (filename, ".ogg")
- || g_str_has_suffix (filename, ".ogv")
- || g_str_has_suffix (filename, ".mpg")
- || g_str_has_suffix (filename, ".flv")
- || g_str_has_suffix (filename, ".mpeg")
- || g_str_has_suffix (filename, ".mov")
- || g_str_has_suffix (filename, ".mp4")
- || g_str_has_suffix (filename, ".wmv")
- || g_str_has_suffix (filename, ".webm")
- || g_str_has_suffix (filename, ".mkv"))
- point->bg_type = PP_BG_VIDEO;
- else if (g_str_has_suffix (filename, ".svg"))
- point->bg_type = PP_BG_SVG;
- else if (pp_is_color (point->bg))
- point->bg_type = PP_BG_COLOR;
- else
- point->bg_type = PP_BG_IMAGE;
- g_free (filename);
- }
+ g_string_assign (setting_str, "");
+ while (*p && *p!='\n') /* until newline */
+ {
+ g_string_append_c (setting_str, *p);
+ p++;
+ }
+ parse_config (next_point, setting_str->str);
+ if (!gotconfig)
+ {
+ parse_config (&default_point, slide_str->str);
+ /* copy the default point except the per-slide allocated
+ * data (void *) */
+ memcpy (point, &default_point,
+ sizeof (PinPointPoint) - sizeof (void *));
+ parse_config (point, setting_str->str);
+ gotconfig = TRUE;
+ g_string_assign (slide_str, "");
+ g_string_assign (setting_str, "");
+ g_string_assign (notes_str, "");
+ }
+ else
{
- char *str = slide_str->str;
+ if (point->bg && point->bg[0])
+ {
+ char *filename = g_strdup (point->bg);
+ int i = 0;
+
+ while (filename[i])
+ {
+ filename[i] = tolower(filename[i]);
+ i++;
+ }
+
+ if (strcmp (filename, "camera") == 0)
+ point->bg_type = PP_BG_CAMERA;
+ else if (str_has_video_suffix (filename))
+ point->bg_type = PP_BG_VIDEO;
+ else if (g_str_has_suffix (filename, ".svg"))
+ point->bg_type = PP_BG_SVG;
+ else if (pp_is_color (point->bg))
+ point->bg_type = PP_BG_COLOR;
+ else
+ point->bg_type = PP_BG_IMAGE;
+ g_free (filename);
+ }
- /* trim newlines from start and end. ' ' can be used in the
- * insane case that you actually want blank lines before or after
- * the text of a slide */
- while (*str == '\n') str++;
- while ( slide_str->str[strlen(slide_str->str)-1]=='\n')
- slide_str->str[strlen(slide_str->str)-1]='\0';
+ {
+ char *str = slide_str->str;
- point->text = g_intern_string (str);
- }
+ /* trim newlines from start and end. ' ' can be used in the
+ * insane case that you actually want blank lines before or
+ * after the text of a slide */
+ while (*str == '\n') str++;
+ while ( slide_str->str[strlen(slide_str->str)-1]=='\n')
+ slide_str->str[strlen(slide_str->str)-1]='\0';
- renderer->make_point (renderer, point);
+ point->text = g_intern_string (str);
+ }
+ if (notes_str->str[0])
+ point->speaker_notes = g_strdup (notes_str->str);
- g_string_assign (slide_str, "");
- g_string_assign (setting_str, "");
+ renderer->make_point (renderer, point);
- pp_slides = g_list_append (pp_slides, point);
- point = next_point;
- }
- }
- else
- {
- g_string_append_c (slide_str, *p);
- }
- break;
- case '#': /* comment */
- if (startofline)
- {
- char *end = strchr (p, '\n');
- if (end)
+ g_string_assign (slide_str, "");
+ g_string_assign (setting_str, "");
+ g_string_assign (notes_str, "");
+
+ pp_slides = g_list_append (pp_slides, point);
+ point = next_point;
+ }
+ }
+ else
{
- p = end;
- break;
+ g_string_append_c (slide_str, *p);
}
- }
- /* flow through */
- default:
- startofline = FALSE;
- g_string_append_c (slide_str, *p);
- break;
- }
+ break;
+ case '#': /* comment */
+ if (startofline)
+ {
+ const char *end = p + 1;
+ while (*end != '\n' && *end != '\0')
+ {
+ g_string_append_c (notes_str, *end);
+ end++;
+ }
+ if (end)
+ {
+ g_string_append_c (notes_str, '\n');
+ p = end;
+ break;
+ }
+ }
+ /* flow through */
+ default:
+ startofline = FALSE;
+ g_string_append_c (slide_str, *p);
+ break;
+ }
}
+
if (!done)
{
done = TRUE;
@@ -613,6 +901,7 @@ pp_parse_slides (PinPointRenderer *renderer,
g_string_free (slide_str, TRUE);
g_string_free (setting_str, TRUE);
+ g_string_free (notes_str, TRUE);
if (g_list_nth (pp_slides, slideno))
pp_slidep = g_list_nth (pp_slides, slideno);
diff --git a/pinpoint.h b/pinpoint.h
index cb02d39..3f26630 100644
--- a/pinpoint.h
+++ b/pinpoint.h
@@ -35,9 +35,9 @@ typedef struct _PinPointRenderer PinPointRenderer;
typedef enum
{
- PP_TEXT_LEFT = PANGO_ALIGN_LEFT,
+ PP_TEXT_LEFT = PANGO_ALIGN_LEFT,
PP_TEXT_CENTER = PANGO_ALIGN_CENTER,
- PP_TEXT_RIGHT = PANGO_ALIGN_RIGHT
+ PP_TEXT_RIGHT = PANGO_ALIGN_RIGHT
} PPTextAlign;
typedef enum
@@ -46,6 +46,7 @@ typedef enum
PP_BG_COLOR,
PP_BG_IMAGE,
PP_BG_VIDEO,
+ PP_BG_CAMERA,
PP_BG_SVG
} PPBackgroundType;
@@ -57,6 +58,11 @@ typedef enum
PP_BG_STRETCH
} PPBackgroundScale;
+typedef struct
+{
+ gint width, height;
+} PPResolution;
+
#define PINPOINT_RENDERER(renderer) ((PinPointRenderer *) renderer)
struct _PinPointRenderer
@@ -88,21 +94,37 @@ struct _PinPointPoint
const char *text_color;
gboolean use_markup;
+ gfloat duration; /* on slide 0 the duration is the duration of the
+ presentation, other slides have a representation
+ of their portion of the presentation */
+
+ gfloat new_duration; /* new duration,. used during reharsal */
+
+ char *speaker_notes; /* speaker comments for the slide */
+
const char *shading_color;
float shading_opacity;
const char *transition; /* transition template to use, if any */
const char *command;
+ gint camera_framerate;
+ PPResolution camera_resolution;
+
void *data; /* the renderer can attach data here */
};
-extern char *pp_output_filename;
-extern gboolean pp_fullscreen;
-extern gboolean pp_maximized;
+extern char *pp_output_filename;
+extern gboolean pp_fullscreen;
+extern gboolean pp_maximized;
+extern gboolean pp_speakermode;
+extern gboolean pp_rehearse;
+extern char *pp_camera_device;
-extern GList *pp_slides;
-extern GList *pp_slidep;
+extern GList *pp_slides; /* list of slide text */
+extern GList *pp_slidep; /* current slide */
+extern GFile *pp_basedir;
+extern PinPointPoint *point_defaults;
void pp_parse_slides (PinPointRenderer *renderer,
const char *slide_src);
@@ -112,6 +134,9 @@ pp_get_padding (float stage_width,
float stage_height,
float *padding);
+void pp_rehearse_init (void);
+void pp_rehearse_done (void);
+
void
pp_get_background_position_scale (PinPointPoint *point,
float stage_width,
diff --git a/pp-cairo.c b/pp-cairo.c
index 3c91094..a673674 100644
--- a/pp-cairo.c
+++ b/pp-cairo.c
@@ -41,17 +41,19 @@
typedef struct _CairoRenderer
{
PinPointRenderer renderer;
- gchar *path;
- GHashTable *surfaces; /* keep cairo_surface_t around for source
- images as we wantt to only include one
+ char *path;
+ GHashTable *surfaces; /* keep cairo_surface_t around for source
+ images as we want to only include one
instance of the image when using it in
several slides */
- GHashTable *svgs; /* keep RsvgHandles around for source
+ GHashTable *svgs; /* keep RsvgHandles around for source
svg backgrounds as we want to only
include one instance of the image
when using it in several slides */
- cairo_surface_t *surface;
- cairo_t *ctx;
+ cairo_surface_t *surface;
+ cairo_t *ctx;
+ double width;
+ double height;
} CairoRenderer;
typedef struct
@@ -76,8 +78,10 @@ cairo_renderer_init (PinPointRenderer *pp_renderer,
CairoRenderer *renderer = CAIRO_RENDERER (pp_renderer);
/* A4, landscape */
+ renderer->width = A4_LS_WIDTH;
+ renderer->height = A4_LS_HEIGHT;
renderer->surface = cairo_pdf_surface_create (pp_output_filename,
- A4_LS_WIDTH, A4_LS_HEIGHT);
+ renderer->width, renderer->height);
renderer->path = g_strdup (pinpoint_file);
renderer->ctx = cairo_create (renderer->surface);
@@ -95,17 +99,18 @@ cairo_renderer_init (PinPointRenderer *pp_renderer,
static cairo_surface_t *
_cairo_new_surface_from_pixbuf (const GdkPixbuf *pixbuf)
{
- gint width = gdk_pixbuf_get_width (pixbuf);
- gint height = gdk_pixbuf_get_height (pixbuf);
- guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
- int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
- int cairo_stride;
- guchar *cairo_pixels;
- cairo_format_t format;
+ int width = gdk_pixbuf_get_width (pixbuf);
+ int height = gdk_pixbuf_get_height (pixbuf);
+ guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
+ int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ int cairo_stride;
+ guchar *cairo_pixels;
+
+ cairo_format_t format;
cairo_surface_t *surface;
- static const cairo_user_data_key_t key;
- int j;
+ static const cairo_user_data_key_t key;
+ int j;
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
@@ -127,56 +132,55 @@ _cairo_new_surface_from_pixbuf (const GdkPixbuf *pixbuf)
guchar *q = cairo_pixels;
if (n_channels == 3)
- {
- guchar *end = p + 3 * width;
+ {
+ guchar *end = p + 3 * width;
- while (p < end)
- {
+ while (p < end)
+ {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- q[0] = p[2];
- q[1] = p[1];
- q[2] = p[0];
+ q[0] = p[2];
+ q[1] = p[1];
+ q[2] = p[0];
#else
- q[1] = p[0];
- q[2] = p[1];
- q[3] = p[2];
+ q[1] = p[0];
+ q[2] = p[1];
+ q[3] = p[2];
#endif
- p += 3;
- q += 4;
- }
- }
+ p += 3;
+ q += 4;
+ }
+ }
else
- {
- guchar *end = p + 4 * width;
- guint t1,t2,t3;
+ {
+ guchar *end = p + 4 * width;
+ guint t1,t2,t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
- while (p < end)
- {
+ while (p < end)
+ {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- MULT(q[0], p[2], p[3], t1);
- MULT(q[1], p[1], p[3], t2);
- MULT(q[2], p[0], p[3], t3);
- q[3] = p[3];
+ MULT(q[0], p[2], p[3], t1);
+ MULT(q[1], p[1], p[3], t2);
+ MULT(q[2], p[0], p[3], t3);
+ q[3] = p[3];
#else
- q[0] = p[3];
- MULT(q[1], p[0], p[3], t1);
- MULT(q[2], p[1], p[3], t2);
- MULT(q[3], p[2], p[3], t3);
+ q[0] = p[3];
+ MULT(q[1], p[0], p[3], t1);
+ MULT(q[2], p[1], p[3], t2);
+ MULT(q[3], p[2], p[3], t3);
#endif
- p += 4;
- q += 4;
- }
+ p += 4;
+ q += 4;
+ }
#undef MULT
- }
+ }
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_stride;
}
-
return surface;
}
@@ -208,8 +212,8 @@ _cairo_get_surface (CairoRenderer *renderer,
const char *file)
{
cairo_surface_t *surface;
- GdkPixbuf *pixbuf;
- GError *error = NULL;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
surface = g_hash_table_lookup (renderer->surfaces, file);
if (surface)
@@ -234,7 +238,7 @@ _cairo_get_surface (CairoRenderer *renderer,
if (g_str_has_suffix (file, ".jpg") || g_str_has_suffix (file, ".jpeg"))
{
unsigned char *data = NULL;
- guint len;
+ guint len = 0;
_cairo_read_file (file, &data, &len);
cairo_surface_set_mime_data (surface, CAIRO_MIME_TYPE_JPEG,
@@ -252,7 +256,7 @@ _cairo_get_svg (CairoRenderer *renderer,
const char *file)
{
RsvgHandle *svg;
- GError *error = NULL;
+ GError *error = NULL;
svg = g_hash_table_lookup (renderer->svgs, file);
if (svg)
@@ -281,12 +285,21 @@ static void
_cairo_render_background (CairoRenderer *renderer,
PinPointPoint *point)
{
- gchar *full_path = NULL;
- const gchar *file = point->bg;
+ char *full_path = NULL;
+ const char *file;
+
+ if (point == NULL)
+ {
+ cairo_set_source_rgb (renderer->ctx, 0,0,0);
+ cairo_paint (renderer->ctx);
+ return;
+ }
+
+ file = point->bg;
if (point->bg_type != PP_BG_COLOR && renderer->path && file)
{
- gchar *dir = g_path_get_dirname (renderer->path);
+ char *dir = g_path_get_dirname (renderer->path);
full_path = g_build_filename (dir, file, NULL);
g_free (dir);
@@ -335,7 +348,7 @@ _cairo_render_background (CairoRenderer *renderer,
bg_height = cairo_image_surface_get_height (surface);
pp_get_background_position_scale (point,
- A4_LS_WIDTH, A4_LS_HEIGHT,
+ renderer->width, renderer->height,
bg_width, bg_height,
&bg_x, &bg_y,
&bg_scale_x, &bg_scale_y);
@@ -351,14 +364,24 @@ _cairo_render_background (CairoRenderer *renderer,
case PP_BG_VIDEO:
{
#ifdef USE_CLUTTER_GST
- GdkPixbuf *pixbuf;
+ GdkPixbuf *pixbuf;
cairo_surface_t *surface;
float bg_x, bg_y, bg_width, bg_height, bg_scale_x, bg_scale_y;
GCancellable* cancellable = g_cancellable_new ();
+ GFile *abs_file;
+ gchar *abs_path;
- pixbuf = gst_video_thumbnailer_get_shot (file, cancellable);
+ abs_file = g_file_resolve_relative_path (pp_basedir, point->bg);
+ abs_path = g_file_get_path (abs_file);
+ g_object_unref (abs_file);
+
+ pixbuf = gst_video_thumbnailer_get_shot (abs_path, cancellable);
+ g_free (abs_path);
if (pixbuf == NULL)
- break;
+ {
+ g_warning ("Could not create video thumbmail for %s", point->bg);
+ break;
+ }
surface = _cairo_new_surface_from_pixbuf (pixbuf);
g_hash_table_insert (renderer->surfaces, g_strdup (file), surface);
@@ -367,7 +390,7 @@ _cairo_render_background (CairoRenderer *renderer,
bg_height = cairo_image_surface_get_height (surface);
pp_get_background_position_scale (point,
- A4_LS_WIDTH, A4_LS_HEIGHT,
+ renderer->width, A4_LS_HEIGHT,
bg_width, bg_height,
&bg_x, &bg_y,
&bg_scale_x, &bg_scale_y);
@@ -394,7 +417,7 @@ _cairo_render_background (CairoRenderer *renderer,
rsvg_handle_get_dimensions (svg, &dim);
pp_get_background_position_scale (point,
- A4_LS_WIDTH, A4_LS_HEIGHT,
+ renderer->width, renderer->height,
dim.width, dim.height,
&bg_x, &bg_y,
&bg_scale_x, &bg_scale_y);
@@ -408,6 +431,9 @@ _cairo_render_background (CairoRenderer *renderer,
}
#endif
break;
+ case PP_BG_CAMERA:
+ /* silently ignore camera backgrounds */
+ break;
default:
g_assert_not_reached();
}
@@ -419,13 +445,16 @@ static void
_cairo_render_text (CairoRenderer *renderer,
PinPointPoint *point)
{
- PangoLayout *layout;
+ PangoLayout *layout;
PangoFontDescription *desc;
- PangoRectangle logical_rect = { 0, };
- ClutterColor text_color, shading_color;
+ PangoRectangle logical_rect = { 0, };
+ ClutterColor text_color,
+ shading_color;
- float text_width, text_height, text_x, text_y, text_scale;
+ float text_x, text_y, text_width, text_height, text_scale;
float shading_x, shading_y, shading_width, shading_height;
+ if (point == NULL)
+ return;
layout = pango_cairo_create_layout (renderer->ctx);
desc = pango_font_description_from_string (point->font);
@@ -443,12 +472,12 @@ _cairo_render_text (CairoRenderer *renderer,
goto out;
pp_get_text_position_scale (point,
- A4_LS_WIDTH, A4_LS_HEIGHT,
+ renderer->width, renderer->height,
text_width, text_height,
&text_x, &text_y,
&text_scale);
- pp_get_shading_position_size (A4_LS_HEIGHT, A4_LS_WIDTH,
+ pp_get_shading_position_size (renderer->height, renderer->width, /* XXX: is this right order?? */
text_x, text_y,
text_width, text_height,
text_scale,
@@ -483,9 +512,9 @@ out:
g_object_unref (layout);
}
-static void
-_cairo_render_page (CairoRenderer *renderer,
- PinPointPoint *point)
+void
+cairo_renderer_render_page (CairoRenderer *renderer,
+ PinPointPoint *point)
{
_cairo_render_background (renderer, point);
_cairo_render_text (renderer, point);
@@ -496,10 +525,10 @@ static void
cairo_renderer_run (PinPointRenderer *pp_renderer)
{
CairoRenderer *renderer = CAIRO_RENDERER (pp_renderer);
- GList *cur;
+ GList *cur;
for (cur = pp_slides; cur; cur = g_list_next (cur))
- _cairo_render_page (renderer, cur->data);
+ cairo_renderer_render_page (renderer, cur->data);
}
static void
@@ -508,12 +537,15 @@ cairo_renderer_finalize (PinPointRenderer *pp_renderer)
CairoRenderer *renderer = CAIRO_RENDERER (pp_renderer);
g_free (renderer->path);
- cairo_surface_destroy (renderer->surface);
+ if (renderer->surface)
+ cairo_surface_destroy (renderer->surface);
g_hash_table_unref (renderer->surfaces);
g_hash_table_unref (renderer->svgs);
- cairo_destroy (renderer->ctx);
+ if (renderer->ctx)
+ cairo_destroy (renderer->ctx);
}
+
static gboolean
cairo_renderer_make_point (PinPointRenderer *pp_renderer,
PinPointPoint *point)
@@ -524,12 +556,41 @@ cairo_renderer_make_point (PinPointRenderer *pp_renderer,
{
ClutterColor color;
- ret = clutter_color_from_string (&color, point->bg);
+ ret = clutter_color_from_string (&color, point->bg); /* this roughly checks that the color is valid? */
}
return ret;
}
+void
+cairo_renderer_unset_cr (PinPointRenderer *pp_renderer)
+{
+ CairoRenderer *renderer = CAIRO_RENDERER (pp_renderer);
+ renderer->ctx = NULL;
+}
+
+void
+cairo_renderer_set_cr (PinPointRenderer *pp_renderer,
+ cairo_t *ctx,
+ float width,
+ float height)
+{
+ CairoRenderer *renderer = CAIRO_RENDERER (pp_renderer);
+ if (renderer->ctx)
+ {
+ if (renderer->surface)
+ {
+ cairo_surface_destroy (renderer->surface);
+ renderer->surface = NULL;
+ }
+ cairo_destroy (renderer->ctx);
+ renderer->ctx = NULL;
+ }
+ renderer->ctx = ctx;
+ renderer->width = width;
+ renderer->height = height;
+}
+
static void *
cairo_renderer_allocate_data (PinPointRenderer *renderer)
{
diff --git a/pp-clutter.c b/pp-clutter.c
index 7051d96..08ed901 100644
--- a/pp-clutter.c
+++ b/pp-clutter.c
@@ -21,8 +21,15 @@
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "pinpoint.h"
+
+#if HAVE_CLUTTER_X11
#include <clutter/x11/clutter-x11.h>
+#endif
#include <gio/gio.h>
#ifdef USE_CLUTTER_GST
#include <clutter-gst/clutter-gst.h>
@@ -33,6 +40,17 @@
#endif
#include <stdlib.h>
+
+void cairo_renderer_unset_cr (PinPointRenderer *pp_renderer);
+
+void cairo_renderer_set_cr (PinPointRenderer *pp_renderer,
+ cairo_t *ctx,
+ float width,
+ float height);
+
+void cairo_renderer_render_page (void *renderer,
+ PinPointPoint *point);
+
/* #define QUICK_ACCESS_LEFT - uncomment to move speed access from top to left,
* useful on meego netbook
*/
@@ -41,13 +59,37 @@
#define RESTX 4600.0
#define STARTPOS -3000.0
+/* The maximum of these is used, either 80% of the slide time
+ or 20seconds left of the slide
+ */
+#define SLIDE_WARN_TIME 2.0
+#define SLIDE_WARN_THRESHOLD 0.33
+#define OPACITY_OK 0
+#define OPACITY_PAST_THRESHOLD 96
+#define OPACITY_OVER_TIME 140
+
+#define PREVIEW_WIDTH 640
+#define PREVIEW_HEIGHT 480
+
+static ClutterColor c_prog_bg = {0x11,0x11,0x11,0xff};
+static ClutterColor c_prog_slide = {0xff,0xff,0xff,0x77};
+static ClutterColor c_prog_time = {0xff,0xff,0xff,0x55};
+
static ClutterColor black = {0x00,0x00,0x00,0xff};
+static ClutterColor white = {0xff,0xff,0xff,0xff};
+static ClutterColor red = {0xff,0x00,0x00,0xff};
+
+#ifdef HAVE_PDF
+PinPointRenderer *pp_cairo_renderer (void);
+#endif
typedef struct _ClutterRenderer
{
PinPointRenderer renderer;
GHashTable *bg_cache; /* only load the same backgrounds once */
ClutterActor *stage;
+ ClutterActor *root;
+
ClutterActor *background;
ClutterActor *midground;
ClutterActor *shading;
@@ -55,10 +97,48 @@ typedef struct _ClutterRenderer
ClutterActor *json_layer;
- ClutterActor *commandline;
+ ClutterActor *commandline;
ClutterActor *commandline_shading;
+
+ GTimer *timer;
+ gboolean timer_paused;
+ int total_seconds;
+ gboolean autoadvance;
+
+ gboolean speaker_mode;
+ ClutterActor *speaker_screen;
+
+ gdouble slide_start_time;
+
+ ClutterActor *speaker_buttons_group;
+ ClutterActor *speaker_speakerscreen;
+ ClutterActor *speaker_rehearse;
+ ClutterActor *speaker_autoadvance;
+ ClutterActor *speaker_start;
+ ClutterActor *speaker_pause;
+ ClutterActor *speaker_fullscreen;
+
+ ClutterActor *speaker_notes;
+ ClutterActor *speaker_prev;
+ ClutterActor *speaker_current;
+ ClutterActor *speaker_next;
+
+ ClutterActor *speaker_slide_prog_warning;
+
+ ClutterActor *speaker_prog_bg;
+ ClutterActor *speaker_prog_slide;
+ ClutterActor *speaker_prog_time;
+
+ ClutterActor *speaker_time_remaining;
+
char *path; /* path of the file of the GFileMonitor callback */
float rest_y; /* where the text can rest */
+
+ gboolean reset; /* tells the speaker screen update function to
+ reset all state
+ */
+
+ PinPointRenderer *cairo_renderer;
} ClutterRenderer;
typedef struct
@@ -75,6 +155,10 @@ typedef struct
ClutterActor *midground;
ClutterActor *foreground;
ClutterActor *shading;
+
+#ifdef USE_CLUTTER_GST
+ GstElement *pipeline; /* used for the custom camera pipeline */
+#endif
} ClutterPointData;
#define CLUTTER_RENDERER(renderer) ((ClutterRenderer *) renderer)
@@ -94,16 +178,46 @@ static void file_changed (GFileMonitor *monitor,
static void stage_resized (ClutterActor *actor,
GParamSpec *pspec,
ClutterRenderer *renderer);
-static gboolean key_pressed (ClutterActor *actor,
- ClutterEvent *event,
- ClutterRenderer *renderer);
+static gboolean key_pressed (ClutterActor *actor,
+ ClutterEvent *event,
+ ClutterRenderer *renderer);
+
+static void
+pp_clutter_render_adjust_background (ClutterRenderer *renderer,
+ PinPointPoint *point)
+{
+ float bg_x, bg_y, bg_width, bg_height, bg_scale_x, bg_scale_y;
+ ClutterPointData *data = point->data;
+
+ if (!data)
+ return;
+
+ if (CLUTTER_IS_RECTANGLE (data->background))
+ {
+ clutter_actor_get_size (renderer->stage, &bg_width, &bg_height);
+ clutter_actor_set_size (data->background, bg_width, bg_height);
+ }
+ else
+ {
+ clutter_actor_get_size (data->background, &bg_width, &bg_height);
+ }
+
+ pp_get_background_position_scale (point,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage),
+ bg_width, bg_height,
+ &bg_x, &bg_y, &bg_scale_x, &bg_scale_y);
+ clutter_actor_set_scale (data->background, bg_scale_x, bg_scale_y);
+ clutter_actor_set_position (data->background, bg_x, bg_y);
+}
+#ifdef HAVE_CLUTTER_X11
static void pp_set_fullscreen (ClutterStage *stage,
gboolean fullscreen)
{
static gboolean is_fullscreen = FALSE;
- static gfloat old_width=640, old_height=480;
+ static float old_width=640, old_height=480;
struct {
unsigned long flags;
@@ -129,7 +243,9 @@ static void pp_set_fullscreen (ClutterStage *stage,
if (fullscreen)
{
int full_width = DisplayWidth (xdisplay, xscreen);
- int full_height = DisplayHeight (xdisplay, xscreen)+5; /* avoid being detected as fullscreen */
+ int full_height = DisplayHeight (xdisplay, xscreen)+5;
+ /* avoid being detected as fullscreen, workaround for some
+ windowmanagers */
clutter_actor_get_size (CLUTTER_ACTOR (stage), &old_width, &old_height);
if (wm_hints != None)
@@ -158,6 +274,21 @@ static gboolean pp_get_fullscreen (ClutterStage *stage)
return clutter_stage_get_fullscreen (stage);
return pp_fullscreen;
}
+#else
+
+static void
+pp_set_fullscreen (ClutterStage *stage,
+ gboolean fullscreen)
+{
+ return clutter_stage_set_fullscreen (stage, fullscreen);
+}
+
+static gboolean
+pp_get_fullscreen (ClutterStage *stage)
+{
+ return clutter_stage_get_fullscreen (stage);
+}
+#endif
static void
_destroy_surface (gpointer data)
@@ -167,7 +298,7 @@ _destroy_surface (gpointer data)
*/
}
-static uint hide_cursor = 0;
+static guint hide_cursor = 0;
static gboolean hide_cursor_cb (gpointer stage)
{
hide_cursor = 0;
@@ -181,23 +312,27 @@ static void
activate_commandline (ClutterRenderer *renderer)
{
PinPointPoint *point;
- ClutterPointData *data;
if (!pp_slidep)
return;
-
+
point = pp_slidep->data;
- data = point->data;
clutter_actor_animate (renderer->commandline,
CLUTTER_LINEAR, 500,
- "opacity", 0xff, NULL);
+ "opacity", 0xff,
+ NULL);
+
clutter_actor_animate (renderer->commandline_shading,
CLUTTER_LINEAR, 100,
- "opacity", (int)(point->shading_opacity*0xff*0.33), NULL);
+ "opacity", (int)(point->shading_opacity*0xff*0.33),
+ NULL);
- g_object_set (renderer->commandline, "editable", TRUE,
- "single-line-mode", TRUE, "activatable", TRUE, NULL);
+ g_object_set (renderer->commandline,
+ "editable", TRUE,
+ "single-line-mode", TRUE,
+ "activatable", TRUE,
+ NULL);
clutter_actor_grab_key_focus (renderer->commandline);
}
@@ -250,7 +385,8 @@ static void commandline_notify_cb (ClutterActor *actor,
gpointer data)
{
ClutterRenderer *renderer = CLUTTER_RENDERER (data);
- gfloat scale;
+ float scale;
+
scale = clutter_actor_get_width (renderer->stage) /
(clutter_actor_get_width (actor) / 0.9);
if (scale > 1.0)
@@ -262,7 +398,7 @@ static gboolean stage_motion (ClutterActor *actor,
ClutterEvent *event,
gpointer renderer)
{
- gfloat stage_width, stage_height;
+ float stage_width, stage_height;
if (hide_cursor)
g_source_remove (hide_cursor);
@@ -272,7 +408,8 @@ static gboolean stage_motion (ClutterActor *actor,
if (!pp_get_fullscreen (CLUTTER_STAGE (actor)))
return FALSE;
- clutter_actor_get_size (CLUTTER_RENDERER (renderer)->stage, &stage_width, &stage_height);
+ clutter_actor_get_size (CLUTTER_RENDERER (renderer)->stage,
+ &stage_width, &stage_height);
#ifdef QUICK_ACCESS_LEFT
if (event->motion.x < 8)
{
@@ -293,6 +430,345 @@ static gboolean stage_motion (ClutterActor *actor,
return FALSE;
}
+#define NORMAL_OPACITY 100
+#define HOVER_OPACITY 255
+
+static gboolean
+opacity_hover_enter (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 200,
+ "opacity", HOVER_OPACITY,
+ NULL);
+ return FALSE;
+}
+
+
+static gboolean
+opacity_hover_leave (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 200,
+ "opacity", NORMAL_OPACITY,
+ NULL);
+ return FALSE;
+}
+
+#define opacity_hover(o) \
+ clutter_actor_set_opacity (o, NORMAL_OPACITY); \
+ clutter_actor_set_reactive (o, TRUE); \
+ g_signal_connect (o, "enter-event", \
+ G_CALLBACK (opacity_hover_enter), NULL); \
+ g_signal_connect (o, "leave-event", \
+ G_CALLBACK (opacity_hover_leave), NULL); \
+
+static gboolean
+play_pause (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ ClutterRenderer *renderer = CLUTTER_RENDERER (data);
+ if (renderer->timer_paused)
+ {
+ g_timer_continue (renderer->timer);
+ renderer->timer_paused = FALSE;
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_pause), "pause");
+ }
+ else
+ {
+ g_timer_stop (renderer->timer);
+ renderer->timer_paused = TRUE;
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_pause), "go");
+ }
+ return TRUE;
+}
+
+static gboolean
+toggle_autoadvance (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ ClutterRenderer *renderer = CLUTTER_RENDERER (data);
+ if (renderer->autoadvance)
+ {
+ renderer->autoadvance = FALSE;
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_autoadvance),
+ "enable autoadvance");
+ }
+ else
+ {
+ renderer->autoadvance = TRUE;
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_autoadvance),
+ "disable autoadvance");
+ }
+ return TRUE;
+}
+
+static void end_of_presentation (ClutterRenderer *renderer);
+
+static void
+next_slide (ClutterRenderer *renderer)
+{
+ if (pp_slidep && pp_slidep->next)
+ {
+ leave_slide (renderer, FALSE);
+ pp_slidep = pp_slidep->next;
+ show_slide (renderer, FALSE);
+ }
+ else
+ {
+ end_of_presentation (renderer);
+ }
+}
+
+static void
+prev_slide (ClutterRenderer *renderer)
+{
+ if (pp_slidep && pp_slidep->prev)
+ {
+ leave_slide (renderer, TRUE);
+ pp_slidep = pp_slidep->prev;
+ show_slide (renderer, TRUE);
+ }
+}
+
+static gboolean
+go_prev (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ ClutterRenderer *renderer = CLUTTER_RENDERER (data);
+ prev_slide (renderer);
+ return TRUE;
+}
+
+static gboolean
+go_next (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ ClutterRenderer *renderer = CLUTTER_RENDERER (data);
+ next_slide (renderer);
+ return TRUE;
+}
+
+static gboolean
+start (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ ClutterRenderer *renderer = CLUTTER_RENDERER (data);
+ g_timer_stop (renderer->timer);
+ g_timer_start (renderer->timer);
+ renderer->timer_paused = FALSE;
+ leave_slide (renderer, TRUE);
+ pp_slidep = pp_slides;
+ play_pause (NULL, NULL, data);
+ play_pause (NULL, NULL, data);
+ if (pp_rehearse)
+ {
+ pp_rehearse = FALSE;
+ }
+ pp_rehearse_init (); /* zeroes out the new-time */
+ show_slide (renderer, TRUE);
+ renderer->reset = TRUE;
+ return TRUE;
+}
+
+static gboolean
+start_rehearse (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data)
+{
+ start (actor, event, data);
+ pp_rehearse = TRUE;
+ pp_rehearse_init ();
+
+ return FALSE;
+}
+
+
+static void toggle_speaker_screen (ClutterRenderer *renderer);
+
+static void
+clutter_renderer_init_speaker_screen (ClutterRenderer *renderer)
+{
+ renderer->speaker_screen = clutter_stage_new ();
+
+ renderer->speaker_notes = g_object_new (CLUTTER_TYPE_TEXT,
+ "x", 10.0,
+ "y", 20.0,
+ "font-name", "Sans 20px",
+ "color", &white,
+ NULL);
+
+ renderer->speaker_time_remaining = g_object_new (CLUTTER_TYPE_TEXT,
+ "x", 300.0,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", "Sans 24px",
+ "text", "-",
+ "color", &white,
+ NULL);
+
+ renderer->speaker_buttons_group = clutter_group_new ();
+
+#define BUTTON_FONT "Sans 20px"
+
+ renderer->speaker_speakerscreen = g_object_new (CLUTTER_TYPE_TEXT,
+ "x", 0.0,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "speaker",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+
+ renderer->speaker_rehearse = g_object_new (CLUTTER_TYPE_TEXT,
+ "x", 0.0,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "rehearse",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+ renderer->speaker_autoadvance = g_object_new (CLUTTER_TYPE_TEXT,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "enable autoadvance",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+ renderer->speaker_start = g_object_new (CLUTTER_TYPE_TEXT,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "(re)start",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+ renderer->speaker_pause = g_object_new (CLUTTER_TYPE_TEXT,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+
+ renderer->speaker_fullscreen = g_object_new (CLUTTER_TYPE_TEXT,
+ "x", 0.0,
+ "y", 0.0,
+ "opacity", NORMAL_OPACITY,
+ "font-name", BUTTON_FONT,
+ "text", "fullscreen",
+ "reactive", TRUE,
+ "color", &white,
+ NULL);
+
+ opacity_hover(renderer->speaker_speakerscreen);
+ opacity_hover(renderer->speaker_rehearse);
+
+ g_signal_connect (renderer->speaker_rehearse, "button-press-event",
+ G_CALLBACK (start_rehearse), renderer);
+
+ opacity_hover(renderer->speaker_autoadvance);
+
+ g_signal_connect (renderer->speaker_autoadvance, "button-press-event",
+ G_CALLBACK (toggle_autoadvance), renderer);
+
+ opacity_hover(renderer->speaker_start);
+
+ g_signal_connect (renderer->speaker_start, "button-press-event",
+ G_CALLBACK (start), renderer);
+
+ opacity_hover(renderer->speaker_pause);
+
+ g_signal_connect (renderer->speaker_pause, "button-press-event",
+ G_CALLBACK (play_pause), renderer);
+
+ opacity_hover(renderer->speaker_fullscreen);
+
+ clutter_container_add (CLUTTER_CONTAINER (renderer->speaker_buttons_group),
+ renderer->speaker_speakerscreen,
+ renderer->speaker_start,
+ renderer->speaker_pause,
+ renderer->speaker_autoadvance,
+ renderer->speaker_rehearse,
+ renderer->speaker_fullscreen,
+ NULL);
+
+ g_signal_connect (renderer->speaker_screen, "key-press-event",
+ G_CALLBACK (key_pressed), renderer);
+
+
+
+ renderer->timer_paused = TRUE;
+ renderer->timer = g_timer_new ();
+ g_timer_stop (renderer->timer);
+
+ renderer->speaker_prog_bg = clutter_rectangle_new_with_color (&c_prog_bg);
+ renderer->speaker_prog_time = clutter_rectangle_new_with_color (&c_prog_time);
+ renderer->speaker_prog_slide = clutter_rectangle_new_with_color (&c_prog_slide);
+ renderer->speaker_slide_prog_warning = clutter_rectangle_new_with_color (&red);
+
+ clutter_stage_set_color (CLUTTER_STAGE (renderer->speaker_screen), &black);
+ clutter_stage_set_color (CLUTTER_STAGE (renderer->speaker_screen), &black);
+ clutter_stage_set_user_resizable (CLUTTER_STAGE (renderer->speaker_screen), TRUE);
+
+ renderer->speaker_prev = clutter_cairo_texture_new (PREVIEW_WIDTH, PREVIEW_HEIGHT);
+ renderer->speaker_current = clutter_cairo_texture_new (PREVIEW_WIDTH, PREVIEW_HEIGHT);
+ renderer->speaker_next = clutter_cairo_texture_new (PREVIEW_WIDTH, PREVIEW_HEIGHT);
+
+ clutter_container_add (CLUTTER_CONTAINER (renderer->speaker_screen),
+
+ renderer->speaker_prev,
+ renderer->speaker_current,
+ renderer->speaker_next,
+ renderer->speaker_notes,
+ renderer->speaker_prog_bg,
+ renderer->speaker_slide_prog_warning,
+ renderer->speaker_prog_time,
+
+
+ renderer->speaker_prog_slide,
+
+
+ renderer->speaker_buttons_group,
+ renderer->speaker_time_remaining,
+ NULL);
+
+
+
+ clutter_actor_set_opacity (renderer->speaker_slide_prog_warning, 0);
+
+
+
+ opacity_hover(renderer->speaker_prev);
+ opacity_hover(renderer->speaker_next);
+
+ g_signal_connect (renderer->speaker_prev, "button-press-event",
+ G_CALLBACK (go_prev), renderer);
+ g_signal_connect (renderer->speaker_next, "button-press-event",
+ G_CALLBACK (go_next), renderer);
+
+}
+
+static gboolean
+stage_deleted (ClutterStage *stage,
+ ClutterEvent *event,
+ gpointer user_data)
+{
+ clutter_main_quit ();
+
+ return TRUE;
+}
+
static void
clutter_renderer_init (PinPointRenderer *pp_renderer,
char *pinpoint_file)
@@ -301,10 +777,9 @@ clutter_renderer_init (PinPointRenderer *pp_renderer,
GFileMonitor *monitor;
ClutterActor *stage;
+ renderer->stage = stage = clutter_stage_new ();
+ renderer->root = clutter_group_new ();
renderer->rest_y = STARTPOS;
-
- renderer->stage = stage = clutter_stage_get_default ();
-
renderer->background = clutter_group_new ();
renderer->midground = clutter_group_new ();
renderer->foreground = clutter_group_new ();
@@ -312,12 +787,18 @@ clutter_renderer_init (PinPointRenderer *pp_renderer,
renderer->shading = clutter_rectangle_new_with_color (&black);
renderer->commandline_shading = clutter_rectangle_new_with_color (&black);
renderer->commandline = clutter_text_new ();
+
clutter_actor_set_opacity (renderer->shading, 0x77);
clutter_actor_set_opacity (renderer->commandline_shading, 0x77);
clutter_container_add_actor (CLUTTER_CONTAINER (renderer->midground),
renderer->shading);
- clutter_container_add (CLUTTER_CONTAINER (stage),
+
+
+ clutter_container_add (CLUTTER_CONTAINER (renderer->stage),
+ renderer->root,
+ NULL);
+ clutter_container_add (CLUTTER_CONTAINER (renderer->root),
renderer->background,
renderer->midground,
renderer->foreground,
@@ -326,12 +807,32 @@ clutter_renderer_init (PinPointRenderer *pp_renderer,
renderer->commandline,
NULL);
+ renderer->timer_paused = FALSE;
+ renderer->timer = g_timer_new ();
+
+
+ if (pp_speakermode)
+ toggle_speaker_screen (renderer);
+
clutter_actor_show (stage);
+
+
clutter_stage_set_color (CLUTTER_STAGE (stage), &black);
+ g_signal_connect (stage, "delete-event",
+ G_CALLBACK (stage_deleted), renderer);
g_signal_connect (stage, "key-press-event",
G_CALLBACK (key_pressed), renderer);
g_signal_connect (stage, "notify::width",
G_CALLBACK (stage_resized), renderer);
+
+ if (renderer->speaker_screen)
+ {
+ g_signal_connect (renderer->speaker_screen, "notify::width",
+ G_CALLBACK (stage_resized), renderer);
+ g_signal_connect (renderer->speaker_screen, "notify::height",
+ G_CALLBACK (stage_resized), renderer);
+ }
+
g_signal_connect (stage, "notify::height",
G_CALLBACK (stage_resized), renderer);
g_signal_connect (stage, "motion-event",
@@ -359,12 +860,24 @@ clutter_renderer_init (PinPointRenderer *pp_renderer,
renderer->bg_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, _destroy_surface);
+
+ renderer->cairo_renderer = pp_cairo_renderer ();
+ renderer->cairo_renderer->init (renderer->cairo_renderer, "");
}
+static gboolean update_speaker_screen (ClutterRenderer *renderer);
+
static void
-clutter_renderer_run (PinPointRenderer *renderer)
+clutter_renderer_run (PinPointRenderer *pp_renderer)
{
- show_slide (CLUTTER_RENDERER (renderer), FALSE);
+ ClutterRenderer *renderer = CLUTTER_RENDERER (pp_renderer);
+
+ show_slide (renderer, FALSE);
+
+ /* the presentaiton is not parsed at first initialization,.. */
+ renderer->total_seconds = point_defaults->duration * 60;
+
+ g_timeout_add (15, (GSourceFunc)update_speaker_screen, renderer);
clutter_main ();
}
@@ -405,21 +918,136 @@ _clutter_get_texture (ClutterRenderer *renderer,
return clutter_clone_new (source);
}
+#if USE_CLUTTER_GST
+static void
+on_size_changed (ClutterActor *texture,
+ gint width,
+ gint height,
+ gpointer user_data)
+{
+ PinPointRenderer *pp_renderer = user_data;
+ ClutterRenderer *renderer = CLUTTER_RENDERER (pp_renderer);
+ PinPointPoint *point;
+ ClutterPointData *data;
+
+ point = pp_slidep->data;
+ if (!point)
+ return;
+
+ data = point->data;
+
+ if (data->background != texture)
+ {
+ g_warning ("size changed but not current background ?!");
+ return;
+ }
+
+ clutter_actor_set_size (texture, width, height);
+ pp_clutter_render_adjust_background (renderer, point);
+}
+
+static gboolean
+setup_camera (PinPointRenderer *renderer,
+ PinPointPoint *point)
+{
+ /* These are static to be able to share the texture and the pipeline between
+ * all the slides using the camera */
+ static ClutterActor *texture = NULL;
+ static GstElement *pipeline = NULL;
+
+ ClutterPointData *data = point->data;
+ GstElement *src;
+ GstElement *capsfilter;
+ GstElement *sink;
+ GstCaps *caps;
+ gboolean result;
+
+ if (texture)
+ {
+ data->background = clutter_clone_new (texture);
+ data->pipeline = pipeline;
+
+ return TRUE;
+ }
+
+ texture = g_object_new (CLUTTER_TYPE_TEXTURE, "disable-slicing", TRUE, NULL);
+
+ g_signal_connect (CLUTTER_TEXTURE (texture),
+ "size-change",
+ G_CALLBACK (on_size_changed), renderer);
+
+ /* Set up pipeline */
+ pipeline = gst_pipeline_new (NULL);
+
+ src = gst_element_factory_make ("v4l2src", NULL);
+ if (src == NULL)
+ {
+ g_critical ("Failed to create v4l2src element");
+ g_object_unref (pipeline);
+ return FALSE;
+ }
+
+ capsfilter = gst_element_factory_make ("capsfilter", NULL);
+ sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (texture));
+
+ /* make videotestsrc spit the format we want */
+ caps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
+
+ if (point->camera_framerate)
+ {
+ gst_caps_set_simple (caps,
+ "framerate", GST_TYPE_FRACTION,
+ point->camera_framerate, 1,
+ NULL);
+ }
+
+ if (pp_camera_device)
+ g_object_set (src, "device", pp_camera_device, NULL);
+
+#define W (point->camera_resolution.width)
+#define H (point->camera_resolution.height)
+ if (W != 0 && H != 0)
+ {
+ gst_caps_set_simple (caps,
+ "width", G_TYPE_INT, W,
+ "height", G_TYPE_INT, H,
+ NULL);
+ }
+#undef W
+#undef H
+
+ g_object_set (capsfilter, "caps", caps, NULL);
+
+ gst_bin_add_many (GST_BIN (pipeline), src, capsfilter, sink, NULL);
+ result = gst_element_link_many (src, capsfilter, sink, NULL);
+ if (result == FALSE)
+ {
+ g_critical("Could not link elements");
+ gst_object_unref (pipeline);
+ return FALSE;
+ }
+
+ data->background = texture;
+ data->pipeline = pipeline;
+
+ return TRUE;
+}
+#endif
static gboolean
clutter_renderer_make_point (PinPointRenderer *pp_renderer,
PinPointPoint *point)
{
- ClutterRenderer *renderer = CLUTTER_RENDERER (pp_renderer);
- ClutterPointData *data = point->data;
- const gchar *file = point->bg;
- gchar *full_path = NULL;
+ ClutterRenderer *renderer = CLUTTER_RENDERER (pp_renderer);
+ ClutterPointData *data = point->data;
+ const char *file = point->bg;
+ char *full_path = NULL;
ClutterColor color;
- gboolean ret;
+ gboolean ret = FALSE;
if (point->bg_type != PP_BG_COLOR && renderer->path && file)
{
- gchar *dir = g_path_get_dirname (renderer->path);
+ char *dir = g_path_get_dirname (renderer->path);
full_path = g_build_filename (dir, file, NULL);
g_free (dir);
@@ -433,8 +1061,8 @@ clutter_renderer_make_point (PinPointRenderer *pp_renderer,
ret = clutter_color_from_string (&color, point->bg);
if (ret)
data->background = g_object_new (CLUTTER_TYPE_RECTANGLE,
- "color", &color,
- "width", 100.0,
+ "color", &color,
+ "width", 100.0,
"height", 100.0,
NULL);
}
@@ -447,11 +1075,17 @@ clutter_renderer_make_point (PinPointRenderer *pp_renderer,
#ifdef USE_CLUTTER_GST
data->background = clutter_gst_video_texture_new ();
clutter_media_set_filename (CLUTTER_MEDIA (data->background), file);
- /* should pre-roll the video and set the size */
- clutter_actor_set_size (data->background, 400, 300);
+ g_signal_connect (CLUTTER_TEXTURE (data->background),
+ "size-change",
+ G_CALLBACK (on_size_changed), renderer);
ret = TRUE;
#endif
break;
+ case PP_BG_CAMERA:
+#ifdef USE_CLUTTER_GST
+ ret = setup_camera (pp_renderer, point);
+#endif
+ break;
case PP_BG_SVG:
#ifdef USE_DAX
{
@@ -495,20 +1129,20 @@ clutter_renderer_make_point (PinPointRenderer *pp_renderer,
if (point->use_markup)
{
data->text = g_object_new (CLUTTER_TYPE_TEXT,
- "font-name", point->font,
- "text", point->text,
+ "font-name", point->font,
+ "text", point->text,
"line-alignment", point->text_align,
- "color", &color,
- "use-markup", TRUE,
+ "color", &color,
+ "use-markup", TRUE,
NULL);
}
else
{
data->text = g_object_new (CLUTTER_TYPE_TEXT,
- "font-name", point->font,
- "text", point->text,
+ "font-name", point->font,
+ "text", point->text,
"line-alignment", point->text_align,
- "color", &color,
+ "color", &color,
NULL);
}
@@ -548,7 +1182,34 @@ clutter_renderer_free_data (PinPointRenderer *renderer,
g_slice_free (ClutterPointData, data);
}
+static void end_of_presentation (ClutterRenderer *renderer)
+{
+ if (pp_rehearse)
+ {
+ pp_rehearse_done ();
+ }
+ pp_rehearse = FALSE;
+ if (renderer->autoadvance)
+ toggle_autoadvance (NULL, NULL, renderer);
+}
+
+static void
+toggle_speaker_screen (ClutterRenderer *renderer)
+{
+ if (!renderer->speaker_screen)
+ clutter_renderer_init_speaker_screen (renderer);
+ if (renderer->speaker_mode)
+ {
+ renderer->speaker_mode = FALSE;
+ clutter_actor_hide (renderer->speaker_screen);
+ }
+ else
+ {
+ renderer->speaker_mode = TRUE;
+ clutter_actor_show (renderer->speaker_screen);
+ }
+}
static gboolean
key_pressed (ClutterActor *actor,
@@ -560,39 +1221,46 @@ key_pressed (ClutterActor *actor,
{
case CLUTTER_Left:
case CLUTTER_Up:
- if (pp_slidep && pp_slidep->prev)
- {
- leave_slide (renderer, TRUE);
- pp_slidep = pp_slidep->prev;
- show_slide (renderer, TRUE);
- }
- break;
case CLUTTER_BackSpace:
case CLUTTER_Prior:
- if (pp_slidep && pp_slidep->prev)
- {
- leave_slide (renderer, TRUE);
- pp_slidep = pp_slidep->prev;
- show_slide (renderer, TRUE);
- }
+ prev_slide (renderer);
break;
case CLUTTER_Right:
case CLUTTER_space:
case CLUTTER_Next:
case CLUTTER_Down:
- if (pp_slidep && pp_slidep->next)
- {
- leave_slide (renderer, FALSE);
- pp_slidep = pp_slidep->next;
- show_slide (renderer, FALSE);
- }
+ next_slide (renderer);
break;
case CLUTTER_Escape:
clutter_main_quit ();
break;
+ case CLUTTER_F1:
+ {
+ gboolean was_fullscreen = pp_get_fullscreen (
+ CLUTTER_STAGE (renderer->stage));
+ toggle_speaker_screen (renderer);
+ if (renderer->speaker_mode && renderer->speaker_screen)
+ pp_set_fullscreen (CLUTTER_STAGE (renderer->speaker_screen),
+ was_fullscreen);
+ }
+ break;
+ case CLUTTER_F2:
+ if (renderer->autoadvance)
+ renderer->autoadvance = FALSE;
+ else
+ renderer->autoadvance = TRUE;
+ break;
case CLUTTER_F11:
- pp_set_fullscreen (CLUTTER_STAGE (renderer->stage),
- !pp_get_fullscreen (CLUTTER_STAGE (renderer->stage)));
+ case CLUTTER_F:
+ case CLUTTER_f:
+ {
+ gboolean was_fullscreen = pp_get_fullscreen (
+ CLUTTER_STAGE (renderer->stage));
+ pp_set_fullscreen (CLUTTER_STAGE (renderer->stage), !was_fullscreen);
+ if (renderer->speaker_mode && renderer->speaker_screen)
+ pp_set_fullscreen (CLUTTER_STAGE (renderer->speaker_screen),
+ !was_fullscreen);
+ }
break;
case CLUTTER_Return:
action_slide (renderer);
@@ -604,48 +1272,31 @@ key_pressed (ClutterActor *actor,
return TRUE;
}
-
static void leave_slide (ClutterRenderer *renderer,
gboolean backwards)
{
PinPointPoint *point = pp_slidep->data;
ClutterPointData *data = point->data;
+ point->new_duration += g_timer_elapsed (renderer->timer, NULL) -
+ renderer->slide_start_time;
+
if (!point->transition)
{
clutter_actor_animate (data->text,
CLUTTER_LINEAR, 2000,
- "depth", RESTDEPTH,
- "scale-x", 1.0,
- "scale-y", 1.0,
- "x", RESTX,
- "y", data->rest_y,
+ "depth", RESTDEPTH,
+ "scale-x", 1.0,
+ "scale-y", 1.0,
+ "x", RESTX,
+ "y", data->rest_y,
NULL);
if (data->background)
{
clutter_actor_animate (data->background,
CLUTTER_LINEAR, 1000,
- "opacity", 0x0,
+ "opacity", 0x0,
NULL);
-#ifdef USE_CLUTTER_GST
- if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
- {
- clutter_media_set_playing (CLUTTER_MEDIA (data->background), FALSE);
- }
-#endif
-#ifdef USE_DAX
- if (DAX_IS_ACTOR (data->background))
- {
- dax_actor_set_playing (DAX_ACTOR (data->background), FALSE);
- }
- else if (PP_IS_SUPER_AA (data->background))
- {
- ClutterActor *actor;
-
- actor = mx_offscreen_get_child (MX_OFFSCREEN (data->background));
- dax_actor_set_playing (DAX_ACTOR (actor), FALSE);
- }
-#endif
}
}
else
@@ -654,17 +1305,45 @@ static void leave_slide (ClutterRenderer *renderer,
{
if (backwards)
clutter_state_set_state (data->state, "pre");
- else
+ else
clutter_state_set_state (data->state, "post");
}
}
+
+ if (data->background)
+ {
+#ifdef USE_CLUTTER_GST
+ if (point->bg_type == PP_BG_CAMERA)
+ {
+ gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
+ }
+ if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
+ {
+ clutter_media_set_playing (CLUTTER_MEDIA (data->background),
+ FALSE);
+ }
+#endif
+#ifdef USE_DAX
+ if (DAX_IS_ACTOR (data->background))
+ {
+ dax_actor_set_playing (DAX_ACTOR (data->background), FALSE);
+ }
+ else if (PP_IS_SUPER_AA (data->background))
+ {
+ ClutterActor *actor;
+
+ actor = mx_offscreen_get_child (MX_OFFSCREEN (data->background));
+ dax_actor_set_playing (DAX_ACTOR (actor), FALSE);
+ }
+#endif
+ }
}
static void state_completed (ClutterState *state, gpointer user_data)
{
- PinPointPoint *point = user_data;
- ClutterPointData *data = point->data;
- const gchar *new_state = clutter_state_get_state (state);
+ PinPointPoint *point = user_data;
+ ClutterPointData *data = point->data;
+ const char *new_state = clutter_state_get_state (state);
if (new_state == g_intern_static_string ("post") ||
new_state == g_intern_static_string ("pre"))
@@ -675,11 +1354,11 @@ static void state_completed (ClutterState *state, gpointer user_data)
clutter_actor_reparent (data->text, CLUTTER_RENDERER (data->renderer)->foreground);
g_object_set (data->text,
- "depth", RESTDEPTH,
+ "depth", RESTDEPTH,
"scale-x", 1.0,
"scale-y", 1.0,
- "x", RESTX,
- "y", data->rest_y,
+ "x", RESTX,
+ "y", data->rest_y,
NULL);
clutter_actor_set_opacity (data->background, 0);
}
@@ -689,13 +1368,13 @@ static void state_completed (ClutterState *state, gpointer user_data)
static void
action_slide (ClutterRenderer *renderer)
{
- PinPointPoint *point;
+ PinPointPoint *point;
ClutterPointData *data;
- const char *command = NULL;
+ const char *command = NULL;
if (!pp_slidep)
return;
-
+
point = pp_slidep->data;
data = point->data;
@@ -712,13 +1391,14 @@ action_slide (ClutterRenderer *renderer)
}
}
-static gchar *pp_lookup_transition (const gchar *transition)
+static char *pp_lookup_transition (const char *transition)
{
- int i;
- gchar *dirs[] ={ "", "./transitions/", PKGDATADIR, NULL};
+ int i;
+ char *dirs[] ={ "", "./transitions/", PKGDATADIR, NULL};
+
for (i = 0; dirs[i]; i++)
{
- gchar *path = g_strdup_printf ("%s%s.json", dirs[i], transition);
+ char *path = g_strdup_printf ("%s%s.json", dirs[i], transition);
if (g_file_test (path, G_FILE_TEST_EXISTS))
return path;
g_free (path);
@@ -726,50 +1406,374 @@ static gchar *pp_lookup_transition (const gchar *transition)
return NULL;
}
-
static void update_commandline_shading (ClutterRenderer *renderer)
{
- ClutterColor color;
- float text_x, text_y, text_width, text_height;
- float shading_x, shading_y, shading_width, shading_height;
- const char *command;
- PinPointPoint *point;
- point = pp_slidep->data;
- clutter_actor_get_size (renderer->commandline, &text_width, &text_height);
- clutter_actor_get_position (renderer->commandline, &text_x, &text_y);
- pp_get_shading_position_size (clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage),
- text_x, text_y,
- text_width, text_height,
- 1.0,
- &shading_x, &shading_y,
- &shading_width, &shading_height);
-
- clutter_color_from_string (&color, point->shading_color);
- g_object_set (renderer->commandline_shading,
- "x", shading_x,
- "y", shading_y,
- NULL);
- command = clutter_text_get_text (CLUTTER_TEXT (renderer->commandline));
- clutter_actor_animate (renderer->commandline_shading,
- CLUTTER_EASE_OUT_QUINT, 1000,
- "opacity", command && *command?(int)(point->shading_opacity*255*0.33):0,
- "color", &color,
- "width", shading_width,
- "height", shading_height,
- NULL);
+ PinPointPoint *point;
+ ClutterColor color;
+ const char *command;
+
+ float text_x, text_y, text_width, text_height;
+ float shading_x, shading_y, shading_width, shading_height;
+
+ point = pp_slidep->data;
+ clutter_actor_get_size (renderer->commandline, &text_width, &text_height);
+ clutter_actor_get_position (renderer->commandline, &text_x, &text_y);
+ pp_get_shading_position_size (clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage),
+ text_x, text_y,
+ text_width, text_height,
+ 1.0,
+ &shading_x, &shading_y,
+ &shading_width, &shading_height);
+
+ clutter_color_from_string (&color, point->shading_color);
+ g_object_set (renderer->commandline_shading,
+ "x", shading_x,
+ "y", shading_y,
+ NULL);
+ command = clutter_text_get_text (CLUTTER_TEXT (renderer->commandline));
+
+ clutter_actor_animate (renderer->commandline_shading,
+ CLUTTER_EASE_OUT_QUINT, 1000,
+
+ /* the opacity of the commandline shading depends on whether we
+ have a command or not */
+ "opacity", command && *command?(int)(point->shading_opacity*255*0.33):0,
+ "color", &color,
+ "width", shading_width,
+ "height", shading_height,
+ NULL);
+}
+
+static gfloat point_time (ClutterRenderer *renderer,
+ PinPointPoint *point)
+{
+ GList *iter;
+ float time;
+ gboolean after_current = FALSE;
+
+ for (iter = pp_slides; iter && iter->data != point; iter = iter->next)
+ {
+ if (iter == pp_slidep)
+ after_current = TRUE;
+ }
+
+ time = point->duration != 0.0 ? point->duration : 2.0;
+ /* if before current point, use new time.. if at or after current point
+ use historic time
+ */
+ if (!after_current)
+ if (point->new_duration != 0.0)
+ time = point->new_duration;
+ return time;
+}
+
+static gfloat total_time (ClutterRenderer *renderer,
+ GList *start)
+{
+ GList *iter;
+ gfloat total = 0;
+ if (!start)
+ start = pp_slides;
+ for (iter = start; iter; iter = iter->next)
+ {
+ total += point_time (renderer, iter->data);
+ }
+ return total;
+}
+
+static gfloat slide_rel_duration (ClutterRenderer *renderer,
+ GList *slide)
+{
+ return point_time (renderer, slide->data) / total_time (renderer, pp_slides);
+}
+
+static gfloat slide_rel_start (ClutterRenderer *renderer,
+ GList *slide)
+{
+ GList *iter;
+ float time = 0;
+
+ for (iter = slide ->prev; iter; iter = iter->prev)
+ {
+ time += point_time (renderer, iter->data);
+ }
+
+ time = time / total_time (renderer, pp_slides);
+ return time;
+}
+
+static gfloat slide_time (ClutterRenderer *renderer,
+ GList *slide)
+{
+ float time = point_time (renderer, slide->data) /
+ total_time (renderer, slide);
+ float remaining_time = renderer->total_seconds -
+ g_timer_elapsed (renderer->timer, NULL);
+ time *= remaining_time;
+ return time;
+}
+
+
+static gboolean update_speaker_screen (ClutterRenderer *renderer)
+{
+ PinPointPoint *point;
+
+ if (!pp_slidep)
+ return FALSE;
+
+ point = pp_slidep->data;
+ static float current_slide_time = 0.0;
+ static float current_slide_duration = 0.0;
+ static GList *current_slide = NULL;
+ float nh, nw;
+
+ if (renderer->reset)
+ {
+ current_slide = NULL;
+ current_slide_duration = 0.0;
+ current_slide_time = 0.0;
+ renderer->reset = FALSE;
+ }
+
+ {
+ static float current_slide_prev_time = 0.0;
+ float warn_time = SLIDE_WARN_TIME;
+ float diff = g_timer_elapsed (renderer->timer, NULL) - current_slide_prev_time;
+
+ if (current_slide != pp_slidep)
+ {
+ current_slide_time = 0;
+ current_slide = pp_slidep;
+ current_slide_duration = slide_time (renderer, pp_slidep);
+ }
+
+ /* if 33% of the slide is longer than the seconds based threshold, use
+ the percentage
+ */
+ if ((warn_time <= current_slide_duration * SLIDE_WARN_THRESHOLD))
+ warn_time = current_slide_duration * SLIDE_WARN_THRESHOLD;
+
+ current_slide_time += diff;
+ if (current_slide_time >= current_slide_duration)
+ {
+ if (renderer->autoadvance)
+ {
+ current_slide_time = 0;
+ next_slide (renderer);
+ }
+
+
+ if (renderer->speaker_slide_prog_warning)
+ clutter_actor_animate (renderer->speaker_slide_prog_warning,
+ CLUTTER_LINEAR, 500,
+ "opacity", OPACITY_OVER_TIME,
+ NULL);
+ }
+
+
+ else if ((current_slide_duration - current_slide_time < warn_time))
+ {
+ if (renderer->speaker_slide_prog_warning)
+ clutter_actor_animate (renderer->speaker_slide_prog_warning,
+ CLUTTER_LINEAR, 500,
+ "opacity", OPACITY_PAST_THRESHOLD,
+ NULL);
+ }
+ else
+ {
+ if (renderer->speaker_slide_prog_warning)
+ clutter_actor_animate (renderer->speaker_slide_prog_warning,
+ CLUTTER_LINEAR, 50,
+ "opacity", OPACITY_OK,
+ NULL);
+ }
+
+ current_slide_prev_time = g_timer_elapsed (renderer->timer, NULL);
+ }
+
+ if (!renderer->speaker_mode)
+ return TRUE;
+
+ if (point->speaker_notes)
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_notes),
+ point->speaker_notes);
+ else
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_notes), "");
+
+ nw = clutter_actor_get_width (renderer->speaker_screen) + 1;
+ nh = clutter_actor_get_height (renderer->speaker_screen);
+
+ { /* should draw rectangles representing progress instead... */
+ GString *str = g_string_new ("");
+ int i;
+ GList *iter;
+ for (iter = pp_slides, i=0; iter && iter != pp_slidep;
+ iter = iter->next, i++);
+
+ {
+ int time;
+ time = renderer->total_seconds -
+ g_timer_elapsed (renderer->timer, NULL) + 0.5;
+
+ if (time <= -60)
+ g_string_printf (str, "%imin", time/60);
+ else if (time <= 10)
+ g_string_printf (str, "%is", time);
+ else if (time <= 60)
+ {
+ time = ((time + 4)/ 5) * 5;
+ g_string_printf (str, "%is", time);
+ }
+ else
+ g_string_printf (str, "%i%smin", time / 60, (time % 60 > 30) ? "½":"");
+
+ clutter_text_set_text (CLUTTER_TEXT (renderer->speaker_time_remaining),
+ str->str);
+ }
+ g_string_free (str, TRUE);
+ }
+
+ {
+#define append_ltr(a,b) \
+ clutter_actor_set_x (b, clutter_actor_get_x (a) + clutter_actor_get_width (a) + 20)
+
+ /* should be replace with constraints */
+ append_ltr (renderer->speaker_speakerscreen, renderer->speaker_start);
+ append_ltr (renderer->speaker_start, renderer->speaker_pause);
+ append_ltr (renderer->speaker_pause, renderer->speaker_autoadvance);
+ append_ltr (renderer->speaker_autoadvance, renderer->speaker_rehearse);
+ append_ltr (renderer->speaker_rehearse, renderer->speaker_fullscreen);
+ }
+
+ {
+ float height = 32;
+ float y = clutter_actor_get_height (renderer->speaker_screen) - height;
+ float elapsed_part = g_timer_elapsed (renderer->timer, NULL) / renderer->total_seconds;
+
+ clutter_actor_set_height (renderer->speaker_prog_bg, height);
+ clutter_actor_set_height (renderer->speaker_prog_slide, height * 0.7);
+ clutter_actor_set_height (renderer->speaker_prog_time, height * 0.84);
+ clutter_actor_set_size (renderer->speaker_slide_prog_warning,
+ nw, height * 1.0);
+ clutter_actor_set_y (renderer->speaker_prog_bg, y);
+ clutter_actor_set_y (renderer->speaker_prog_slide, y + height * 0.05);
+ clutter_actor_set_y (renderer->speaker_prog_time, y);
+
+ clutter_actor_set_y (renderer->speaker_slide_prog_warning, y - height * 0.1);
+ /*
+ clutter_actor_set_size (renderer->speaker_slide_prog_warning,
+ nw, nh);
+ clutter_actor_set_y (renderer->speaker_slide_prog_warning, 0);*/
+
+ clutter_actor_set_x (renderer->speaker_buttons_group, nw * 0.4);
+ clutter_actor_set_y (renderer->speaker_buttons_group, 5);
+
+ clutter_actor_set_width (renderer->speaker_prog_bg, nw);
+
+
+ clutter_actor_set_position (renderer->speaker_time_remaining,
+ nw - clutter_actor_get_width (renderer->speaker_time_remaining),
+ nh - clutter_actor_get_height (renderer->speaker_time_remaining) - 4);
+
+ clutter_actor_set_width (renderer->speaker_prog_slide,
+ nw * slide_rel_duration (renderer, pp_slidep));
+ clutter_actor_set_x (renderer->speaker_prog_slide,
+ nw * slide_rel_start (renderer, pp_slidep));
+
+ clutter_actor_set_x (renderer->speaker_prog_time, nw * elapsed_part);
+
+ clutter_actor_set_width (renderer->speaker_prog_time, nw * (1.0-elapsed_part));
+
+
+ elapsed_part = current_slide_time / current_slide_duration;
+ }
+
+ {
+ float scale;
+ scale = nh / clutter_actor_get_height (renderer->speaker_next) * 0.4;
+ clutter_actor_set_scale (renderer->speaker_prev, scale, scale);
+ clutter_actor_set_scale (renderer->speaker_current, scale, scale);
+ clutter_actor_set_scale (renderer->speaker_next, scale, scale);
}
+ {
+ static GList *current_slide = NULL;
+ if (current_slide != pp_slidep)
+ {
+ cairo_t *cr;
+
+ /*************/
+ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (renderer->speaker_prev));
+ cairo_renderer_set_cr (renderer->cairo_renderer,
+ cr, clutter_actor_get_width (renderer->speaker_prev),
+ clutter_actor_get_height (renderer->speaker_prev));
+ if (pp_slidep->prev)
+ cairo_renderer_render_page (renderer->cairo_renderer,
+ pp_slidep->prev->data);
+ else
+ cairo_renderer_render_page (renderer->cairo_renderer,
+ NULL);
+ cairo_renderer_unset_cr (renderer->cairo_renderer);
+ cairo_destroy (cr);
+
+ /*************/
+ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (renderer->speaker_current));
+ cairo_renderer_set_cr (renderer->cairo_renderer,
+ cr, clutter_actor_get_width (renderer->speaker_current),
+ clutter_actor_get_height (renderer->speaker_current));
+ cairo_renderer_render_page (renderer->cairo_renderer,
+ pp_slidep->data);
+ cairo_renderer_unset_cr (renderer->cairo_renderer);
+ cairo_destroy (cr);
+
+ /*************/
+ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (renderer->speaker_next));
+ cairo_renderer_set_cr (renderer->cairo_renderer,
+ cr, clutter_actor_get_width (renderer->speaker_next),
+ clutter_actor_get_height (renderer->speaker_next));
+ if (pp_slidep->next)
+ cairo_renderer_render_page (renderer->cairo_renderer,
+ pp_slidep->next->data);
+ else
+ cairo_renderer_render_page (renderer->cairo_renderer,
+ NULL);
+ cairo_renderer_unset_cr (renderer->cairo_renderer);
+ cairo_destroy (cr);
+ /*************/
+ current_slide = pp_slidep;
+ }
+ }
+
+ clutter_actor_set_position (renderer->speaker_prev,
+ nw * 0.0,
+ nh * -0.1);
+ clutter_actor_set_position (renderer->speaker_current,
+ nw * 0.0,
+ nh * 0.3);
+ clutter_actor_set_position (renderer->speaker_next,
+ nw * 0.0,
+ nh * 0.7);
+ clutter_actor_set_position (renderer->speaker_notes,
+ nw * 0.46,
+ nh * 0.35);
+ clutter_actor_set_width (renderer->speaker_notes,
+ nw * 0.5);
+ return TRUE;
+}
+
static void
show_slide (ClutterRenderer *renderer, gboolean backwards)
{
- PinPointPoint *point;
+ PinPointPoint *point;
ClutterPointData *data;
- ClutterColor color;
+ ClutterColor color;
if (!pp_slidep)
return;
-
+
+ renderer->slide_start_time = g_timer_elapsed (renderer->timer, NULL);
+
point = pp_slidep->data;
data = point->data;
@@ -781,28 +1785,14 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
if (data->background)
{
- float bg_x, bg_y, bg_width, bg_height, bg_scale_x, bg_scale_y;
- if (CLUTTER_IS_RECTANGLE (data->background))
- {
- clutter_actor_get_size (renderer->stage, &bg_width, &bg_height);
- clutter_actor_set_size (data->background, bg_width, bg_height);
- }
- else
- {
- clutter_actor_get_size (data->background, &bg_width, &bg_height);
- }
-
- pp_get_background_position_scale (point,
- clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage),
- bg_width, bg_height,
- &bg_x, &bg_y, &bg_scale_x, &bg_scale_y);
-
- clutter_actor_set_scale (data->background, bg_scale_x, bg_scale_y);
- clutter_actor_set_position (data->background, bg_x, bg_y);
+ pp_clutter_render_adjust_background (renderer, point);
#ifdef USE_CLUTTER_GST
- if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
+ if (point->bg_type == PP_BG_CAMERA)
+ {
+ gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
+ }
+ else if (CLUTTER_GST_IS_VIDEO_TEXTURE (data->background))
{
clutter_media_set_progress (CLUTTER_MEDIA (data->background), 0.0);
clutter_media_set_playing (CLUTTER_MEDIA (data->background), TRUE);
@@ -831,66 +1821,70 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
{
clutter_actor_animate (renderer->foreground,
CLUTTER_LINEAR, 500,
- "opacity", 255,
+ "opacity", 255,
NULL);
clutter_actor_animate (renderer->midground,
CLUTTER_LINEAR, 500,
- "opacity", 255,
+ "opacity", 255,
NULL);
clutter_actor_animate (renderer->background,
CLUTTER_LINEAR, 500,
- "opacity", 255,
+ "opacity", 255,
NULL);
-
if (point->text && *point->text)
{
float text_x, text_y, text_width, text_height, text_scale;
float shading_x, shading_y, shading_width, shading_height;
clutter_actor_get_size (data->text, &text_width, &text_height);
- pp_get_text_position_scale (point,
- clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage),
- text_width, text_height,
- &text_x, &text_y,
- &text_scale);
- pp_get_shading_position_size (clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage),
- text_x, text_y,
- text_width, text_height,
- text_scale,
- &shading_x, &shading_y,
- &shading_width, &shading_height);
+
+ pp_get_text_position_scale (
+ point,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage),
+ text_width, text_height,
+ &text_x, &text_y,
+ &text_scale);
+
+ pp_get_shading_position_size (
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage),
+ text_x, text_y,
+ text_width, text_height,
+ text_scale,
+ &shading_x, &shading_y,
+ &shading_width, &shading_height);
+
clutter_color_from_string (&color, point->shading_color);
clutter_actor_animate (data->text,
CLUTTER_EASE_OUT_QUINT, 1000,
- "depth", 0.0,
+ "depth", 0.0,
"scale-x", text_scale,
"scale-y", text_scale,
- "x", text_x,
- "y", text_y,
+ "x", text_x,
+ "y", text_y,
NULL);
clutter_actor_animate (renderer->shading,
CLUTTER_EASE_OUT_QUINT, 1000,
- "x", shading_x,
- "y", shading_y,
+ "x", shading_x,
+ "y", shading_y,
"opacity", (int)(point->shading_opacity*255),
- "color", &color,
- "width", shading_width,
- "height", shading_height,
+ "color", &color,
+ "width", shading_width,
+ "height", shading_height,
NULL);
}
else
{
- clutter_actor_animate (renderer->shading,
- CLUTTER_LINEAR, 500,
- "opacity", 0,
- "width", 0.0,
- "height", 0.0,
- NULL);
+ clutter_actor_animate (renderer->shading,
+ CLUTTER_LINEAR, 500,
+ "opacity", 0,
+ "width", 0.0,
+ "height", 0.0,
+ NULL);
}
@@ -906,29 +1900,37 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
/* fade out global group of texts when using a custom .json template */
clutter_actor_animate (renderer->foreground,
CLUTTER_LINEAR, 500,
- "opacity", 0,
+ "opacity", 0,
NULL);
clutter_actor_animate (renderer->midground,
CLUTTER_LINEAR, 500,
- "opacity", 0,
+ "opacity", 0,
NULL);
clutter_actor_animate (renderer->background,
CLUTTER_LINEAR, 500,
- "opacity", 0,
+ "opacity", 0,
NULL);
if (!data->script)
{
- gchar *path = pp_lookup_transition (point->transition);
+ char *path = pp_lookup_transition (point->transition);
data->script = clutter_script_new ();
clutter_script_load_from_file (data->script, path, &error);
g_free (path);
- data->foreground = CLUTTER_ACTOR (clutter_script_get_object (data->script, "foreground"));
- data->midground = CLUTTER_ACTOR (clutter_script_get_object (data->script, "midground"));
- data->background2 = CLUTTER_ACTOR (clutter_script_get_object (data->script, "background"));
- data->state = CLUTTER_STATE (clutter_script_get_object (data->script, "state"));
- data->json_slide = CLUTTER_ACTOR (clutter_script_get_object (data->script, "actor"));
- clutter_container_add_actor (CLUTTER_CONTAINER (renderer->json_layer), data->json_slide);
- g_signal_connect (data->state, "completed", G_CALLBACK (state_completed), point);
+ data->foreground = CLUTTER_ACTOR (
+ clutter_script_get_object (data->script, "foreground"));
+ data->midground = CLUTTER_ACTOR (
+ clutter_script_get_object (data->script, "midground"));
+ data->background2 = CLUTTER_ACTOR (
+ clutter_script_get_object (data->script, "background"));
+ data->state = CLUTTER_STATE (
+ clutter_script_get_object (data->script, "state"));
+ data->json_slide = CLUTTER_ACTOR (
+ clutter_script_get_object (data->script, "actor"));
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (renderer->json_layer),
+ data->json_slide);
+ g_signal_connect (data->state, "completed",
+ G_CALLBACK (state_completed), point);
clutter_state_warp_to_state (data->state, "pre");
if (data->background2) /* parmanently steal background */
@@ -936,24 +1938,32 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
clutter_actor_reparent (data->background, data->background2);
}
}
- clutter_actor_set_size (data->json_slide, clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage));
- clutter_actor_set_size (data->foreground, clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage));
+ clutter_actor_set_size (data->json_slide,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage));
+
+ clutter_actor_set_size (data->foreground,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage));
+
+ clutter_actor_set_size (data->background2,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage));
- clutter_actor_set_size (data->background2, clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage));
if (!data->json_slide)
{
- g_warning ("failed to load transition %s %s\n", point->transition, error?error->message:"");
+ g_warning ("failed to load transition %s %s\n",
+ point->transition, error?error->message:"");
return;
}
+
if (data->foreground)
{
clutter_actor_reparent (data->text, data->foreground);
}
- clutter_actor_set_opacity (data->background, 255);
+
+ clutter_actor_set_opacity (data->background, 255);
{
float text_x, text_y, text_width, text_height, text_scale;
@@ -966,42 +1976,46 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
&text_x, &text_y,
&text_scale);
g_object_set (data->text,
- "depth", 0.0,
+ "depth", 0.0,
"scale-x", text_scale,
"scale-y", text_scale,
- "x", text_x,
- "y", text_y,
+ "x", text_x,
+ "y", text_y,
NULL);
-
if (clutter_actor_get_width (data->text) > 1.0)
{
ClutterColor color;
float shading_x, shading_y, shading_width, shading_height;
clutter_color_from_string (&color, point->shading_color);
+ pp_get_shading_position_size (
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage),
+ text_x, text_y,
+ text_width, text_height,
+ text_scale,
+ &shading_x, &shading_y,
+ &shading_width, &shading_height);
- pp_get_shading_position_size (clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage),
- text_x, text_y,
- text_width, text_height,
- text_scale,
- &shading_x, &shading_y,
- &shading_width, &shading_height);
if (!data->shading)
{
data->shading = clutter_rectangle_new_with_color (&black);
- clutter_container_add_actor (CLUTTER_CONTAINER (data->midground), data->shading);
- clutter_actor_set_size (data->midground, clutter_actor_get_width (renderer->stage),
- clutter_actor_get_height (renderer->stage));
+
+ clutter_container_add_actor (
+ CLUTTER_CONTAINER (data->midground), data->shading);
+ clutter_actor_set_size (data->midground,
+ clutter_actor_get_width (renderer->stage),
+ clutter_actor_get_height (renderer->stage));
}
+
g_object_set (data->shading,
- "depth", -0.01,
- "x", shading_x,
- "y", shading_y,
+ "depth", -0.01,
+ "x", shading_x,
+ "y", shading_y,
"opacity", (int)(point->shading_opacity*255),
- "color", &color,
- "width", shading_width,
+ "color", &color,
+ "width", shading_width,
"height", shading_height,
NULL);
}
@@ -1016,11 +2030,11 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
if (!backwards)
clutter_actor_raise_top (data->json_slide);
+
clutter_actor_show (data->json_slide);
clutter_state_set_state (data->state, "show");
}
-
/* render potentially executed commands */
{
float text_x, text_y, text_width, text_height;
@@ -1028,27 +2042,29 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
clutter_color_from_string (&color, point->text_color);
g_object_set (renderer->commandline,
"font-name", point->font,
- "text", point->command?point->command:"",
- "color", &color,
+ "text", point->command?point->command:"",
+ "color", &color,
NULL);
+
color.alpha *= 0.33;
g_object_set (renderer->commandline,
"selection-color", &color,
NULL);
clutter_actor_get_size (renderer->commandline, &text_width, &text_height);
+
if (point->position == CLUTTER_GRAVITY_SOUTH ||
point->position == CLUTTER_GRAVITY_SOUTH_WEST)
text_y = clutter_actor_get_height (renderer->stage) * 0.05;
else
text_y = clutter_actor_get_height (renderer->stage) * 0.95 - text_height;
- text_x = clutter_actor_get_width (renderer->stage) * 0.05;
+ text_x = clutter_actor_get_width (renderer->stage) * 0.05;
g_object_set (renderer->commandline,
- "x", text_x,
- "y", text_y,
- NULL);
+ "x", text_x,
+ "y", text_y,
+ NULL);
clutter_actor_animate (renderer->commandline,
CLUTTER_EASE_OUT_QUINT, 1000,
"opacity", point->command?(gint)(0xff*0.33):0,
@@ -1056,8 +2072,12 @@ show_slide (ClutterRenderer *renderer, gboolean backwards)
update_commandline_shading (renderer);
}
-}
+ if (renderer->speaker_mode)
+ {
+ update_speaker_screen (renderer);
+ }
+}
static void
stage_resized (ClutterActor *actor,
@@ -1065,6 +2085,7 @@ stage_resized (ClutterActor *actor,
ClutterRenderer *renderer)
{
show_slide (renderer, FALSE); /* redisplay the current slide */
+ update_speaker_screen (renderer);
}
static guint reload_tag = 0;
@@ -1073,9 +2094,11 @@ static gboolean
reload (gpointer data)
{
ClutterRenderer *renderer = data;
- char *text = NULL;
+ char *text = NULL;
+
if (!g_file_get_contents (renderer->path, &text, NULL, NULL))
g_error ("failed to load slides from %s\n", renderer->path);
+
renderer->rest_y = STARTPOS;
pp_parse_slides (PINPOINT_RENDERER (renderer), text);
g_free (text);
@@ -1093,6 +2116,7 @@ file_changed (GFileMonitor *monitor,
{
if (reload_tag)
g_source_remove (reload_tag);
+
reload_tag = g_timeout_add (200, reload, renderer);
}