diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/repl-connection.c | 6 | ||||
-rw-r--r-- | src/starlet-fixture-display.c | 403 | ||||
-rw-r--r-- | src/starlet-playback-display.c | 360 |
3 files changed, 303 insertions, 466 deletions
diff --git a/src/repl-connection.c b/src/repl-connection.c index 2e3201f..72446e7 100644 --- a/src/repl-connection.c +++ b/src/repl-connection.c @@ -153,6 +153,12 @@ static void input_ready(GObject *source, GAsyncResult *res, gpointer vp) printf("Prompt!\n"); repl->input[0] = '\0'; } + if ( strncmp(remaining, "Entering a new prompt", 21) == 0 ) { + fprintf(stderr, "Scheme error!\n"); + g_object_unref(repl->conn); + repl->conn = NULL; + return; + } free(remaining); g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(repl->conn)), diff --git a/src/starlet-fixture-display.c b/src/starlet-fixture-display.c index bf02350..ae7bc5e 100644 --- a/src/starlet-fixture-display.c +++ b/src/starlet-fixture-display.c @@ -29,6 +29,7 @@ #include <glib.h> #include <glib/gstdio.h> #include <libguile.h> +#include <lo/lo.h> #include <libintl.h> #define _(x) gettext(x) @@ -37,6 +38,7 @@ #define OVERALL_BORDER (20.0) +#define STATUS_HEIGHT (35.0) #define FIXTURE_BORDER (5.0) @@ -47,32 +49,61 @@ struct fixture double intensity; double rgb[3]; int selected; + double min_x; + double min_y; + double max_x; + double max_y; }; struct fixture_display { - double fixture_tile_width; struct fixture *fixtures; int n_fixtures; + double current_cue_number; + int cue_running; + double scanout_rate; + int programmer_empty; + char *playback_name; GtkWidget *da; ReplConnection *repl; int shutdown; char *socket; int verbose; + int got_eof; + lo_server osc_srv; }; +static void show_vertical_center_log(cairo_t *cr, PangoLayout *layout, + double x, double h) +{ + int layw, layh; + pango_layout_get_pixel_size(layout, &layw, &layh); + cairo_move_to(cr, x, (h-layh)/2.0); + pango_cairo_show_layout(cr, layout); +} + + static void draw_fixture(cairo_t *cr, PangoContext *pc, PangoFontDescription *fontdesc, - double w, struct fixture_display *fixd, - struct fixture *fix) + struct fixture *fix, + double *pw, double *ph) { PangoLayout *layout; - const double h = 3.0/2.0*w; + double w = 180.0; + const double lh = 20.0; + const double inner_margin = 3.0; + int n_lines = 2; + double h = n_lines * lh + 2*inner_margin; + + *pw = w; + *ph = h; + + cairo_save(cr); /* Pan/tilt (underneath rectangle) */ // if ( fix->cls->attributes & PANTILT ) { // @@ -93,56 +124,88 @@ static void draw_fixture(cairo_t *cr, // // } - cairo_rectangle(cr, 0.0, 0.0, w, h); + cairo_rectangle(cr, 0.5, 0.5, w, h); if ( fix->selected ) { - cairo_set_source_rgba(cr, 0.3, 0.3, 0.9, 0.9); + cairo_set_source_rgba(cr, 0.3, 0.5, 0.2, 1.0); + cairo_fill_preserve(cr); + cairo_set_line_width(cr, 2.0); + cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); + cairo_stroke(cr); } else { - cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, 0.9); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + cairo_fill_preserve(cr); + cairo_set_line_width(cr, 1.0); + cairo_set_source_rgb(cr, 0.0, 0.6, 0.0); + cairo_stroke(cr); } - cairo_fill_preserve(cr); - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); + + /* Margin inside fixture rectangle */ + cairo_translate(cr, inner_margin, inner_margin); + w -= 2.0*inner_margin; + h -= 2.0*inner_margin; /* Label */ layout = pango_layout_new(pc); pango_layout_set_text(layout, fix->label, -1); - pango_layout_set_width(layout, (w*PANGO_SCALE)-4.0); - pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + pango_layout_set_height(layout, lh*PANGO_SCALE); pango_layout_set_font_description(layout, fontdesc); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_move_to(cr, 0.0, 2.0); - pango_cairo_show_layout(cr, layout); + show_vertical_center_log(cr, layout, 0.0, lh); g_object_unref(layout); + cairo_translate(cr, 0.0, lh); + + /* Colour */ + cairo_rectangle(cr, 1.0, 0.0, w*0.25, lh); + cairo_set_source_rgba(cr, fix->rgb[0], fix->rgb[1], fix->rgb[2], 1.0); + cairo_fill(cr); + + /* Mimic */ + cairo_set_source_rgba(cr, + fix->intensity * fix->rgb[0] / 100.0, + fix->intensity * fix->rgb[1] / 100.0, + fix->intensity * fix->rgb[2] / 100.0, + 1.0); + cairo_rectangle(cr, w*0.25+2.0, 0.0, w*0.75-2.0, lh); + cairo_fill(cr); /* Intensity */ if ( fix->intensity >= 0.0 ) { char tmp[32]; - snprintf(tmp, 32, "%.0f %%", fix->intensity); + double grey; + snprintf(tmp, 32, "%.0f%%", fix->intensity); layout = pango_layout_new(pc); pango_layout_set_text(layout, tmp, -1); - pango_layout_set_width(layout, (w*PANGO_SCALE)-4.0); - pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + pango_layout_set_height(layout, lh*PANGO_SCALE); pango_layout_set_font_description(layout, fontdesc); - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_move_to(cr, 0.0, 25.0); - pango_cairo_show_layout(cr, layout); + + if ( fix->intensity < 50.0 ) { + grey = 1.0; + } else { + grey = 0.0; + } + cairo_set_source_rgb(cr, grey, grey, grey); + + show_vertical_center_log(cr, layout, w*0.3, lh); g_object_unref(layout); } - /* Mimic */ - cairo_set_source_rgba(cr, - fix->intensity * fix->rgb[0] / 100.0, - fix->intensity * fix->rgb[1] / 100.0, - fix->intensity * fix->rgb[2] / 100.0, - 1.0); - cairo_rectangle(cr, 3.0, 2.0*h/3.0-3.0, w-6.0, h/3.0); - cairo_fill(cr); + cairo_restore(cr); +} - /* Colour */ - cairo_rectangle(cr, 3.0, 4.0*h/8.0-3.0, w-6.0, h/8.0); - cairo_set_source_rgba(cr, fix->rgb[0], fix->rgb[1], fix->rgb[2], 1.0); - cairo_fill(cr); + +static void plot_text(cairo_t *cr, const char *text, + PangoContext *pc, PangoFontDescription *fontdesc, + double x, double y) +{ + PangoLayout *layout; + + layout = pango_layout_new(pc); + pango_layout_set_text(layout, text, -1); + pango_layout_set_font_description(layout, fontdesc); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_move_to(cr, x, y); + pango_cairo_show_layout(cr, layout); + g_object_unref(layout); } @@ -153,10 +216,12 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct fixture_display PangoContext *pc; PangoFontDescription *fontdesc; double x, y; + char tmp[128]; w = gtk_widget_get_allocated_width(widget); h = gtk_widget_get_allocated_height(widget); pc = gtk_widget_get_pango_context(widget); + fontdesc = pango_font_description_from_string("Sans 10"); /* Overall background */ if ( fixd->repl == NULL ) { @@ -164,7 +229,7 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct fixture_display cairo_paint(cr); return FALSE; } else { - cairo_set_source_rgb(cr, 0.0, 0.0, 0.2); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.08); cairo_paint(cr); } @@ -173,20 +238,56 @@ static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, struct fixture_display w -= OVERALL_BORDER*2.0; h -= OVERALL_BORDER*2.0; + /* Playback status */ + cairo_save(cr); + + if ( fixd->cue_running ) { + cairo_rectangle(cr, 0.0, 0.0, w, 18.0); + cairo_set_source_rgb(cr, 0.5, 0.0, 0.0); + cairo_fill(cr); + } + + if ( fixd->current_cue_number < 0.0 ) { + snprintf(tmp, 128, "Playback %s: Current cue doesn't exist! " + "Scanout %.2f per second", + fixd->playback_name, + fixd->scanout_rate); + } else { + snprintf(tmp, 128, "Playback %s: Current cue number: %.2f " + "Scanout %.2f per second", + fixd->playback_name, + fixd->current_cue_number, + fixd->scanout_rate); + } + plot_text(cr, tmp, pc, fontdesc, 0.0, 0.0); + cairo_restore(cr); + + if ( !fixd->programmer_empty ) { + cairo_rectangle(cr, w-150.0, 0.0, 150.0, 18.0); + cairo_set_source_rgb(cr, 0.8, 0.0, 0.0); + cairo_fill(cr); + plot_text(cr, "Programmer active", pc, fontdesc, w-150.0, 0.0); + } + /* Fixtures */ - x = FIXTURE_BORDER; - y = FIXTURE_BORDER; - fontdesc = pango_font_description_from_string("Comfortaa Bold 12"); + x = 0.0; + y = STATUS_HEIGHT; for ( i=0; i<fixd->n_fixtures; i++ ) { + double fw, fh; cairo_save(cr); cairo_translate(cr, x, y); - draw_fixture(cr, pc, fontdesc, fixd->fixture_tile_width, - fixd, &fixd->fixtures[i]); + draw_fixture(cr, pc, fontdesc, fixd, &fixd->fixtures[i], + &fw, &fh); + fixd->fixtures[i].min_x = x; + fixd->fixtures[i].min_y = y; + fixd->fixtures[i].max_x = x + fw; + fixd->fixtures[i].max_y = y + fh; cairo_restore(cr); - x += fixd->fixture_tile_width + FIXTURE_BORDER*2; - if ( x + fixd->fixture_tile_width + FIXTURE_BORDER*2 > w ) { - x = FIXTURE_BORDER; - y += fixd->fixture_tile_width*3.0/2.0 + FIXTURE_BORDER*2; + x += fw + FIXTURE_BORDER; + if ( x + fw > w) { + /* Can't fit another fixture on this row */ + x = 0.0; + y += fh + FIXTURE_BORDER; } } @@ -214,17 +315,41 @@ static void shutdown_sig(GtkWidget *window, struct fixture_display *fixd) } +static void request_programmer_status(struct fixture_display *fixd) +{ + char tmp[256]; + snprintf(tmp, 256, "(list 'programmer-empty " + "(state-empty? programmer-state))"); + repl_send(fixd->repl, tmp); +} + + +static void request_playback_status(struct fixture_display *fixd) +{ + char tmp[256]; + snprintf(tmp, 256, "(list 'playback-status (list " + "(get-playback-cue-number %s)" + "scanout-freq" + "(playback-state %s)" + "))", + fixd->playback_name, + fixd->playback_name); + repl_send(fixd->repl, tmp); +} + + static void request_intensities(struct fixture_display *fixd) { int i; + repl_send(fixd->repl, "(define all-vals (current-value-state))\n"); for ( i=0; i<fixd->n_fixtures; i++ ) { char tmp[256]; snprintf(tmp, 256, "(list" " 'fixture-parameters" " (list \"%s\" " - " (current-value %s 'intensity) " - " (let ((col (current-value %s 'colour)))" + " (state-find %s intensity all-vals) " + " (let ((col (state-find %s colour all-vals)))" " (if (colour? col)" " (colour-as-rgb col)" " #f))))", @@ -236,12 +361,6 @@ static void request_intensities(struct fixture_display *fixd) } -static void request_selection(struct fixture_display *fixd) -{ - repl_send(fixd->repl, "(list 'selection (map get-fixture-name (get-selection)))"); -} - - static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, struct fixture_display *fixd) { int claim = 1; @@ -260,6 +379,10 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, struct fixture_ repl_send(fixd->repl, "(back! pb)"); break; + case GDK_KEY_F5 : + repl_send(fixd->repl, "(exit)"); + break; + default : claim = 0; break; @@ -302,9 +425,12 @@ static gboolean redraw_cb(gpointer data) return G_SOURCE_CONTINUE; } } else { - if ( !fixd->shutdown ) { + if ( !fixd->shutdown && fixd->got_eof ) { + fixd->got_eof = FALSE; request_intensities(fixd); - request_selection(fixd); + request_playback_status(fixd); + request_programmer_status(fixd); + repl_send(fixd->repl, "'end-of-stuff"); redraw(fixd); } return G_SOURCE_CONTINUE; @@ -347,17 +473,6 @@ static int symbol_eq(SCM symbol, const char *val) } -static char *symbol_to_str(SCM symbol) -{ - if ( scm_is_symbol(symbol) ) { - SCM str = scm_symbol_to_string(symbol); - return scm_to_locale_string(str); - } else { - return NULL; - } -} - - static char *group_fixture_name(SCM item) { char tmp[64]; @@ -411,6 +526,14 @@ static void handle_patched_fixtures(struct fixture_display *fixd, fixd->fixtures[i].intensity = -1; fixd->fixtures[i].selected = 0; + fixd->fixtures[i].min_x = 0.0; + fixd->fixtures[i].min_y = 0.0; + fixd->fixtures[i].max_x = 0.0; + fixd->fixtures[i].max_y = 0.0; + fixd->fixtures[i].intensity = 0.0; + fixd->fixtures[i].rgb[0] = 0.0; + fixd->fixtures[i].rgb[1] = 0.0; + fixd->fixtures[i].rgb[2] = 0.0; } } @@ -447,7 +570,12 @@ static void handle_fixture_parameters(struct fixture_display *fixd, SCM list) fix = find_fixture(fixd, fixture_name); if ( fix != NULL ) { - fix->intensity = scm_to_double(scm_list_ref(list, scm_from_int(1))); + SCM i = scm_list_ref(list, scm_from_int(1)); + if ( symbol_eq(i, "no-value") ) { + fix->intensity = 0.0; + } else { + fix->intensity = scm_to_double(i); + } read_rgb(fix->rgb, scm_list_ref(list, scm_from_int(2))); } else { fprintf(stderr, "Unrecognised fixture '%s' (parameters)\n", @@ -458,45 +586,23 @@ static void handle_fixture_parameters(struct fixture_display *fixd, SCM list) } -static void handle_selection(struct fixture_display *fixd, SCM list) +static void handle_playback_status(struct fixture_display *fixd, SCM list) { - int i; - int nfix; - - if ( !is_list(list) ) { - fprintf(stderr, "Invalid selection list\n"); - return; - } - - nfix = scm_to_int(scm_length(list)); - - for ( i=0; i<fixd->n_fixtures; i++ ) { - fixd->fixtures[i].selected = 0; + SCM cue_number = scm_list_ref(list, scm_from_int(0)); + if ( scm_is_false(cue_number) ) { + fixd->current_cue_number = -1.0; + } else { + fixd->current_cue_number = scm_to_double(cue_number); } + fixd->scanout_rate = scm_to_double(scm_list_ref(list, scm_from_int(1))); + fixd->cue_running = symbol_eq(scm_list_ref(list, scm_from_int(2)), + "running"); +} - for ( i=0; i<nfix; i++ ) { - SCM item = scm_list_ref(list, scm_from_int(i)); - char *name_str; - if ( scm_is_symbol(item) ) { - name_str = symbol_to_str(item); - } else if ( is_list(item) ) { - name_str = group_fixture_name(item); - } else { - fprintf(stderr, "Unrecognised type in selection list\n"); - name_str = NULL; - } - if ( name_str != NULL ) { - struct fixture *fix = find_fixture(fixd, name_str); - if ( fix != NULL ) { - fix->selected = 1; - } else { - fprintf(stderr, "Fixture '%s' not found (selection)\n", - name_str); - } - free(name_str); - } - } +static void handle_programmer_status(struct fixture_display *fixd, SCM empty) +{ + fixd->programmer_empty = scm_is_true(empty); } @@ -512,10 +618,14 @@ static void process_line(SCM sexp, void *data) handle_patched_fixtures(fixd, contents); } else if ( symbol_eq(tag, "fixture-parameters") ) { handle_fixture_parameters(fixd, contents); - } else if ( symbol_eq(tag, "selection") ) { - handle_selection(fixd, contents); + } else if ( symbol_eq(tag, "playback-status") ) { + handle_playback_status(fixd, contents); + } else if ( symbol_eq(tag, "programmer-empty") ) { + handle_programmer_status(fixd, contents); } } + } else if ( scm_is_symbol(sexp) && symbol_eq(sexp, "end-of-stuff") ) { + fixd->got_eof = TRUE; } } @@ -527,13 +637,81 @@ static gboolean try_connect_cb(gpointer data) fixd->repl = repl_connection_new(fixd->socket, process_line, fixd, fixd->verbose); if ( fixd->repl != NULL ) { + fixd->got_eof = FALSE; repl_send(fixd->repl, "(list 'patched-fixtures (reverse (patched-fixture-names)))"); + repl_send(fixd->repl, "'end-of-stuff"); } } return G_SOURCE_CONTINUE; } +static struct fixture *which_fixture(struct fixture_display *fixd, + double x, double y) +{ + int i; + for ( i=0; i<fixd->n_fixtures; i++ ) { + struct fixture *t = &fixd->fixtures[i]; + if ( (x > t->min_x) + && (x < t->max_x) + && (y > t->min_y) + && (y < t->max_y) ) return t; + } + return NULL; +} + + +static gint button_press_sig(GtkWidget *window, GdkEventButton *event, + struct fixture_display *fixd) +{ + struct fixture *fix; + if ( event->y < STATUS_HEIGHT ) return FALSE; + fix = which_fixture(fixd, + event->x-OVERALL_BORDER, + event->y-OVERALL_BORDER); + if ( fix != NULL ) { + char tmp[256]; + snprintf(tmp, 256, "(toggle-sel %s)", fix->scheme_name); + repl_send(fixd->repl, tmp); + } + return FALSE; +} + + +static void osc_error_callback(int num, const char *msg, const char *path) +{ + fprintf(stderr, "liblo error %i (%s) for path %s\n", num, msg, path); +} + + +static int osc_selection_callback(const char *path, const char *types, + lo_arg **argv, int argc, lo_message msg, + void *vp) +{ + int i; + gchar **bits; + struct fixture_display *fixd = vp; + + for ( i=0; i<fixd->n_fixtures; i++ ) { + fixd->fixtures[i].selected = 0; + } + + bits = g_strsplit(&argv[0]->s, " ",-1); + for ( i=0; bits[i] != NULL; i++ ) { + struct fixture *fix = find_fixture(fixd, bits[i]); + if ( fix != NULL ) { + fix->selected = 1; + } else { + fprintf(stderr, "Fixture '%s' not found (selection)\n", + bits[i]); + } + } + g_strfreev(bits); + + return 1; +} + + int main(int argc, char *argv[]) { struct fixture_display fixd; @@ -597,7 +775,6 @@ int main(int argc, char *argv[]) da = gtk_drawing_area_new(); - fixd.fixture_tile_width = 100.0; fixd.fixtures = NULL; fixd.n_fixtures = 0; fixd.da = da; @@ -605,19 +782,33 @@ int main(int argc, char *argv[]) fixd.socket = socket; fixd.verbose = verbose; fixd.repl = NULL; + fixd.playback_name = strdup("pb"); + fixd.cue_running = 0; + fixd.programmer_empty = 1; + fixd.got_eof = TRUE; + + fixd.osc_srv = lo_server_thread_new_from_url("osc.udp://:7772", + osc_error_callback); + lo_server_thread_start(fixd.osc_srv); + lo_server_thread_add_method(fixd.osc_srv, "/starlet/selection/update", + "s", osc_selection_callback, &fixd); gtk_container_add(GTK_CONTAINER(mainwindow), GTK_WIDGET(da)); gtk_widget_set_can_focus(GTK_WIDGET(da), TRUE); gtk_widget_add_events(da, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK); - g_signal_connect(G_OBJECT(da), "draw", G_CALLBACK(draw_sig), &fixd); - g_signal_connect(G_OBJECT(da), "realize", G_CALLBACK(realise_sig), &fixd); + g_signal_connect(G_OBJECT(da), + "draw", G_CALLBACK(draw_sig), &fixd); + g_signal_connect(G_OBJECT(da), "realize", + G_CALLBACK(realise_sig), &fixd); + g_signal_connect(G_OBJECT(da), "button-press-event", + G_CALLBACK(button_press_sig), &fixd); gtk_widget_grab_focus(GTK_WIDGET(da)); gtk_widget_show_all(mainwindow); - g_timeout_add(50, redraw_cb, &fixd); + g_timeout_add(200, redraw_cb, &fixd); g_timeout_add(1000, try_connect_cb, &fixd); gtk_main(); diff --git a/src/starlet-playback-display.c b/src/starlet-playback-display.c deleted file mode 100644 index 9ce5438..0000000 --- a/src/starlet-playback-display.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * starlet-playback-display.c - * - * Copyright © 2019-2021 Thomas White <taw@bitwiz.me.uk> - * - * This file is part of Starlet. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - - -#include <gtk/gtk.h> -#include <getopt.h> -#include <string.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <glib.h> -#include <glib/gstdio.h> -#include <libguile.h> - -#include <libintl.h> -#define _(x) gettext(x) - -#include "repl-connection.h" - - -#define OVERALL_BORDER (20.0) - - -struct playback_display -{ - GtkWidget *da; - ReplConnection *repl; - int shutdown; - const char *playback_name; - double current_cue_number; - double scanout_rate; - char *socket; - int verbose; -}; - - -static void plot_text(cairo_t *cr, const char *text, - PangoContext *pc, PangoFontDescription *fontdesc, - double x, double y) -{ - PangoLayout *layout; - - layout = pango_layout_new(pc); - pango_layout_set_text(layout, text, -1); - pango_layout_set_font_description(layout, fontdesc); - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_move_to(cr, x, y); - pango_cairo_show_layout(cr, layout); - g_object_unref(layout); -} - - -static gboolean draw_sig(GtkWidget *widget, cairo_t *cr, - struct playback_display *pbd) -{ - PangoContext *pc; - PangoFontDescription *fontdesc; - char tmp[32]; - - pc = gtk_widget_get_pango_context(widget); - fontdesc = pango_font_description_from_string("Comfortaa Bold 12"); - - /* Overall background */ - if ( pbd->repl == NULL ) { - cairo_set_source_rgb(cr, 0.2, 0.0, 0.0); - cairo_paint(cr); - return FALSE; - } else { - cairo_set_source_rgb(cr, 0.0, 0.0, 0.2); - cairo_paint(cr); - } - - cairo_save(cr); - cairo_translate(cr, OVERALL_BORDER, OVERALL_BORDER); - - if ( pbd->current_cue_number < 0.0 ) { - snprintf(tmp, 32, "Current cue doesn't exist!"); - } else { - snprintf(tmp, 32, "Current cue number: %.2f", pbd->current_cue_number); - } - plot_text(cr, tmp, pc, fontdesc, 0.0, 0.0); - snprintf(tmp, 32, "Scanout rate: %.2f per second", pbd->scanout_rate); - plot_text(cr, tmp, pc, fontdesc, 0.0, 32.0); - - cairo_restore(cr); - - return FALSE; -} - - -static void redraw(struct playback_display *pbd) -{ - gint w, h; - w = gtk_widget_get_allocated_width(GTK_WIDGET(pbd->da)); - h = gtk_widget_get_allocated_height(GTK_WIDGET(pbd->da)); - gtk_widget_queue_draw_area(GTK_WIDGET(pbd->da), 0, 0, w, h); -} - - -static void shutdown_sig(GtkWidget *window, struct playback_display *pbd) -{ - if ( pbd->repl != NULL ) { - repl_connection_close(pbd->repl); - } - pbd->shutdown = TRUE; -} - - -static void request_playback_status(struct playback_display *pbd) -{ - char tmp[256]; - snprintf(tmp, 256, "(list 'playback-status (list " - "(get-playback-cue-number %s)" - "scanout-freq" - "))", - pbd->playback_name); - repl_send(pbd->repl, tmp); -} - - -static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, struct playback_display *pbd) -{ - int claim = 1; - - switch ( event->keyval ) { - - case GDK_KEY_Escape : - repl_send(pbd->repl, "(sel #f)"); - break; - - case GDK_KEY_KP_Enter : - repl_send(pbd->repl, "(go! pb)"); - break; - - case GDK_KEY_KP_Add : - repl_send(pbd->repl, "(back! pb)"); - break; - - default : - claim = 0; - break; - - } - - if ( claim ) return TRUE; - return FALSE; -} - - -static gint realise_sig(GtkWidget *da, struct playback_display *pbd) -{ - GdkWindow *win = gtk_widget_get_window(da); - - /* Keyboard and input method stuff */ - gdk_window_set_accept_focus(win, TRUE); - g_signal_connect(G_OBJECT(da), "key-press-event", G_CALLBACK(key_press_sig), pbd); - - return FALSE; -} - - -static gboolean redraw_cb(gpointer data) -{ - struct playback_display *pbd = data; - if ( pbd->repl == NULL ) { - return G_SOURCE_CONTINUE; - } - if ( repl_closed(pbd->repl) ) { - if ( pbd->shutdown ) { - gtk_main_quit(); - return G_SOURCE_REMOVE; - } else { - pbd->repl = NULL; - redraw(pbd); - return G_SOURCE_CONTINUE; - } - } else { - if ( !pbd->shutdown ) { - request_playback_status(pbd); - redraw(pbd); - } - return G_SOURCE_CONTINUE; - } -} - - -static void show_help(const char *s) -{ - printf(_("Syntax: %s [options]\n\n"), s); - printf(_("Show playback status in Starlet\n" - " -s, --socket REPL socket for Starlet process (default guile.socket).\n" - " -v, --verbose Show all REPL communications.\n" - " -h, --help Display this help message.\n")); -} - - -static int is_list(SCM list) -{ - return scm_is_true(scm_list_p(list)); -} - - -static int symbol_eq(SCM symbol, const char *val) -{ - return scm_is_true(scm_eq_p(symbol, scm_from_utf8_symbol(val))); -} - - -static void handle_playback_status(struct playback_display *pbd, SCM list) -{ - SCM cue_number = scm_list_ref(list, scm_from_int(0)); - if ( scm_is_false(cue_number) ) { - pbd->current_cue_number = -1.0; - } else { - pbd->current_cue_number = scm_to_double(cue_number); - } - pbd->scanout_rate = scm_to_double(scm_list_ref(list, scm_from_int(1))); -} - - -static void process_line(SCM sexp, void *data) -{ - struct playback_display *pbd = data; - - if ( is_list(sexp) && scm_to_int(scm_length(sexp)) == 2 ) { - SCM tag = scm_list_ref(sexp, scm_from_int(0)); - SCM contents = scm_list_ref(sexp, scm_from_int(1)); - if ( scm_is_symbol(tag) ) { - if ( symbol_eq(tag, "playback-status") ) { - handle_playback_status(pbd, contents); - } - } - } -} - - -static gboolean try_connect_cb(gpointer data) -{ - struct playback_display *pbd = data; - if ( pbd->repl == NULL ) { - pbd->repl = repl_connection_new(pbd->socket, process_line, - pbd, pbd->verbose); - } - return G_SOURCE_CONTINUE; -} - - -int main(int argc, char *argv[]) -{ - struct playback_display pbd; - int c; - GtkWidget *mainwindow; - GtkWidget *da; - char *socket = NULL; - char *playback_name = "pb"; - int verbose = 0; - - gtk_init(&argc, &argv); - - const struct option longopts[] = { - {"help", 0, NULL, 'h'}, - {"socket", 1, NULL, 's'}, - {"playback", 1, NULL, 'p'}, - {"verbose", 0, NULL, 'v'}, - {0, 0, NULL, 0} - }; - - while ((c = getopt_long(argc, argv, "hvs:", longopts, NULL)) != -1) { - - switch (c) - { - case 'h' : - show_help(argv[0]); - return 0; - - case 's' : - socket = strdup(optarg); - break; - - case 'p' : - playback_name = strdup(optarg); - break; - - case 'v' : - verbose = 1; - break; - - case 0 : - break; - - default : - return 1; - } - - } - - #if !GLIB_CHECK_VERSION(2,36,0) - g_type_init(); - #endif - - bindtextdomain("starlet", LOCALEDIR); - textdomain("starlet"); - - if ( socket == NULL ) { - socket = strdup("guile.socket"); - } - - /* Create main window */ - mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(mainwindow), 320, 512); - g_signal_connect(G_OBJECT(mainwindow), "destroy", - G_CALLBACK(shutdown_sig), &pbd); - gtk_window_set_title(GTK_WINDOW(mainwindow), "Starlet playback display"); - - da = gtk_drawing_area_new(); - - pbd.da = da; - pbd.shutdown = FALSE; - pbd.playback_name = playback_name; - pbd.socket = socket; - pbd.verbose = verbose; - pbd.repl = NULL; - - gtk_container_add(GTK_CONTAINER(mainwindow), GTK_WIDGET(da)); - gtk_widget_set_can_focus(GTK_WIDGET(da), TRUE); - gtk_widget_add_events(da, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_BUTTON_MOTION_MASK); - g_signal_connect(G_OBJECT(da), "draw", G_CALLBACK(draw_sig), &pbd); - g_signal_connect(G_OBJECT(da), "realize", G_CALLBACK(realise_sig), &pbd); - - gtk_widget_grab_focus(GTK_WIDGET(da)); - gtk_widget_show_all(mainwindow); - - g_timeout_add(50, redraw_cb, &pbd); - - g_timeout_add(1000, try_connect_cb, &pbd); - - gtk_main(); - - return 0; -} |