summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2008-02-12 21:23:46 -0800
committerAaron Plattner <aplattner@nvidia.com>2008-02-12 21:23:46 -0800
commit389b71f6f2e4bdcfee1b7bdcad0bf36f6ba43e5b (patch)
tree37a5d58b6ece4db47664507d7a54c3ace4046138
parent4256beee1897d25700b9cd6bf51728bc31c86627 (diff)
1.0-76671.0-7667
-rw-r--r--src/gtk+-2.x/ctkgvo.c1822
-rw-r--r--src/gtk+-2.x/ctkgvo.h65
-rw-r--r--src/gtk+-2.x/ctkutils.c15
-rw-r--r--src/gtk+-2.x/ctkutils.h4
-rw-r--r--src/gtk+-2.x/ctkwindow.c108
-rw-r--r--src/libXNVCtrl/NVCtrl.h10
-rw-r--r--src/libXNVCtrl/libXNVCtrl.abin13488 -> 13488 bytes
-rw-r--r--src/parse.c16
-rw-r--r--src/parse.h2
-rw-r--r--src/query-assign.c103
10 files changed, 1883 insertions, 262 deletions
diff --git a/src/gtk+-2.x/ctkgvo.c b/src/gtk+-2.x/ctkgvo.c
index e06c7d7..15f6279 100644
--- a/src/gtk+-2.x/ctkgvo.c
+++ b/src/gtk+-2.x/ctkgvo.c
@@ -23,12 +23,14 @@
*/
#include <gtk/gtk.h>
+#include <string.h>
#include "NvCtrlAttributes.h"
#include "ctkhelp.h"
#include "ctkgvo.h"
#include "ctkdropdownmenu.h"
+#include "ctkutils.h"
#include "gvo_banner_left.h"
@@ -58,10 +60,15 @@
/* local prototypes */
-static void init_gvo_banner(CtkGvo *ctk_gvo);
+static void init_gvo_banner(CtkGvoBanner *banner);
+static gboolean update_gvo_banner(gpointer data);
-static void pack_gvo_banner(CtkGvo *ctk_gvo);
+static void update_gvo_banner_video_output(CtkGvoBanner *banner,
+ gint output_video_format,
+ gint output_data_format);
+static void update_gvo_banner_video_input(CtkGvoBanner *banner,
+ gint sdi, gint comp);
static GtkWidget *start_menu(const gchar *name, GtkWidget *table,
const gint row);
@@ -74,9 +81,12 @@ static void sync_mode_changed(CtkDropDownMenu *menu, gpointer user_data);
static void output_video_format_changed(CtkDropDownMenu *menu,
gpointer user_data);
+static void post_output_video_format_changed(CtkGvo *ctk_gvo, gint value);
+
static void output_data_format_changed(CtkDropDownMenu *menu,
gpointer user_data);
+static void post_output_data_format_changed(CtkGvo *ctk_gvo, gint value);
static void update_sync_mode_menu(CtkGvo *ctk_gvo,
const gint composite_sync,
@@ -85,8 +95,7 @@ static void update_sync_mode_menu(CtkGvo *ctk_gvo,
static void init_sync_mode_menu(CtkGvo *ctk_gvo);
-static void update_output_video_format_menu(CtkGvo *ctk_gvo,
- const gint current);
+static void update_output_video_format_menu(CtkGvo *ctk_gvo);
static void init_output_video_format_menu(CtkGvo *ctk_gvo);
@@ -97,18 +106,52 @@ static void create_toggle_sdi_output_button(CtkGvo *ctk_gvo);
static void toggle_sdi_output_button(GtkWidget *button, gpointer user_data);
+static void post_toggle_sdi_output_button(CtkGvo *gvo, gboolean enabled);
+
+static void init_sync_format_menu(CtkGvo *ctk_gvo);
+
+static void update_sync_format_menu(CtkGvo *ctk_gvo);
+
static void sync_format_changed(CtkDropDownMenu *menu, gpointer user_data);
-static void
-update_input_video_format_text_entry(CtkGvo *ctk_gvo,
- const gint input_video_format);
+static void update_input_video_format_text_entry(CtkGvo *ctk_gvo);
static void init_input_video_format_text_entry(CtkGvo *ctk_gvo);
-static void
-input_video_format_detect_button_toggled(GtkToggleButton *togglebutton,
- CtkGvo *ctk_gvo);
+static int max_input_video_format_text_entry_length(void);
+
+static void detect_input(GtkToggleButton *togglebutton, CtkGvo *ctk_gvo);
+static gint detect_input_done(gpointer data);
+
+static const char *get_video_format_name(const gint format);
+static const char *get_data_format_name(const gint format);
+static void get_video_format_resolution(const gint format, gint *w, gint *h);
+
+static void set_gvo_sensitivity(CtkGvo *ctk_gvo,
+ gboolean sensitive, guint flags);
+
+static void get_video_format_details(CtkGvo *ctk_gvo);
+
+static void update_gvo_current_info(CtkGvo *ctk_gvo, gint w, gint h,
+ gint state);
+
+static void update_delay_spin_buttons(CtkGvo *ctk_gvo);
+
+static void hsync_delay_changed(GtkSpinButton *spinbutton, gpointer user_data);
+static void vsync_delay_changed(GtkSpinButton *spinbutton, gpointer user_data);
+
+static void update_offset_spin_buttons(CtkGvo *ctk_gvo);
+
+static void x_offset_changed(GtkSpinButton *spinbutton, gpointer user_data);
+static void y_offset_changed(GtkSpinButton *spinbutton, gpointer user_data);
+static gint probe(gpointer data);
+
+static void register_for_gvo_events(CtkGvo *ctk_gvo);
+
+static void gvo_event_received(GtkObject *object,
+ gpointer arg1,
+ gpointer user_data);
GType ctk_gvo_get_type(void)
{
@@ -147,6 +190,13 @@ typedef struct {
const char *name;
} FormatName;
+typedef struct {
+ int format;
+ int rate;
+ int width;
+ int height;
+} FormatDetails;
+
static const FormatName videoFormatNames[] = {
{ NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC, "480i 59.94 Hz (SMPTE259) NTSC"},
{ NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL, "576i 50.00 Hz (SMPTE259) PAL"},
@@ -180,6 +230,39 @@ static const FormatName videoFormatNames[] = {
};
+static FormatDetails videoFormatDetails[] = {
+ { NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_23_98_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_24_00_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_25_00_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_29_97_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_30_00_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_50_00_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_59_94_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_60_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_976_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274, 0, 0, 0 },
+ { NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274, 0, 0, 0 },
+ { -1, -1, -1, -1 },
+};
+
+
static const FormatName dataFormatNames[] = {
{ NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB444, "RGB -> YCrCb (4:4:4)" },
{ NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB422, "RGB -> YCrCb (4:2:2)" },
@@ -197,19 +280,44 @@ static const FormatName dataFormatNames[] = {
#define SYNC_FORMAT_COMP_BI_LEVEL 2
#define SYNC_FORMAT_COMP_TRI_LEVEL 3
+static const FormatName syncFormatNames[] = {
+ { SYNC_FORMAT_SDI, "SDI Sync" },
+ { SYNC_FORMAT_COMP_AUTO, "COMP Sync" },
+ { SYNC_FORMAT_COMP_BI_LEVEL, "COMP Sync (Bi-level)" },
+ { SYNC_FORMAT_COMP_TRI_LEVEL, "COMP Sync (Tri-level)" },
+ { -1, NULL },
+};
+
+
+/* arguments to set_gvo_sensitivity() */
+
+#define SET_SENSITIVITY_EXCLUDE_ENABLE_BUTTON 0x0001
+#define SET_SENSITIVITY_EXCLUDE_DETECT_BUTTON 0x0002
+#define SET_SENSITIVITY_EXCLUDE_ROI_BUTTONS 0x0004
+
+#define CURRENT_SDI_STATE_INACTIVE 0
+#define CURRENT_SDI_STATE_IN_USE_BY_X 1
+#define CURRENT_SDI_STATE_IN_USE_BY_GLX 2
+
+#define DEFAULT_DETECT_INPUT_TIME_INTERVAL 2000
+#define UPDATE_GVO_BANNER_TIME_INTERVAL 200
+#define DEFAULT_GVO_PROBE_TIME_INTERVAL 1000
/*
* ctk_gvo_new() - constructor for the CtkGvo widget
*/
GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
- CtkConfig *ctk_config)
+ GtkWidget *parent_window,
+ CtkConfig *ctk_config,
+ CtkEvent *ctk_event)
{
GObject *object;
CtkGvo *ctk_gvo;
- GtkWidget *hbox, *alignment, *button;
+ GtkWidget *hbox, *alignment, *button, *label;
ReturnStatus ret;
- int val, i, screen_width, screen_height, width, height, n;
+ gchar scratch[64], *firmware;
+ gint val, i, width, height, n;
GtkWidget *frame, *table, *menu;
@@ -233,7 +341,9 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
ctk_gvo = CTK_GVO(object);
ctk_gvo->handle = handle;
+ ctk_gvo->parent_window = parent_window;
ctk_gvo->ctk_config = ctk_config;
+ ctk_gvo->ctk_event = ctk_event;
/* set container properties for the CtkGvo widget */
@@ -249,25 +359,52 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
- ctk_gvo->banner_table = gtk_table_new(1, 6, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(ctk_gvo->banner_table), 0);
- gtk_table_set_col_spacings(GTK_TABLE(ctk_gvo->banner_table), 0);
-
- gtk_container_add(GTK_CONTAINER(frame), ctk_gvo->banner_table);
-
- init_gvo_banner(ctk_gvo);
- pack_gvo_banner(ctk_gvo);
+ ctk_gvo->banner_frame = frame;
+ init_gvo_banner(&ctk_gvo->banner);
/*
- * Output options
+ * General information
*/
- frame = gtk_frame_new("Output Options");
+ frame = gtk_frame_new("General Information");
gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
table = gtk_table_new(3, 2, FALSE);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 3);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 15);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ /* NV_CTRL_GVO_FIRMWARE_VERSION */
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_FIRMWARE_VERSION, &val);
+
+ if (ret == NvCtrlSuccess) {
+ snprintf(scratch, 64, "1.%02d", val);
+ firmware = strdup(scratch);
+ } else {
+ firmware = strdup("???");
+ }
+
+ add_table_row(table, 0, 0, "Firmware Version:", firmware);
+ ctk_gvo->current_resolution_label =
+ add_table_row(table, 1, 0, "Current SDI Resolution:", "Inactive");
+ ctk_gvo->current_state_label =
+ add_table_row(table, 2, 0, "Current SDI State:", "Inactive");
+
+
+ /*
+ * Sync options
+ */
+
+ frame = gtk_frame_new("Sync Options");
+
+ gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
+
+ table = gtk_table_new(4, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(table), 0);
gtk_table_set_col_spacings(GTK_TABLE(table), 0);
@@ -295,54 +432,135 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
g_signal_connect(G_OBJECT(ctk_gvo->sync_mode_menu), "changed",
G_CALLBACK(sync_mode_changed), (gpointer) ctk_gvo);
+ /* Sync Format */
+
+ menu = start_menu("Sync Format: ", table, 1);
+
+ for (i = 0; syncFormatNames[i].name; i++) {
+ ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu),
+ syncFormatNames[i].name,
+ syncFormatNames[i].format);
+ }
+
+ finish_menu(menu, table, 1);
+
+ ctk_gvo->sync_format_menu = menu;
+
+ init_sync_format_menu(ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->sync_format_menu),
+ "changed", G_CALLBACK(sync_format_changed),
+ (gpointer) ctk_gvo);
+
+ /* input type */
+
+ label = gtk_label_new("Input Video Format: ");
+ alignment = gtk_alignment_new(0, 0, 0, 0);
+ gtk_container_add(GTK_CONTAINER(alignment), label);
+
+ gtk_table_attach(GTK_TABLE(table),
+ alignment, 0, 1, 2, 3, GTK_FILL, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
+
+ ctk_gvo->input_video_format_text_entry = gtk_entry_new();
+
+ gtk_widget_set_sensitive(ctk_gvo->input_video_format_text_entry, FALSE);
+ gtk_entry_set_width_chars
+ (GTK_ENTRY(ctk_gvo->input_video_format_text_entry),
+ max_input_video_format_text_entry_length());
+
+ init_input_video_format_text_entry(ctk_gvo);
+
+ gtk_table_attach(GTK_TABLE(table), ctk_gvo->input_video_format_text_entry,
+ 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
+
+ /* detect button */
+
+ button = gtk_toggle_button_new_with_label("Detect");
+
+ alignment = gtk_alignment_new(1, 1, 0, 0);
+
+ gtk_container_add(GTK_CONTAINER(alignment), button);
+ gtk_table_attach(GTK_TABLE(table), alignment,
+ 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
+
+ ctk_gvo->input_video_format_detect_button = button;
+
+ g_signal_connect(G_OBJECT(button), "toggled",
+ G_CALLBACK(detect_input), ctk_gvo);
+
+
+ /*
+ * Output options
+ */
+
+ frame = gtk_frame_new("Output Options");
+
+ gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
+
+ table = gtk_table_new(3, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 0);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 0);
+
+ gtk_container_add(GTK_CONTAINER(frame), table);
/* Output Video Format */
- menu = start_menu("Output Video Format: ", table, 1);
+ menu = start_menu("Output Video Format: ", table, 0);
- screen_width = NvCtrlGetScreenWidth(handle);
- screen_height = NvCtrlGetScreenHeight(handle);
+ ctk_gvo->screen_width = NvCtrlGetScreenWidth(handle);
+ ctk_gvo->screen_height = NvCtrlGetScreenHeight(handle);
+
+ /* get the width, height, and refresh rate for each format */
+
+ get_video_format_details(ctk_gvo);
n = 0;
for (i = 0; videoFormatNames[i].name; i++) {
- /* query the width/height needed for the video format */
-
- NvCtrlGetDisplayAttribute(handle,
- videoFormatNames[i].format,
- NV_CTRL_GVO_VIDEO_FORMAT_WIDTH,
- &width);
-
- NvCtrlGetDisplayAttribute(handle,
- videoFormatNames[i].format,
- NV_CTRL_GVO_VIDEO_FORMAT_HEIGHT,
- &height);
+ /*
+ * runtime check that videoFormatDetails[] and
+ * videoFormatNames[] are in sync
+ */
- if ((width > screen_width) ||
- (height > screen_height)) {
+ if (videoFormatDetails[i].format != videoFormatNames[i].format) {
+ nv_error_msg("GVO format tables out of alignment!");
+ return NULL;
+ }
+
+ /* check that the current X screen can support width and height */
+
+ width = videoFormatDetails[i].width;
+ height = videoFormatDetails[i].height;
+
+ if ((width > ctk_gvo->screen_width) ||
+ (height > ctk_gvo->screen_height)) {
nv_warning_msg("Not exposing GVO video format '%s' (this video "
"format requires a resolution of atleast %d x %d, "
"but the current X screen is %d x %d)",
videoFormatNames[i].name,
- width, height, screen_width, screen_height);
+ width, height, ctk_gvo->screen_width,
+ ctk_gvo->screen_height);
continue;
}
-
+
ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu),
videoFormatNames[i].name,
videoFormatNames[i].format);
n++;
}
- finish_menu(menu, table, 1);
+ finish_menu(menu, table, 0);
if (!n) {
nv_warning_msg("No GVO video formats will fit the current X screen of "
"%d x %d; please create an X screen of atleast "
"720 x 487; not exposing GVO page.\n",
- screen_width, screen_height);
+ ctk_gvo->screen_width, ctk_gvo->screen_height);
return NULL;
}
@@ -358,7 +576,7 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
/* Output Data Format */
- menu = start_menu("Output Data Format: ", table, 2);
+ menu = start_menu("Output Data Format: ", table, 1);
for (i = 0; dataFormatNames[i].name; i++) {
ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu),
@@ -366,7 +584,7 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
dataFormatNames[i].format);
}
- finish_menu(menu, table, 2);
+ finish_menu(menu, table, 1);
ctk_gvo->output_data_format_menu = menu;
@@ -378,69 +596,142 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
/*
- * Sync options
+ * Synchronization Delay
*/
- frame = gtk_frame_new("Sync Options");
+ frame = gtk_frame_new("Synchronization Delay");
gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
- hbox = gtk_hbox_new(FALSE, 0);
- gtk_container_add(GTK_CONTAINER(frame), hbox);
+ table = gtk_table_new(2, 2, FALSE);
- /* menu */
+ gtk_table_set_row_spacings(GTK_TABLE(table), 3);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 15);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ get_video_format_resolution(ctk_gvo->input_video_format, &width, &height);
+
+ /* NV_CTRL_GVO_SYNC_DELAY_PIXELS */
+
+ label = gtk_label_new("HSync Delay (in pixels): ");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
+ GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_SYNC_DELAY_PIXELS, &val);
+ if (ret != NvCtrlSuccess) val = 0;
+
+ if (width < 1) width = 1;
- menu = ctk_drop_down_menu_new(0);
+ ctk_gvo->hsync_delay_spin_button =
+ gtk_spin_button_new_with_range(0.0, width, 1);
+
+ gtk_spin_button_set_value
+ (GTK_SPIN_BUTTON(ctk_gvo->hsync_delay_spin_button), val);
- ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu), "SDI Sync",
- SYNC_FORMAT_SDI);
+ g_signal_connect(G_OBJECT(ctk_gvo->hsync_delay_spin_button),
+ "value-changed",
+ G_CALLBACK(hsync_delay_changed), ctk_gvo);
+
+ gtk_table_attach(GTK_TABLE(table), ctk_gvo->hsync_delay_spin_button,
+ 1, 2, 0, 1,
+ GTK_FILL /*| GTK_EXPAND*/, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
- ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu), "COMP Sync",
- SYNC_FORMAT_COMP_AUTO);
+ /* NV_CTRL_GVO_SYNC_DELAY_LINES */
- ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu),
- "COMP Sync (Bi-level)",
- SYNC_FORMAT_COMP_BI_LEVEL);
+ label = gtk_label_new("VSync Delay (in lines): ");
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
+ GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_SYNC_DELAY_LINES, &val);
+ if (ret != NvCtrlSuccess) val = 0;
- ctk_drop_down_menu_append_item(CTK_DROP_DOWN_MENU(menu),
- "COMP Sync (Tri-level)",
- SYNC_FORMAT_COMP_TRI_LEVEL);
+ if (height < 1) height = 1;
+
+ ctk_gvo->vsync_delay_spin_button =
+ gtk_spin_button_new_with_range(0.0, height, 1);
- ctk_drop_down_menu_finalize(CTK_DROP_DOWN_MENU(menu));
+ gtk_spin_button_set_value
+ (GTK_SPIN_BUTTON(ctk_gvo->vsync_delay_spin_button), val);
- gtk_box_pack_start(GTK_BOX(hbox), menu, FALSE, FALSE, TABLE_PADDING);
+ g_signal_connect(G_OBJECT(ctk_gvo->vsync_delay_spin_button),
+ "value-changed",
+ G_CALLBACK(vsync_delay_changed), ctk_gvo);
- ctk_gvo->sync_format_menu = menu;
+ gtk_table_attach(GTK_TABLE(table), ctk_gvo->vsync_delay_spin_button,
+ 1, 2, 1, 2,
+ GTK_FILL /*| GTK_EXPAND*/, GTK_FILL,
+ TABLE_PADDING, TABLE_PADDING);
- /* input type */
+ /*
+ * Region of Interest
+ */
+
+ frame = gtk_frame_new("Region of Interest");
+
+ gtk_box_pack_start(GTK_BOX(object), frame, FALSE, FALSE, 0);
- ctk_gvo->input_video_format_text_entry = gtk_entry_new();
- gtk_box_pack_start(GTK_BOX(hbox), ctk_gvo->input_video_format_text_entry,
- TRUE, TRUE, TABLE_PADDING);
- gtk_widget_set_sensitive(ctk_gvo->input_video_format_text_entry, FALSE);
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
+
+ get_video_format_resolution(ctk_gvo->output_video_format, &width, &height);
- /* XXX maybe set the text entry to the maximum format name length */
+ /* NV_CTRL_GVO_X_SCREEN_PAN_X */
- init_input_video_format_text_entry(ctk_gvo);
+ label = gtk_label_new("X Offset: ");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, TABLE_PADDING);
- g_signal_connect(G_OBJECT(ctk_gvo->sync_format_menu),
- "changed", G_CALLBACK(sync_format_changed),
- (gpointer) ctk_gvo);
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_X_SCREEN_PAN_X, &val);
+ if (ret != NvCtrlSuccess) val = 0;
- /* detect button */
-
- button = gtk_toggle_button_new_with_label("Detect");
+ width = ctk_gvo->screen_width - width;
+ if (width < 1) width = 1;
+
+ ctk_gvo->x_offset_spin_button =
+ gtk_spin_button_new_with_range(0.0, width, 1);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, TABLE_PADDING);
+ gtk_spin_button_set_value
+ (GTK_SPIN_BUTTON(ctk_gvo->x_offset_spin_button), val);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->x_offset_spin_button),
+ "value-changed",
+ G_CALLBACK(x_offset_changed), ctk_gvo);
+
+ gtk_box_pack_start(GTK_BOX(hbox), ctk_gvo->x_offset_spin_button,
+ FALSE, FALSE, TABLE_PADDING);
+
+ /* NV_CTRL_GVO_X_SCREEN_PAN_Y */
- ctk_gvo->input_video_format_detect_button = button;
+ label = gtk_label_new("Y Offset: ");
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, TABLE_PADDING);
+
+ ret = NvCtrlGetAttribute(handle, NV_CTRL_GVO_X_SCREEN_PAN_Y, &val);
+ if (ret != NvCtrlSuccess) val = 0;
+
+ height = ctk_gvo->screen_height - height;
+ if (height < 1) height = 1;
+
+ ctk_gvo->y_offset_spin_button =
+ gtk_spin_button_new_with_range(0.0, height, 1);
- g_signal_connect(G_OBJECT(button), "toggled",
- G_CALLBACK(input_video_format_detect_button_toggled),
- ctk_gvo);
+ gtk_spin_button_set_value
+ (GTK_SPIN_BUTTON(ctk_gvo->y_offset_spin_button), val);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->y_offset_spin_button),
+ "value-changed",
+ G_CALLBACK(y_offset_changed), ctk_gvo);
+
+ gtk_box_pack_start(GTK_BOX(hbox), ctk_gvo->y_offset_spin_button,
+ FALSE, FALSE, TABLE_PADDING);
- /* "Enable SDI Output" button */
+ /*
+ * "Enable SDI Output" button
+ */
create_toggle_sdi_output_button(ctk_gvo);
@@ -450,6 +741,27 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
gtk_box_pack_start(GTK_BOX(object), alignment, TRUE, TRUE, 0);
+ /* create the watch cursor (for use when "Detect" is toggled" */
+
+ ctk_gvo->wait_cursor = gdk_cursor_new(GDK_WATCH);
+
+ /*
+ * register a timeout function (directly with glib, not through
+ * ctk_config) to update the LEDs
+ */
+
+ g_timeout_add(UPDATE_GVO_BANNER_TIME_INTERVAL, update_gvo_banner,
+ &ctk_gvo->banner);
+
+ ctk_config_add_timer(ctk_gvo->ctk_config,
+ DEFAULT_GVO_PROBE_TIME_INTERVAL,
+ "Graphics To Video Probe",
+ (GSourceFunc) probe,
+ (gpointer) ctk_gvo);
+
+
+ register_for_gvo_events(ctk_gvo);
+
/* show the GVO widget */
gtk_widget_show_all(GTK_WIDGET(ctk_gvo));
@@ -459,8 +771,31 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
} /* ctk_gvo_new() */
+void ctk_gvo_select(GtkWidget *widget)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(widget);
+
+ gtk_container_add(GTK_CONTAINER(ctk_gvo->banner_frame),
+ ctk_gvo->banner.table);
+
+ ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) probe);
+}
+
+void ctk_gvo_unselect(GtkWidget *widget)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(widget);
+
+ gtk_container_remove(GTK_CONTAINER(ctk_gvo->banner_frame),
+ ctk_gvo->banner.table);
+
+ ctk_config_start_timer(ctk_gvo->ctk_config, (GSourceFunc) probe);
+}
+
/**************************************************************************/
+/*
+ * code for handling the GVO banner
+ */
#define GVO_BANNER_LEFT 0
@@ -485,8 +820,25 @@ GtkWidget* ctk_gvo_new(NvCtrlAttributeHandle *handle,
#define GVO_BANNER_COUNT 18
+/* value for controlling LED state */
+
+#define GVO_LED_VID_OUT_NOT_IN_USE 0
+#define GVO_LED_VID_OUT_HD_MODE 1
+#define GVO_LED_VID_OUT_SD_MODE 2
+
+#define GVO_LED_SDI_SYNC_NONE 0
+#define GVO_LED_SDI_SYNC_HD 1
+#define GVO_LED_SDI_SYNC_SD 2
+#define GVO_LED_SDI_SYNC_ERROR 3
+
+#define GVO_LED_COMP_SYNC_NONE 0
+#define GVO_LED_COMP_SYNC_SYNC 1
+
+
static GtkWidget *__gvo_banner_widget[GVO_BANNER_COUNT];
+/* XXX we can get rid of a bunch of these images */
+
static const nv_image_t *__gvo_banner_imgs[GVO_BANNER_COUNT] = {
&gvo_banner_left_image,
&gvo_banner_vid1_green_image,
@@ -508,13 +860,47 @@ static const nv_image_t *__gvo_banner_imgs[GVO_BANNER_COUNT] = {
&gvo_banner_right_image,
};
-static void init_gvo_banner(CtkGvo *ctk_gvo)
+
+/*
+ * pack_gvo_banner_slot() - update slot 'slot' in the banner with the
+ * image specified by 'new'
+ */
+
+static void pack_gvo_banner_slot(CtkGvoBanner *banner,
+ gint slot, gint new, gint old)
+{
+ if (old >= 0) {
+ gtk_container_remove(GTK_CONTAINER(banner->slots[slot]),
+ __gvo_banner_widget[old]);
+ }
+
+ gtk_box_pack_start(GTK_BOX(banner->slots[slot]),
+ __gvo_banner_widget[new], TRUE, TRUE, 0);
+
+} /* pack_gvo_banner_slot() */
+
+
+
+/*
+ * init_gvo_banner() - initialize the GVO banner
+ */
+
+static void init_gvo_banner(CtkGvoBanner *banner)
{
int i;
const nv_image_t *img;
guint8 *image_buffer = NULL;
+ banner->table = gtk_table_new(1, 6, FALSE);
+ gtk_object_ref(GTK_OBJECT(banner->table));
+
+ gtk_table_set_row_spacings(GTK_TABLE(banner->table), 0);
+ gtk_table_set_col_spacings(GTK_TABLE(banner->table), 0);
+
for (i = 0; i < GVO_BANNER_COUNT; i++) {
+
+ if (__gvo_banner_widget[i]) continue;
+
img = __gvo_banner_imgs[i];
image_buffer = decompress_image_data(img);
@@ -524,28 +910,251 @@ static void init_gvo_banner(CtkGvo *ctk_gvo)
FALSE, 8, img->width, img->height,
img->width * img->bytes_per_pixel,
free_decompressed_image, NULL));
+
+ /*
+ * XXX increment the reference count, so that when we do
+ * gtk_container_remove() later, it doesn't get destroyed
+ */
+
+ gtk_object_ref(GTK_OBJECT(__gvo_banner_widget[i]));
+
+
+ gtk_widget_show(__gvo_banner_widget[i]);
}
-}
-static void pack_gvo_banner_slot(CtkGvo *ctk_gvo, int n,
- int banner_image_index)
+ /*
+ * fill in the banner table with initial images, and the
+ * containers for the LED images that will get swapped in and out.
+ */
+
+ gtk_table_attach(GTK_TABLE(banner->table),
+ __gvo_banner_widget[GVO_BANNER_LEFT],
+ 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+
+
+ for (i = 0; i < 4; i++) {
+ banner->slots[i] = gtk_hbox_new(FALSE, 0);
+ gtk_object_ref(GTK_OBJECT(banner->slots[i]));
+ gtk_table_attach(GTK_TABLE(banner->table), banner->slots[i],
+ i+1, i+2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+ }
+
+ gtk_table_attach(GTK_TABLE(banner->table),
+ __gvo_banner_widget[GVO_BANNER_RIGHT],
+ 5, 6, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+
+
+ /*
+ * initialize LED state
+ */
+
+ banner->state.vid1 = GVO_LED_VID_OUT_NOT_IN_USE;
+ banner->state.vid2 = GVO_LED_VID_OUT_NOT_IN_USE;
+ banner->state.sdi = GVO_LED_SDI_SYNC_NONE;
+ banner->state.comp = GVO_LED_COMP_SYNC_NONE;
+
+ banner->img.vid1 = GVO_BANNER_VID1_GREY;
+ banner->img.vid2 = GVO_BANNER_VID2_GREY;
+ banner->img.sdi = GVO_BANNER_SDI_SYNC_GREY;
+ banner->img.comp = GVO_BANNER_COMP_SYNC_GREY;
+
+ pack_gvo_banner_slot(banner, 0, banner->img.vid1, -1);
+ pack_gvo_banner_slot(banner, 1, banner->img.vid2, -1);
+ pack_gvo_banner_slot(banner, 2, banner->img.sdi, -1);
+ pack_gvo_banner_slot(banner, 3, banner->img.comp, -1);
+
+ gtk_widget_show_all(GTK_WIDGET(banner->table));
+
+} /* init_gvo_banner() */
+
+
+
+/*
+ * update_gvo_banner() - called by a timer to update the LED images
+ * based on current state
+ */
+
+static gboolean update_gvo_banner(gpointer data)
{
- GtkWidget *image = __gvo_banner_widget[banner_image_index];
+ guint8 old, new;
+ CtkGvoBanner *banner = (CtkGvoBanner *) data;
+
+ /*
+ * we store the flashing state here:
+ *
+ * 0 == no LED is currently flashing
+ * 1 == some LED is flashing; currently "on" (lit)
+ * 2 == some LED is flashing; currently "off" (grey)
+ *
+ * this is used to track the current state, so that we can make
+ * all LEDs flash at the same time.
+ */
+
+ gint flashing = 0;
- gtk_table_attach(GTK_TABLE(ctk_gvo->banner_table),
- image, n, n+1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
-}
+ /* Vid 1 out */
-static void pack_gvo_banner(CtkGvo *ctk_gvo)
+ old = banner->img.vid1;
+
+ if (banner->state.vid1 == GVO_LED_VID_OUT_HD_MODE) {
+ new = (old == GVO_BANNER_VID1_GREY) ?
+ GVO_BANNER_VID1_GREEN: GVO_BANNER_VID1_GREY;
+ flashing = (new == GVO_BANNER_VID1_GREY) ? 2 : 1;
+ } else if (banner->state.vid1 == GVO_LED_VID_OUT_SD_MODE) {
+ new = (old == GVO_BANNER_VID1_GREY) ?
+ GVO_BANNER_VID1_YELLOW: GVO_BANNER_VID1_GREY;
+ flashing = (new == GVO_BANNER_VID1_GREY) ? 2 : 1;
+ } else {
+ new = GVO_BANNER_VID1_GREY;
+ }
+
+ if (old != new) {
+ pack_gvo_banner_slot(banner, 0, new, old);
+ banner->img.vid1 = new;
+ }
+
+ /* Vid 1 out */
+
+ old = banner->img.vid2;
+
+ if (banner->state.vid2 == GVO_LED_VID_OUT_HD_MODE) {
+ if (flashing) {
+ new = (flashing == 1) ?
+ GVO_BANNER_VID2_GREEN: GVO_BANNER_VID2_GREY;
+ } else {
+ new = (old == GVO_BANNER_VID2_GREY) ?
+ GVO_BANNER_VID2_GREEN: GVO_BANNER_VID2_GREY;
+ flashing = (new == GVO_BANNER_VID2_GREY) ? 2 : 1;
+ }
+ } else if (banner->state.vid2 == GVO_LED_VID_OUT_SD_MODE) {
+ if (flashing) {
+ new = (flashing == 1) ?
+ GVO_BANNER_VID2_YELLOW: GVO_BANNER_VID2_GREY;
+ } else {
+ new = (old == GVO_BANNER_VID2_GREY) ?
+ GVO_BANNER_VID2_YELLOW: GVO_BANNER_VID2_GREY;
+ flashing = (new == GVO_BANNER_VID2_GREY) ? 2 : 1;
+ }
+ } else {
+ new = GVO_BANNER_VID2_GREY;
+ }
+
+ if (old != new) {
+ pack_gvo_banner_slot(banner, 1, new, old);
+ banner->img.vid2 = new;
+ }
+
+ /* SDI sync */
+
+ old = banner->img.sdi;
+
+ if (banner->state.sdi == GVO_LED_SDI_SYNC_HD) {
+ if (flashing) {
+ new = (flashing == 1) ?
+ GVO_BANNER_SDI_SYNC_GREEN : GVO_BANNER_SDI_SYNC_GREY;
+ } else {
+ new = (banner->img.sdi == GVO_BANNER_SDI_SYNC_GREY) ?
+ GVO_BANNER_SDI_SYNC_GREEN : GVO_BANNER_SDI_SYNC_GREY;
+ flashing = (new == GVO_BANNER_SDI_SYNC_GREY) ? 2 : 1;
+ }
+ } else if (banner->state.sdi == GVO_LED_SDI_SYNC_SD) {
+ if (flashing) {
+ new = (flashing == 1) ?
+ GVO_BANNER_SDI_SYNC_YELLOW : GVO_BANNER_SDI_SYNC_GREY;
+ } else {
+ new = (banner->img.sdi == GVO_BANNER_SDI_SYNC_GREY) ?
+ GVO_BANNER_SDI_SYNC_YELLOW : GVO_BANNER_SDI_SYNC_GREY;
+ flashing = (new == GVO_BANNER_SDI_SYNC_GREY) ? 2 : 1;
+ }
+ } else if (banner->state.sdi == GVO_LED_SDI_SYNC_ERROR) {
+ new = GVO_BANNER_SDI_SYNC_YELLOW;
+ } else {
+ new = GVO_BANNER_SDI_SYNC_GREY;
+ }
+
+ if (old != new) {
+ pack_gvo_banner_slot(banner, 2, new, old);
+ banner->img.sdi = new;
+ }
+
+ /* COMP sync */
+
+ old = banner->img.comp;
+
+ if (banner->state.comp == GVO_LED_COMP_SYNC_SYNC) {
+ if (flashing) {
+ new = (flashing == 1) ?
+ GVO_BANNER_COMP_SYNC_GREEN : GVO_BANNER_COMP_SYNC_GREY;
+ } else {
+ new = (banner->img.comp == GVO_BANNER_COMP_SYNC_GREY) ?
+ GVO_BANNER_COMP_SYNC_GREEN : GVO_BANNER_COMP_SYNC_GREY;
+ }
+ } else {
+ new = GVO_BANNER_COMP_SYNC_GREY;
+ }
+
+ if (old != new) {
+ pack_gvo_banner_slot(banner, 3, new, old);
+ banner->img.comp = new;
+ }
+
+ return TRUE;
+
+} /* update_gvo_banner() */
+
+
+
+/*
+ * update_gvo_banner_video_output() - update banner state accordingly,
+ * based on the current output_video_format and output_data_format
+ */
+
+static void update_gvo_banner_video_output(CtkGvoBanner *banner,
+ gint output_video_format,
+ gint output_data_format)
{
- pack_gvo_banner_slot(ctk_gvo, 0, GVO_BANNER_LEFT);
- pack_gvo_banner_slot(ctk_gvo, 1, GVO_BANNER_VID1_RED);
- pack_gvo_banner_slot(ctk_gvo, 2, GVO_BANNER_VID2_GREY);
- pack_gvo_banner_slot(ctk_gvo, 3, GVO_BANNER_SDI_SYNC_GREEN);
- pack_gvo_banner_slot(ctk_gvo, 4, GVO_BANNER_COMP_SYNC_YELLOW);
- pack_gvo_banner_slot(ctk_gvo, 5, GVO_BANNER_RIGHT);
-}
+ if (output_video_format == NV_CTRL_GVO_VIDEO_FORMAT_NONE) {
+ banner->state.vid1 = GVO_LED_VID_OUT_NOT_IN_USE;
+ banner->state.vid2 = GVO_LED_VID_OUT_NOT_IN_USE;
+ } else if ((output_video_format ==
+ NV_CTRL_GVO_VIDEO_FORMAT_480I_59_94_SMPTE259_NTSC) ||
+ (output_video_format ==
+ NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL)) {
+ banner->state.vid1 = GVO_LED_VID_OUT_SD_MODE;
+ banner->state.vid2 = GVO_LED_VID_OUT_SD_MODE;
+ } else {
+ banner->state.vid1 = GVO_LED_VID_OUT_HD_MODE;
+ banner->state.vid2 = GVO_LED_VID_OUT_HD_MODE;
+ }
+
+ if (output_data_format == NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB422) {
+ banner->state.vid2 = GVO_LED_VID_OUT_NOT_IN_USE;
+ }
+} /* update_gvo_banner_video_output() */
+
+
+
+/*
+ * update_gvo_banner_video_input() - update banner state accordingly,
+ * based on the current sdi and composite input
+ */
+
+static void update_gvo_banner_video_input(CtkGvoBanner *banner,
+ gint sdi, gint comp)
+{
+ if (sdi == NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_HD) {
+ banner->state.sdi = GVO_LED_SDI_SYNC_HD;
+ } else if (sdi == NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_SD) {
+ banner->state.sdi = GVO_LED_SDI_SYNC_SD;
+ } else {
+ banner->state.sdi = GVO_LED_SDI_SYNC_NONE;
+ }
+
+ banner->state.comp = comp ?
+ GVO_LED_COMP_SYNC_SYNC : GVO_LED_COMP_SYNC_NONE;
+
+} /* update_gvo_banner_video_input() */
@@ -585,25 +1194,49 @@ static void finish_menu(GtkWidget *menu, GtkWidget *table, const gint row)
/**************************************************************************/
+/*
+ * sync_mode_changed() - callback when the SyncMode menu changes
+ */
static void sync_mode_changed(CtkDropDownMenu *menu, gpointer user_data)
{
CtkGvo *ctk_gvo = CTK_GVO(user_data);
gint value;
+ char *name;
value = ctk_drop_down_menu_get_current_value(menu);
- /* XXX confirm that the value is valid */
-
- //printf("%s(): %d\n", __FUNCTION__, value);
-
+ switch (value) {
+ case NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING: name = "Free Running"; break;
+ case NV_CTRL_GVO_SYNC_MODE_GENLOCK: name = "GenLock"; break;
+ case NV_CTRL_GVO_SYNC_MODE_FRAMELOCK: name = "FrameLock"; break;
+ default: return;
+ }
NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_SYNC_MODE, value);
- /* XXX statusbar */
+ if (value != NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING) {
+ NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_SYNC_SOURCE,
+ ctk_gvo->sync_source);
+ }
- /* XXX update the output video format menu */
-}
+ ctk_gvo->sync_mode = value;
+
+ update_output_video_format_menu(ctk_gvo);
+
+ update_sync_format_menu(ctk_gvo);
+
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Sync Mode set to %s.", name);
+
+} /* sync_mode_changed() */
+
+
+
+/*
+ * output_video_format_changed() - callback when the output video
+ * format menu changes
+ */
static void output_video_format_changed(CtkDropDownMenu *menu,
gpointer user_data)
@@ -613,16 +1246,37 @@ static void output_video_format_changed(CtkDropDownMenu *menu,
value = ctk_drop_down_menu_get_current_value(menu);
- /* XXX confirm that the value is valid */
+ if (!(ctk_gvo->valid_putput_video_format_mask & (1 << value))) {
+ ctk_config_statusbar_message(ctk_gvo->ctk_config, "Invalid "
+ "Output Video Format: %s; ignoring.",
+ get_video_format_name(value));
+ return;
+ }
- //printf("%s(): %d\n", __FUNCTION__, value);
-
NvCtrlSetAttribute(ctk_gvo->handle,
NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT, value);
- /* XXX statusbar */
+ post_output_video_format_changed(ctk_gvo, value);
+
+} /* output_video_format_changed() */
+
+
+static void post_output_video_format_changed(CtkGvo *ctk_gvo, gint value)
+{
+ ctk_gvo->output_video_format = value;
+
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Output Video Format set to: %s.",
+ get_video_format_name(value));
}
+
+
+/*
+ * output_data_format_changed() - callback when the output data format
+ * menu changes
+ */
+
static void output_data_format_changed(CtkDropDownMenu *menu,
gpointer user_data)
{
@@ -631,17 +1285,21 @@ static void output_data_format_changed(CtkDropDownMenu *menu,
value = ctk_drop_down_menu_get_current_value(menu);
- /* XXX confirm that the value is valid */
-
- //printf("%s(): %d\n", __FUNCTION__, value);
-
-
NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_DATA_FORMAT, value);
- /* XXX statusbar */
-}
+ post_output_data_format_changed(ctk_gvo, value);
+
+} /* output_data_format_changed() */
+
+static void post_output_data_format_changed(CtkGvo *ctk_gvo, gint value)
+{
+ ctk_gvo->output_data_format = value;
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Output Data Format set to: %s.",
+ get_data_format_name(value));
+}
/**************************************************************************/
@@ -720,6 +1378,8 @@ static void init_sync_mode_menu(CtkGvo *ctk_gvo)
val = NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING;
}
+ ctk_gvo->sync_mode = val;
+
/* set the current mode in the menu */
ctk_drop_down_menu_set_current_value
@@ -738,7 +1398,7 @@ static void init_sync_mode_menu(CtkGvo *ctk_gvo)
ret = NvCtrlGetAttribute(ctk_gvo->handle,
NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED, &sdi);
if (ret != NvCtrlSuccess) {
- sdi = NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED;
+ sdi = NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_NONE;
}
/* update the menu */
@@ -755,12 +1415,11 @@ static void init_sync_mode_menu(CtkGvo *ctk_gvo)
* possibly update which entry is current.
*/
-static void update_output_video_format_menu(CtkGvo *ctk_gvo,
- const gint current)
+static void update_output_video_format_menu(CtkGvo *ctk_gvo)
{
ReturnStatus ret;
NVCTRLAttributeValidValuesRec valid;
- gint bitmask, i;
+ gint bitmask, i, refresh_rate;
gboolean sensitive, current_not_available = FALSE;
/* retrieve the currently available values */
@@ -777,6 +1436,38 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo,
bitmask = valid.u.bits.ints;
}
+ /*
+ * if the SyncMode is genlock or framelock, trim the bitmask
+ * accordingly: if GENLOCK, then the only bit allowed is the bit
+ * that corresponds to the exact input mode; if FRAMELOCK, then
+ * only modes with the same refresh rate as the input mode are
+ * allowed.
+ */
+
+ if ((ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_GENLOCK) &&
+ (ctk_gvo->input_video_format != NV_CTRL_GVO_VIDEO_FORMAT_NONE)) {
+ bitmask &= (1 << ctk_gvo->input_video_format);
+ }
+
+ if ((ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_FRAMELOCK) &&
+ (ctk_gvo->input_video_format != NV_CTRL_GVO_VIDEO_FORMAT_NONE)) {
+
+ refresh_rate = 0;
+
+ for (i = 0; videoFormatDetails[i].format != -1; i++) {
+ if (videoFormatDetails[i].format == ctk_gvo->input_video_format) {
+ refresh_rate = videoFormatDetails[i].rate;
+ break;
+ }
+ }
+
+ for (i = 0; videoFormatDetails[i].format != -1; i++) {
+ if (videoFormatDetails[i].rate != refresh_rate) {
+ bitmask &= ~(1 << videoFormatDetails[i].format);
+ }
+ }
+ }
+
/*
* loop over each video format; if that format is set in the
* bitmask, then it is available
@@ -795,7 +1486,8 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo,
/* if the current video is not sensitive, take note */
- if ((current == videoFormatNames[i].format) && !sensitive) {
+ if ((ctk_gvo->output_video_format == videoFormatNames[i].format) &&
+ !sensitive) {
current_not_available = TRUE;
}
}
@@ -804,7 +1496,7 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo,
* if the current video is not available, then make the first
* available format current
*/
-
+
if (current_not_available && bitmask) {
for (i = 0; videoFormatNames[i].name; i++) {
if ((1 << videoFormatNames[i].format) & bitmask) {
@@ -817,15 +1509,101 @@ static void update_output_video_format_menu(CtkGvo *ctk_gvo,
(CTK_DROP_DOWN_MENU(ctk_gvo->output_video_format_menu),
videoFormatNames[i].format);
+ ctk_gvo->output_video_format = videoFormatNames[i].format;
+
break;
}
}
}
+
+ /*
+ * cache the bitmask
+ */
+
+ ctk_gvo->valid_putput_video_format_mask = bitmask;
+
} /* update_output_video_format_menu() */
/*
+ * init_sync_format_menu() - initialize the sync format menu
+ */
+
+static void init_sync_format_menu(CtkGvo *ctk_gvo)
+{
+ ReturnStatus ret;
+ gint sync_source, sync_mode, comp_mode, val;
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_SYNC_SOURCE,
+ &sync_source);
+
+ if (ret != NvCtrlSuccess) {
+ sync_source = NV_CTRL_GVO_SYNC_SOURCE_SDI;
+ }
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_SYNC_MODE,
+ &sync_mode);
+
+ if (ret != NvCtrlSuccess) {
+ sync_mode = NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING;
+ }
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE,
+ &comp_mode);
+
+ if (ret != NvCtrlSuccess) {
+ comp_mode = NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_AUTO;
+ }
+
+ if (sync_source == NV_CTRL_GVO_SYNC_SOURCE_SDI) {
+ val = SYNC_FORMAT_SDI;
+ } else if (comp_mode ==
+ NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_AUTO) {
+ val = SYNC_FORMAT_COMP_AUTO;
+ } else if (comp_mode ==
+ NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_BI_LEVEL) {
+ val = SYNC_FORMAT_COMP_BI_LEVEL;
+ } else if (comp_mode ==
+ NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_TRI_LEVEL){
+ val = SYNC_FORMAT_COMP_TRI_LEVEL;
+ } else {
+ val = SYNC_FORMAT_SDI; // should not get here
+ }
+
+ ctk_drop_down_menu_set_current_value
+ (CTK_DROP_DOWN_MENU(ctk_gvo->sync_format_menu), val);
+
+ if (sync_mode == NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING) {
+ ctk_gvo->sync_format_sensitive = FALSE;
+ } else {
+ ctk_gvo->sync_format_sensitive = TRUE;
+ }
+
+ ctk_gvo->sync_source = sync_source;
+
+ gtk_widget_set_sensitive(ctk_gvo->sync_format_menu,
+ ctk_gvo->sync_format_sensitive);
+
+} /* init_sync_format_menu() */
+
+
+static void update_sync_format_menu(CtkGvo *ctk_gvo)
+{
+ if (ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING) {
+ ctk_gvo->sync_format_sensitive = FALSE;
+ } else {
+ ctk_gvo->sync_format_sensitive = TRUE;
+ }
+
+ gtk_widget_set_sensitive(ctk_gvo->sync_format_menu,
+ ctk_gvo->sync_format_sensitive);
+}
+
+/*
* init_output_video_format_menu() - initialize the output video
* format menu: set the currently active menu entry and update the
* sensitivity of all entries.
@@ -845,7 +1623,9 @@ static void init_output_video_format_menu(CtkGvo *ctk_gvo)
ctk_drop_down_menu_set_current_value
(CTK_DROP_DOWN_MENU(ctk_gvo->output_video_format_menu), val);
- update_output_video_format_menu(ctk_gvo, val);
+ ctk_gvo->output_video_format = val;
+
+ update_output_video_format_menu(ctk_gvo);
} /* init_output_video_format_menu() */
@@ -983,6 +1763,8 @@ static void create_toggle_sdi_output_button(CtkGvo *ctk_gvo)
ctk_gvo->toggle_sdi_output_button = button;
+ ctk_gvo->sdi_output_enabled = FALSE;
+
g_signal_connect(G_OBJECT(button), "toggled",
G_CALLBACK(toggle_sdi_output_button),
GTK_OBJECT(ctk_gvo));
@@ -1040,30 +1822,53 @@ static void toggle_sdi_output_button(GtkWidget *button, gpointer user_data)
return;
}
+ post_toggle_sdi_output_button(ctk_gvo, enabled);
+
+} /* toggle_sdi_output_button() */
+
+
+static void post_toggle_sdi_output_button(CtkGvo *ctk_gvo, gboolean enabled)
+{
+ gint w, h;
+
if (enabled) {
gtk_container_remove(GTK_CONTAINER(ctk_gvo->toggle_sdi_output_button),
ctk_gvo->enable_sdi_output_label);
gtk_container_add(GTK_CONTAINER(ctk_gvo->toggle_sdi_output_button),
ctk_gvo->disable_sdi_output_label);
+
+ update_gvo_banner_video_output(&ctk_gvo->banner,
+ ctk_gvo->output_video_format,
+ ctk_gvo->output_data_format);
+
+ get_video_format_resolution(ctk_gvo->output_video_format, &w, &h);
+ update_gvo_current_info(ctk_gvo, w, h, CURRENT_SDI_STATE_IN_USE_BY_X);
+
} else {
gtk_container_remove(GTK_CONTAINER(ctk_gvo->toggle_sdi_output_button),
ctk_gvo->disable_sdi_output_label);
gtk_container_add(GTK_CONTAINER(ctk_gvo->toggle_sdi_output_button),
ctk_gvo->enable_sdi_output_label);
+
+ update_gvo_banner_video_output(&ctk_gvo->banner,
+ NV_CTRL_GVO_VIDEO_FORMAT_NONE,
+ ctk_gvo->output_data_format);
+
+ update_gvo_current_info(ctk_gvo, 0, 0, CURRENT_SDI_STATE_INACTIVE);
}
- gtk_widget_set_sensitive(ctk_gvo->sync_mode_menu, !enabled);
- gtk_widget_set_sensitive(ctk_gvo->output_video_format_menu, !enabled);
- gtk_widget_set_sensitive(ctk_gvo->output_data_format_menu, !enabled);
-
-
- // XXX set sensitivity
+
+ ctk_gvo->sdi_output_enabled = enabled;
- // status bar
+ set_gvo_sensitivity(ctk_gvo, !enabled,
+ SET_SENSITIVITY_EXCLUDE_ENABLE_BUTTON |
+ SET_SENSITIVITY_EXCLUDE_ROI_BUTTONS);
-} /* toggle_sdi_output_button() */
+ ctk_config_statusbar_message(ctk_gvo->ctk_config, "SDI Output %s.",
+ enabled ? "enabled" : "disabled");
+}
@@ -1074,7 +1879,8 @@ static void toggle_sdi_output_button(GtkWidget *button, gpointer user_data)
static void sync_format_changed(CtkDropDownMenu *menu, gpointer user_data)
{
CtkGvo *ctk_gvo = CTK_GVO(user_data);
- gint value, sync_source, mode;
+ gint i, value, sync_source, mode;
+ const char *name = "Unknown";
value = ctk_drop_down_menu_get_current_value(menu);
@@ -1099,10 +1905,22 @@ static void sync_format_changed(CtkDropDownMenu *menu, gpointer user_data)
return;
}
+ for (i = 0; syncFormatNames[i].name; i++) {
+ if (syncFormatNames[i].format == value) {
+ name = syncFormatNames[i].name;
+ break;
+ }
+ }
+
+ ctk_gvo->sync_source = sync_source;
+
NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_SYNC_SOURCE, sync_source);
NvCtrlSetAttribute(ctk_gvo->handle,
NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE, mode);
+ ctk_config_statusbar_message(ctk_gvo->ctk_config, "Sync Format set to "
+ "\"%s\".", name);
+
} /* sync_format_changed() */
@@ -1111,18 +1929,21 @@ static void sync_format_changed(CtkDropDownMenu *menu, gpointer user_data)
* update_input_video_format_text_entry() -
*/
-static void update_input_video_format_text_entry(CtkGvo *ctk_gvo,
- const gint input_video_format)
+static void update_input_video_format_text_entry(CtkGvo *ctk_gvo)
{
gint i;
- const gchar *str = "No Signal Detected";
-
- for (i = 0; videoFormatNames[i].name; i++) {
- if (videoFormatNames[i].format == input_video_format) {
- str = videoFormatNames[i].name;
+ const gchar *str;
+
+ if (ctk_gvo->sync_mode == NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING) {
+ str = "Free Running";
+ } else {
+ str = "No incoming signal detected";
+ for (i = 0; videoFormatNames[i].name; i++) {
+ if (videoFormatNames[i].format == ctk_gvo->input_video_format) {
+ str = videoFormatNames[i].name;
+ }
}
}
-
gtk_entry_set_text(GTK_ENTRY(ctk_gvo->input_video_format_text_entry), str);
} /* update_input_video_format_text_entry() */
@@ -1144,42 +1965,723 @@ static void init_input_video_format_text_entry(CtkGvo *ctk_gvo)
val = NV_CTRL_GVO_VIDEO_FORMAT_NONE;
}
- update_input_video_format_text_entry(ctk_gvo, val);
+ ctk_gvo->input_video_format = val;
+
+ update_input_video_format_text_entry(ctk_gvo);
} /* init_input_video_format_text_entry() */
/*
- * input_video_format_detect_button_toggled() -
+ * max_input_video_format_text_entry_length()
*/
-static void
-input_video_format_detect_button_toggled(GtkToggleButton *togglebutton,
- CtkGvo *ctk_gvo)
+static int max_input_video_format_text_entry_length(void)
{
- if (gtk_toggle_button_get_active(togglebutton)) {
+ gint i, tmp, max = 0;
+
+ for (i = 0; videoFormatNames[i].name; i++) {
+ tmp = strlen(videoFormatNames[i].name);
+ if (max < tmp) max = tmp;
+ }
+
+ return max;
+
+} /* max_input_video_format_text_entry_length() */
+
+
+
+/*
+ * detect_input() - if the Detect button is enabled, then enable
+ * INPUT_VIDEO_FORMAT_REACQUIRE, make everything else insensitive,
+ * switch to the wait cursor, and queue detect_input_done() to be
+ * called.
+ */
+
+static void detect_input(GtkToggleButton *togglebutton, CtkGvo *ctk_gvo)
+{
+ gboolean enabled;
+
+ enabled = gtk_toggle_button_get_active(togglebutton);
+
+ if (!enabled) return;
- /* XXX need to make the other widgets insensitive */
+ /* grab the server */
+
+ gtk_grab_add(ctk_gvo->input_video_format_detect_button);
- NvCtrlSetAttribute(ctk_gvo->handle,
- NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE,
- NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_TRUE);
+ /* change the cursor */
+
+ gdk_window_set_cursor
+ ((GTK_WIDGET(ctk_gvo->parent_window))->window,
+ ctk_gvo->wait_cursor);
+
+ /* make all other widgets insensitive */
+
+ set_gvo_sensitivity(ctk_gvo, FALSE,
+ SET_SENSITIVITY_EXCLUDE_DETECT_BUTTON);
+
+ /* enable REACQUIRE */
+
+ NvCtrlSetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE,
+ NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_TRUE);
+
+ /* update the statusbar */
+
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Detecting incoming signal...");
+
+ /* register the "done" function */
+
+ g_timeout_add(DEFAULT_DETECT_INPUT_TIME_INTERVAL,
+ detect_input_done, (gpointer) ctk_gvo);
+
+} /* detect_input() */
+
+
+
+/*
+ * detect_input_done() - done detecting; disable REACQUIRE, make all
+ * widgets sensitive again, and probe the new state
+ */
+
+static gint detect_input_done(gpointer data)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(data);
+
+ /* disable REACQUIRE */
+
+ NvCtrlSetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE,
+ NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_FALSE);
+
+ /* reprobe */
+
+ probe((gpointer) ctk_gvo);
+
+ /* un-press the detect button */
+
+ g_signal_handlers_block_by_func
+ (G_OBJECT(ctk_gvo->input_video_format_detect_button),
+ G_CALLBACK(detect_input),
+ (gpointer) ctk_gvo);
+
+ gtk_toggle_button_set_active
+ (GTK_TOGGLE_BUTTON(ctk_gvo->input_video_format_detect_button), FALSE);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(ctk_gvo->input_video_format_detect_button),
+ G_CALLBACK(detect_input),
+ (gpointer) ctk_gvo);
+
+ /* update the status bar */
+
+ ctk_config_statusbar_message(ctk_gvo->ctk_config,
+ "Done detecting incoming signal.");
+
+ /* restore sensitivity */
+
+ set_gvo_sensitivity(ctk_gvo, TRUE,
+ SET_SENSITIVITY_EXCLUDE_DETECT_BUTTON);
+
+ /* restore the cursor */
+
+ gdk_window_set_cursor((GTK_WIDGET(ctk_gvo->parent_window))->window,
+ NULL);
+
+ /* ungrab the server */
+
+ gtk_grab_remove(ctk_gvo->input_video_format_detect_button);
+
+ return FALSE;
+
+} /* detect_input_done() */
+
+
+
+
+/**************************************************************************/
+
+
+/*
+ * get_video_format_name() - return the name of the given video format
+ */
+
+static const char *get_video_format_name(const gint format)
+{
+ gint i;
+
+ for (i = 0; videoFormatNames[i].name; i++) {
+ if (videoFormatNames[i].format == format) {
+ return videoFormatNames[i].name;
+ }
+ }
+
+ return "Unknown";
+
+} /* get_video_format_name() */
+
+
+
+/*
+ * get_data_format_name() - return the name of the given data format
+ */
+
+static const char *get_data_format_name(const gint format)
+{
+ gint i;
+
+ for (i = 0; dataFormatNames[i].name; i++) {
+ if (dataFormatNames[i].format == format) {
+ return dataFormatNames[i].name;
+ }
+ }
+
+ return "Unknown";
+
+} /* get_data_format_name() */
+
+
+
+/*
+ * get_video_format_resolution() - return the width and height of the
+ * given video format
+ */
+
+static void get_video_format_resolution(const gint format, gint *w, gint *h)
+{
+ gint i;
+
+ *w = *h = 0;
+
+ for (i = 0; videoFormatDetails[i].format != -1; i++) {
+ if (videoFormatDetails[i].format == format) {
+ *w = videoFormatDetails[i].width;
+ *h = videoFormatDetails[i].height;
+ return;
+ }
+ }
+} /* get_video_format_resolution() */
+
+
+/*
+ * set_gvo_sensitivity() - set the sensitivity of all the GVO widgets
+ */
+
+static void set_gvo_sensitivity(CtkGvo *ctk_gvo,
+ gboolean sensitive, guint flags)
+{
+ gtk_widget_set_sensitive(ctk_gvo->sync_mode_menu, sensitive);
+ gtk_widget_set_sensitive(ctk_gvo->output_video_format_menu, sensitive);
+ gtk_widget_set_sensitive(ctk_gvo->output_data_format_menu, sensitive);
+ gtk_widget_set_sensitive(ctk_gvo->hsync_delay_spin_button, sensitive);
+ gtk_widget_set_sensitive(ctk_gvo->vsync_delay_spin_button, sensitive);
+
+ if (!(flags & SET_SENSITIVITY_EXCLUDE_ROI_BUTTONS)) {
+ gtk_widget_set_sensitive(ctk_gvo->x_offset_spin_button, sensitive);
+ gtk_widget_set_sensitive(ctk_gvo->y_offset_spin_button, sensitive);
+ }
+
+ if (!(flags & SET_SENSITIVITY_EXCLUDE_ENABLE_BUTTON)) {
+ gtk_widget_set_sensitive(ctk_gvo->toggle_sdi_output_button, sensitive);
+ }
+
+ if (!(flags & SET_SENSITIVITY_EXCLUDE_DETECT_BUTTON)) {
+ gtk_widget_set_sensitive(ctk_gvo->input_video_format_detect_button,
+ sensitive);
+ }
+
+ if (!sensitive || (sensitive && ctk_gvo->sync_format_sensitive)) {
+ gtk_widget_set_sensitive(ctk_gvo->sync_format_menu, sensitive);
+ }
+
+} /* set_gvo_sensitivity() */
+
+
+
+/*
+ * get_video_format_details() - initialize the videoFormatDetails[]
+ * table by querying each of refresh rate, width, and height from
+ * NV-CONTROL.
+ */
+
+static void get_video_format_details(CtkGvo *ctk_gvo)
+{
+ ReturnStatus ret;
+ gint i, val;
+
+ for (i = 0; videoFormatDetails[i].format != -1; i++) {
+
+ ret = NvCtrlGetDisplayAttribute(ctk_gvo->handle,
+ videoFormatDetails[i].format,
+ NV_CTRL_GVO_VIDEO_FORMAT_REFRESH_RATE,
+ &val);
+
+ if (ret != NvCtrlSuccess) val = 0;
+
+ videoFormatDetails[i].rate = val;
+
+ ret = NvCtrlGetDisplayAttribute(ctk_gvo->handle,
+ videoFormatDetails[i].format,
+ NV_CTRL_GVO_VIDEO_FORMAT_WIDTH,
+ &val);
+
+ if (ret != NvCtrlSuccess) val = 0;
+
+ videoFormatDetails[i].width = val;
+
+ ret = NvCtrlGetDisplayAttribute(ctk_gvo->handle,
+ videoFormatDetails[i].format,
+ NV_CTRL_GVO_VIDEO_FORMAT_HEIGHT,
+ &val);
+
+ if (ret != NvCtrlSuccess) val = 0;
+
+ videoFormatDetails[i].height = val;
+ }
+} /* get_video_format_details() */
+
+
+/**************************************************************************/
+
+
+/*
+ * update_gvo_current_info() -
+ */
+
+static void update_gvo_current_info(CtkGvo *ctk_gvo, gint w, gint h,
+ gint state)
+{
+ gchar res_string[64], state_string[64];
+
+ if (!ctk_gvo->current_resolution_label) return;
+ if (!ctk_gvo->current_state_label) return;
+
+ switch (state) {
+
+ case CURRENT_SDI_STATE_INACTIVE:
+ snprintf(res_string, 64, "Inactive");
+ snprintf(state_string, 64, "Inactive");
+ break;
+
+ case CURRENT_SDI_STATE_IN_USE_BY_X:
+ snprintf(res_string, 64, "%d x %d", w, h);
+ snprintf(state_string, 64, "In Use by X");
+ break;
+
+ case CURRENT_SDI_STATE_IN_USE_BY_GLX:
+ snprintf(res_string, 64, "%d x %d", w, h);
+ snprintf(state_string, 64, "In Use by GLX");
+ break;
+
+ default:
+ return;
+ }
+
+ gtk_label_set_text(GTK_LABEL(ctk_gvo->current_resolution_label),
+ res_string);
+
+ gtk_label_set_text(GTK_LABEL(ctk_gvo->current_state_label),
+ state_string);
+
+} /* update_gvo_current_info() */
+
+
+/*
+ * update_delay_spin_buttons() -
+ */
+
+static void update_delay_spin_buttons(CtkGvo *ctk_gvo)
+{
+ gint w, h;
+
+ get_video_format_resolution(ctk_gvo->input_video_format, &w, &h);
+
+ gtk_spin_button_set_range
+ (GTK_SPIN_BUTTON(ctk_gvo->hsync_delay_spin_button), 0, w);
+ gtk_spin_button_set_range
+ (GTK_SPIN_BUTTON(ctk_gvo->vsync_delay_spin_button), 0, h);
+
+} /* update_delay_spin_buttons() */
+
+
+
+/*
+ * hsync_delay_changed()
+ */
+
+static void hsync_delay_changed(GtkSpinButton *spinbutton, gpointer user_data)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(user_data);
+ gint val;
+
+ val = gtk_spin_button_get_value(spinbutton);
+
+ NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_SYNC_DELAY_PIXELS, val);
+
+} /* hsync_delay_changed() */
+
+
+/*
+ * vsync_delay_changed()
+ */
+
+static void vsync_delay_changed(GtkSpinButton *spinbutton, gpointer user_data)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(user_data);
+ gint val;
+
+ val = gtk_spin_button_get_value(spinbutton);
+
+ NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_SYNC_DELAY_LINES, val);
+
+} /* vsync_delay_changed() */
+
+
+
+static void update_offset_spin_buttons(CtkGvo *ctk_gvo)
+{
+ gint w, h, x, y;
+
+ get_video_format_resolution(ctk_gvo->output_video_format, &w, &h);
+
+ x = ctk_gvo->screen_width - w;
+ y = ctk_gvo->screen_height - h;
+
+ gtk_spin_button_set_range
+ (GTK_SPIN_BUTTON(ctk_gvo->x_offset_spin_button), 0, x);
+ gtk_spin_button_set_range
+ (GTK_SPIN_BUTTON(ctk_gvo->y_offset_spin_button), 0, y);
+
+} /* update_delay_spin_buttons() */
+
+
+
+/*
+ * x_offset_changed()
+ */
+
+static void x_offset_changed(GtkSpinButton *spinbutton, gpointer user_data)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(user_data);
+ gint val;
+
+ val = gtk_spin_button_get_value(spinbutton);
+
+ NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_X_SCREEN_PAN_X, val);
+
+} /* x_offset_changed() */
+
+
+
+/*
+ * y_offset_changed()
+ */
+
+static void y_offset_changed(GtkSpinButton *spinbutton, gpointer user_data)
+{
+ CtkGvo *ctk_gvo = CTK_GVO(user_data);
+ gint val;
+
+ val = gtk_spin_button_get_value(spinbutton);
+
+ NvCtrlSetAttribute(ctk_gvo->handle, NV_CTRL_GVO_X_SCREEN_PAN_Y, val);
+
+} /* y_offset_changed() */
+
+
+/**************************************************************************/
+
+/*
+ * probe() - query the incoming signal
+ */
+
+static gint probe(gpointer data)
+{
+ ReturnStatus ret;
+ gint input, sdi, comp;
+ CtkGvo *ctk_gvo = CTK_GVO(data);
+
+ /* query NV_CTRL_GVO_INPUT_VIDEO_FORMAT */
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_INPUT_VIDEO_FORMAT, &input);
+
+ if (ret != NvCtrlSuccess) {
+ input = NV_CTRL_GVO_VIDEO_FORMAT_NONE;
+ }
+
+ ctk_gvo->input_video_format = input;
+
+ /* query COMPOSITE_SYNC_INPUT_DETECTED */
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED, &comp);
+
+ if (ret != NvCtrlSuccess) {
+ comp = NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED_FALSE;
+ }
+
+ /* query SDI_SYNC_INPUT_DETECTED */
+
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED, &sdi);
+
+ if (ret != NvCtrlSuccess) {
+ sdi = NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_NONE;
+ }
+
+ /* update the input video format text entry */
+
+ update_input_video_format_text_entry(ctk_gvo);
+
+ if (!ctk_gvo->sdi_output_enabled) {
+
+ /* update the available SyncModes */
+
+ update_sync_mode_menu(ctk_gvo, comp, sdi, ctk_gvo->sync_mode);
+
+ /* update the available output video formats */
+
+ update_output_video_format_menu(ctk_gvo);
+ }
+
+ /* update whatever data will be needed to change the LED colors */
+
+ update_gvo_banner_video_input(&ctk_gvo->banner, sdi, comp);
+
+ /* update the range for the sync delay spin buttons */
+
+ update_delay_spin_buttons(ctk_gvo);
+ update_offset_spin_buttons(ctk_gvo);
+
+ return TRUE;
+
+} /* probe() */
+
+
+/**************************************************************************/
+
+static void register_for_gvo_events(CtkGvo *ctk_gvo)
+{
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_SYNC_MODE),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_SYNC_SOURCE),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_DATA_FORMAT),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_SYNC_DELAY_PIXELS),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_SYNC_DELAY_LINES),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_X_SCREEN_PAN_X),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_X_SCREEN_PAN_Y),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_GLX_LOCKED),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+
+ g_signal_connect(G_OBJECT(ctk_gvo->ctk_event),
+ CTK_EVENT_NAME(NV_CTRL_GVO_DISPLAY_X_SCREEN),
+ G_CALLBACK(gvo_event_received),
+ (gpointer) ctk_gvo);
+}
+
+
+static void gvo_event_received(GtkObject *object,
+ gpointer arg1,
+ gpointer user_data)
+{
+ CtkEventStruct *event_struct = (CtkEventStruct *) arg1;
+ CtkGvo *ctk_gvo = CTK_GVO(user_data);
+ ReturnStatus ret;
+ GtkWidget *widget;
+ gint attribute = event_struct->attribute;
+ gint value = event_struct->value;
+ gint w, h;
+
+ switch (attribute) {
+ case NV_CTRL_GVO_SYNC_MODE:
+ case NV_CTRL_GVO_SYNC_SOURCE:
+ case NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE:
+ // XXX implement me
+ break;
+
+ case NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT:
+ widget = ctk_gvo->output_video_format_menu;
+
+ g_signal_handlers_block_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(output_video_format_changed),
+ (gpointer) ctk_gvo);
+
+ ctk_drop_down_menu_set_current_value
+ (CTK_DROP_DOWN_MENU(widget), value);
+
+ post_output_video_format_changed(ctk_gvo, value);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(output_video_format_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_DATA_FORMAT:
+ widget = ctk_gvo->output_data_format_menu;
+
+ g_signal_handlers_block_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(output_data_format_changed),
+ (gpointer) ctk_gvo);
+
+ ctk_drop_down_menu_set_current_value
+ (CTK_DROP_DOWN_MENU(widget), value);
+
+ post_output_data_format_changed(ctk_gvo, value);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(output_data_format_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_SYNC_DELAY_PIXELS:
+ widget = ctk_gvo->hsync_delay_spin_button;
+
+ g_signal_handlers_block_by_func(G_OBJECT(widget),
+ G_CALLBACK(hsync_delay_changed),
+ (gpointer) ctk_gvo);
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(widget),
+ G_CALLBACK(hsync_delay_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_SYNC_DELAY_LINES:
+ widget = ctk_gvo->vsync_delay_spin_button;
+
+ g_signal_handlers_block_by_func(G_OBJECT(widget),
+ G_CALLBACK(vsync_delay_changed),
+ (gpointer) ctk_gvo);
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(widget),
+ G_CALLBACK(vsync_delay_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_X_SCREEN_PAN_X:
+ widget = ctk_gvo->x_offset_spin_button;
+
+ g_signal_handlers_block_by_func(G_OBJECT(widget),
+ G_CALLBACK(x_offset_changed),
+ (gpointer) ctk_gvo);
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(widget),
+ G_CALLBACK(x_offset_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_X_SCREEN_PAN_Y:
+ widget = ctk_gvo->y_offset_spin_button;
+
+ g_signal_handlers_block_by_func(G_OBJECT(widget),
+ G_CALLBACK(y_offset_changed),
+ (gpointer) ctk_gvo);
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(widget),
+ G_CALLBACK(y_offset_changed),
+ (gpointer) ctk_gvo);
+ break;
+
+ case NV_CTRL_GVO_GLX_LOCKED:
+ if (value == NV_CTRL_GVO_GLX_LOCKED_TRUE) {
+ get_video_format_resolution(ctk_gvo->output_video_format, &w, &h);
+ update_gvo_current_info(ctk_gvo, w, h,
+ CURRENT_SDI_STATE_IN_USE_BY_GLX);
+ set_gvo_sensitivity(ctk_gvo, FALSE, 0);
+ } else {
+ update_gvo_current_info(ctk_gvo, 0, 0, CURRENT_SDI_STATE_INACTIVE);
+ set_gvo_sensitivity(ctk_gvo, TRUE, 0);
+ }
+ break;
+
+ case NV_CTRL_GVO_DISPLAY_X_SCREEN:
+
/*
- * need to register a timer to automatically turn this off for
- * 2 seconds
+ * XXX explicitly re-query this value, since a change may not
+ * actually have been successfully applied (if GLX already had
+ * GVO locked)
*/
- } else {
+ ret = NvCtrlGetAttribute(ctk_gvo->handle,
+ NV_CTRL_GVO_DISPLAY_X_SCREEN, &value);
- /* XXX need to make the other widgets sensitive */
+ if (ret == NvCtrlSuccess) {
+
+ widget = ctk_gvo->toggle_sdi_output_button;
+
+ g_signal_handlers_block_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(toggle_sdi_output_button),
+ ctk_gvo);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), value);
+
+ post_toggle_sdi_output_button(ctk_gvo, value);
+
+ g_signal_handlers_unblock_by_func
+ (G_OBJECT(widget),
+ G_CALLBACK(toggle_sdi_output_button),
+ ctk_gvo);
+ }
+ break;
- NvCtrlSetAttribute(ctk_gvo->handle,
- NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE,
- NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_FALSE);
}
-} /* input_video_format_detect_button_toggled() */
+}
/**************************************************************************/
@@ -1201,3 +2703,5 @@ GtkTextBuffer* ctk_gvo_create_help (GtkTextTagTable *table)
return b;
}
+
+
diff --git a/src/gtk+-2.x/ctkgvo.h b/src/gtk+-2.x/ctkgvo.h
index 8079b75..e68fb0b 100644
--- a/src/gtk+-2.x/ctkgvo.h
+++ b/src/gtk+-2.x/ctkgvo.h
@@ -27,9 +27,11 @@
#include "NvCtrlAttributes.h"
#include "ctkconfig.h"
+#include "ctkevent.h"
G_BEGIN_DECLS
+
#define CTK_TYPE_GVO (ctk_gvo_get_type())
#define CTK_GVO(obj) \
@@ -48,17 +50,45 @@ G_BEGIN_DECLS
(G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_GVO, CtkGvoClass))
+
typedef struct _CtkGvo CtkGvo;
typedef struct _CtkGvoClass CtkGvoClass;
+typedef struct _CtkGvoBanner CtkGvoBanner;
+
+
+struct _CtkGvoBanner
+{
+ GtkWidget *table;
+
+ GtkWidget *slots[4];
+
+ struct {
+ guint8 vid1;
+ guint8 vid2;
+ guint8 sdi;
+ guint8 comp;
+ } img;
+
+ struct {
+ guint8 vid1;
+ guint8 vid2;
+ guint8 sdi;
+ guint8 comp;
+ } state;
+};
+
struct _CtkGvo
{
GtkVBox parent;
NvCtrlAttributeHandle *handle;
+ GtkWidget *parent_window;
CtkConfig *ctk_config;
- GtkWidget *banner_table;
+ CtkEvent *ctk_event;
+
+ GtkWidget *banner_frame;
GtkWidget *sync_mode_menu;
GtkWidget *output_video_format_menu;
@@ -72,18 +102,49 @@ struct _CtkGvo
GtkWidget *input_video_format_text_entry;
GtkWidget *input_video_format_detect_button;
+ GtkWidget *current_resolution_label;
+ GtkWidget *current_state_label;
+
+ gint sync_mode;
+ gint sync_source;
+ gint input_video_format;
+ gint output_video_format;
+ gint output_data_format;
+
+ gint valid_putput_video_format_mask;
gint input_video_format_detect_timer;
+
+ GdkCursor *wait_cursor;
+ CtkGvoBanner banner;
+
+ GtkWidget *hsync_delay_spin_button;
+ GtkWidget *vsync_delay_spin_button;
+
+ GtkWidget *x_offset_spin_button;
+ GtkWidget *y_offset_spin_button;
+
+ gboolean sync_format_sensitive;
+ gboolean sdi_output_enabled;
+
+ gint screen_width;
+ gint screen_height;
};
+
struct _CtkGvoClass
{
GtkVBoxClass parent_class;
};
+
GType ctk_gvo_get_type (void) G_GNUC_CONST;
-GtkWidget* ctk_gvo_new (NvCtrlAttributeHandle *, CtkConfig *);
+GtkWidget* ctk_gvo_new (NvCtrlAttributeHandle *,
+ GtkWidget *, CtkConfig *, CtkEvent *);
+void ctk_gvo_select (GtkWidget *);
+void ctk_gvo_unselect (GtkWidget *);
GtkTextBuffer* ctk_gvo_create_help (GtkTextTagTable *);
+
G_END_DECLS
#endif /* __CTK_GVO_H__*/
diff --git a/src/gtk+-2.x/ctkutils.c b/src/gtk+-2.x/ctkutils.c
index 6436475..10900d7 100644
--- a/src/gtk+-2.x/ctkutils.c
+++ b/src/gtk+-2.x/ctkutils.c
@@ -24,15 +24,14 @@
#include <gtk/gtk.h>
#include "ctkutils.h"
-
#include <stdlib.h>
-
-void add_table_row(GtkWidget *table,
- const gint row,
- const gint value_alignment,
- const gchar *name,
- const gchar *value)
+
+GtkWidget *add_table_row(GtkWidget *table,
+ const gint row,
+ const gint value_alignment,
+ const gchar *name,
+ const gchar *value)
{
GtkWidget *label;
@@ -48,5 +47,7 @@ void add_table_row(GtkWidget *table,
gtk_misc_set_alignment(GTK_MISC(label), value_alignment, 0.5);
gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+
+ return label;
}
diff --git a/src/gtk+-2.x/ctkutils.h b/src/gtk+-2.x/ctkutils.h
index a58159b..586cc8b 100644
--- a/src/gtk+-2.x/ctkutils.h
+++ b/src/gtk+-2.x/ctkutils.h
@@ -30,8 +30,8 @@
G_BEGIN_DECLS
-void add_table_row(GtkWidget *, const gint, const gint, const gchar *,
- const gchar *);
+GtkWidget *add_table_row(GtkWidget *, const gint, const gint, const gchar *,
+ const gchar *);
G_END_DECLS
diff --git a/src/gtk+-2.x/ctkwindow.c b/src/gtk+-2.x/ctkwindow.c
index a49f2d6..b7ec7be 100644
--- a/src/gtk+-2.x/ctkwindow.c
+++ b/src/gtk+-2.x/ctkwindow.c
@@ -81,7 +81,7 @@ static void ctk_window_class_init(CtkWindowClass *);
static void ctk_window_real_destroy(GtkObject *);
static void add_page(GtkWidget *, GtkTextBuffer *, CtkWindow *,
- GtkTreeIter *, const gchar *,
+ GtkTreeIter *, GtkTreeIter *, const gchar *,
config_file_attributes_func_t func,
select_widget_func_t load_func,
unselect_widget_func_t unload_func);
@@ -552,7 +552,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
ctk_event);
if (child) {
help = ctk_color_correction_create_help(tag_table);
- add_page(child, help, ctk_window, &iter,
+ add_page(child, help, ctk_window, &iter, NULL,
"X Server Color Correction", NULL, NULL, NULL);
}
@@ -561,7 +561,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_xvideo_new(handles[i], ctk_config);
if (child) {
help = ctk_xvideo_create_help(tag_table, CTK_XVIDEO(child));
- add_page(child, help, ctk_window, &iter,
+ add_page(child, help, ctk_window, &iter, NULL,
"X Server XVideo Settings", NULL, NULL, NULL);
}
@@ -570,7 +570,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_randr_new(handles[i], ctk_config, ctk_event);
if (child) {
help = ctk_randr_create_help(tag_table, CTK_RANDR(child));
- add_page(child, help, ctk_window, &iter,
+ add_page(child, help, ctk_window, &iter, NULL,
"Rotation Settings", NULL, NULL, NULL);
}
@@ -580,7 +580,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
if (child) {
help = ctk_cursor_shadow_create_help(tag_table,
CTK_CURSOR_SHADOW(child));
- add_page(child, help, ctk_window, &iter, "Cursor Shadow",
+ add_page(child, help, ctk_window, &iter, NULL, "Cursor Shadow",
NULL, NULL, NULL);
}
@@ -589,7 +589,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_opengl_new(handles[i], ctk_config, ctk_event);
if (child) {
help = ctk_opengl_create_help(tag_table, CTK_OPENGL(child));
- add_page(child, help, ctk_window, &iter, "OpenGL Settings",
+ add_page(child, help, ctk_window, &iter, NULL, "OpenGL Settings",
NULL, NULL, NULL);
}
@@ -599,8 +599,8 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_glx_new(handles[i], ctk_config, ctk_event);
if (child) {
help = ctk_glx_create_help(tag_table, CTK_GLX(child));
- add_page(child, help, ctk_window, &iter, "OpenGL/GLX Information",
- NULL, ctk_glx_probe_info, NULL);
+ add_page(child, help, ctk_window, &iter, NULL,
+ "OpenGL/GLX Information", NULL, ctk_glx_probe_info, NULL);
}
@@ -610,8 +610,8 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
if (child) {
help = ctk_multisample_create_help(tag_table,
CTK_MULTISAMPLE(child));
- add_page(child, help, ctk_window, &iter, "Antialiasing Settings",
- NULL, NULL, NULL);
+ add_page(child, help, ctk_window, &iter, NULL,
+ "Antialiasing Settings", NULL, NULL, NULL);
}
/* thermal information */
@@ -619,17 +619,19 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_thermal_new(handles[i], ctk_config);
if (child) {
help = ctk_thermal_create_help(tag_table, CTK_THERMAL(child));
- add_page(child, help, ctk_window, &iter, "Thermal Monitor",
+ add_page(child, help, ctk_window, &iter, NULL, "Thermal Monitor",
NULL, ctk_thermal_start_timer, ctk_thermal_stop_timer);
}
/* gvo (Graphics To Video Out) */
- child = ctk_gvo_new(handles[i], ctk_config);
+ child = ctk_gvo_new(handles[i], GTK_WIDGET(ctk_window),
+ ctk_config, ctk_event);
if (child) {
help = ctk_gvo_create_help(tag_table);
- add_page(child, help, ctk_window, &iter, "Graphics to Video Out",
- NULL, NULL, NULL);
+ add_page(child, help, ctk_window, &iter, NULL,
+ "Graphics to Video Out", NULL,
+ ctk_gvo_select, ctk_gvo_unselect);
}
/* clocks (GPU overclocking) */
@@ -637,7 +639,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
child = ctk_clocks_new(handles[i], ctk_config, ctk_event);
if (child) {
help = ctk_clocks_create_help(tag_table, CTK_CLOCKS(child));
- add_page(child, help, ctk_window, &iter, "Clock Frequencies",
+ add_page(child, help, ctk_window, &iter, NULL, "Clock Frequencies",
NULL, ctk_clocks_select, NULL);
}
@@ -665,7 +667,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
if (!widget) continue;
add_page(widget, ctk_framelock_create_help(tag_table),
- ctk_window, NULL, "FrameLock",
+ ctk_window, NULL, NULL, "FrameLock",
ctk_framelock_config_file_attributes,
ctk_framelock_select,
ctk_framelock_unselect);
@@ -676,7 +678,7 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
add_page(GTK_WIDGET(ctk_window->ctk_config),
ctk_config_create_help(tag_table),
- ctk_window, NULL, "nvidia-settings Configuration",
+ ctk_window, NULL, NULL, "nvidia-settings Configuration",
NULL, NULL, NULL);
/*
@@ -713,35 +715,47 @@ GtkWidget *ctk_window_new(NvCtrlAttributeHandle **handles, gint num_handles,
/*
* add_page() - add a new page to ctk_window's tree_store, using iter
- * as a parent.
+ * as a parent; the new child iter is written in pchild_iter, if
+ * provided.
*/
static void add_page(GtkWidget *widget, GtkTextBuffer *help,
CtkWindow *ctk_window, GtkTreeIter *iter,
+ GtkTreeIter *child_iter,
const gchar *label, config_file_attributes_func_t func,
select_widget_func_t select_func,
unselect_widget_func_t unselect_func)
{
- GtkTreeIter child_iter;
+ GtkTreeIter tmp_child_iter;
if (!widget)
return;
+ if (!child_iter) child_iter = &tmp_child_iter;
+
+ /*
+ * add another reference to the widget, so that it doesn't get
+ * destroyed the next time it gets hidden (removed from the page
+ * viewer).
+ */
+
gtk_object_ref(GTK_OBJECT(widget));
- gtk_tree_store_append(ctk_window->tree_store, &child_iter, iter);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+
+ gtk_tree_store_append(ctk_window->tree_store, child_iter, iter);
+
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_LABEL_COLUMN, label, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_WIDGET_COLUMN, widget, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_HELP_COLUMN, help, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN,
func, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_SELECT_WIDGET_FUNC_COLUMN,
select_func, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
+ gtk_tree_store_set(ctk_window->tree_store, child_iter,
CTK_WINDOW_UNSELECT_WIDGET_FUNC_COLUMN,
unselect_func, -1);
} /* add_page() */
@@ -874,7 +888,7 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help,
CtkEvent *ctk_event,
GtkTextTagTable *tag_table)
{
- GtkTreeIter child_iter, grandchild_iter;
+ GtkTreeIter child_iter;
ReturnStatus ret;
int i, enabled, n, mask;
char *name;
@@ -903,25 +917,8 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help,
name = "Display Devices";
}
- /*
- * add another reference to the widget, so that it doesn't get
- * destroyed the next time it gets hidden (removed from the page
- * viewer).
- */
-
- gtk_object_ref(GTK_OBJECT(widget));
-
- gtk_tree_store_append(ctk_window->tree_store, &child_iter, iter);
-
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
- CTK_WINDOW_LABEL_COLUMN, name, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
- CTK_WINDOW_WIDGET_COLUMN, widget, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
- CTK_WINDOW_HELP_COLUMN, help, -1);
- gtk_tree_store_set(ctk_window->tree_store, &child_iter,
- CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN,
- NULL, -1);
+ add_page(widget, help, ctk_window, iter, &child_iter, name,
+ NULL, NULL, NULL);
/*
* create pages for each of the display devices driven by this X
@@ -969,23 +966,8 @@ static void add_display_devices(GtkWidget *widget, GtkTextBuffer *help,
continue;
}
- gtk_object_ref(GTK_OBJECT(widget));
-
- gtk_tree_store_append(ctk_window->tree_store, &grandchild_iter,
- &child_iter);
-
- gtk_tree_store_set(ctk_window->tree_store, &grandchild_iter,
- CTK_WINDOW_LABEL_COLUMN, name, -1);
-
- gtk_tree_store_set(ctk_window->tree_store, &grandchild_iter,
- CTK_WINDOW_WIDGET_COLUMN, widget, -1);
-
- gtk_tree_store_set(ctk_window->tree_store, &grandchild_iter,
- CTK_WINDOW_HELP_COLUMN, help, -1);
-
- gtk_tree_store_set(ctk_window->tree_store, &grandchild_iter,
- CTK_WINDOW_CONFIG_FILE_ATTRIBUTES_FUNC_COLUMN,
- NULL, -1);
+ add_page(widget, help, ctk_window, &child_iter,
+ NULL, name, NULL, NULL, NULL);
}
} /* add_display_devices() */
diff --git a/src/libXNVCtrl/NVCtrl.h b/src/libXNVCtrl/NVCtrl.h
index 7561010..da7b15b 100644
--- a/src/libXNVCtrl/NVCtrl.h
+++ b/src/libXNVCtrl/NVCtrl.h
@@ -687,12 +687,10 @@
* NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED to detect what input syncs are
* present.
*
- *         (If no analog sync is detected but it is known
- *           that a thought to be valid bi-level or tri-level
- *         sync is connected set
- *         NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE
- *         appropriately and retest with
- *         NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED).
+ *  (If no analog sync is detected but it is known that a
+ * valid bi-level or tri-level sync is connected set
+ * NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE appropriately and
+ * retest with NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED).
*
* - specify NV_CTRL_GVO_SYNC_SOURCE, if appropriate
*
diff --git a/src/libXNVCtrl/libXNVCtrl.a b/src/libXNVCtrl/libXNVCtrl.a
index a94e166..324775e 100644
--- a/src/libXNVCtrl/libXNVCtrl.a
+++ b/src/libXNVCtrl/libXNVCtrl.a
Binary files differ
diff --git a/src/parse.c b/src/parse.c
index 126b740..434b90a 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -53,6 +53,7 @@ static char *nv_strndup(char *s, int n);
#define N NV_PARSER_TYPE_NO_CONFIG_WRITE
#define G NV_PARSER_TYPE_GUI_ATTRIUBUTE
#define V NV_PARSER_TYPE_XVIDEO_ATTRIBUTE
+#define P NV_PARSER_TYPE_PACKED_ATTRIBUTE
AttributeTableEntry attributeTable[] = {
@@ -123,6 +124,13 @@ AttributeTableEntry attributeTable[] = {
{ "XVideoTextureSyncToVBlank", NV_CTRL_ATTR_XV_TEXTURE_SYNC_TO_VBLANK, V },
{ "XVideoBlitterSyncToVBlank", NV_CTRL_ATTR_XV_BLITTER_SYNC_TO_VBLANK, V },
+ { "GPUOverclockingState", NV_CTRL_GPU_OVERCLOCKING_STATE, N },
+ { "GPUDefault2DClockFreqs", NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS, N|P },
+ { "GPUDefault3DClockFreqs", NV_CTRL_GPU_DEFAULT_3D_CLOCK_FREQS, N|P },
+ { "GPU2DClockFreqs", NV_CTRL_GPU_2D_CLOCK_FREQS, N|P },
+ { "GPU3DClockFreqs", NV_CTRL_GPU_3D_CLOCK_FREQS, N|P },
+ { "GPUCurrentClockFreqs", NV_CTRL_GPU_CURRENT_CLOCK_FREQS, N|P },
+
{ NULL, 0, 0 }
};
@@ -131,6 +139,7 @@ AttributeTableEntry attributeTable[] = {
#undef N
#undef G
#undef V
+#undef P
/*
* nv_parse_attribute_string() - see comments in parse.h
@@ -259,6 +268,11 @@ int nv_parse_attribute_string(const char *str, int query, ParsedAttribute *a)
if (a->flags & NV_PARSER_TYPE_COLOR_ATTRIBUTE) {
/* color attributes are floating point */
a->fval = strtod(s, &tmp);
+ } else if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ /* two 16-bit integers, separated by ',' */
+ a->val = (strtol(s, &tmp, 10) & 0xffff) << 16;
+ if (!tmp || (*tmp != ',')) stop(NV_PARSER_STATUS_MISSING_COMMA);
+ a->val |= strtol((tmp + 1), &tmp, 10) & 0xffff;
} else {
/* all other attributes are integer */
a->val = strtol(s, &tmp, 10);
@@ -309,6 +323,8 @@ char *nv_parse_strerror(int status)
return "Trailing garbage"; break;
case NV_PARSER_STATUS_UNKNOWN_ATTR_NAME :
return "Unrecognized attribute name"; break;
+ case NV_PARSER_STATUS_MISSING_COMMA:
+ return "Missing comma in packed integer value"; break;
default:
return "Unknown error"; break;
}
diff --git a/src/parse.h b/src/parse.h
index 020a01e..ccff17f 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -48,6 +48,7 @@
#define NV_PARSER_TYPE_NO_CONFIG_WRITE (1<<18)
#define NV_PARSER_TYPE_GUI_ATTRIUBUTE (1<<19)
#define NV_PARSER_TYPE_XVIDEO_ATTRIBUTE (1<<20)
+#define NV_PARSER_TYPE_PACKED_ATTRIBUTE (1<<21)
#define NV_PARSER_ASSIGNMENT 0
#define NV_PARSER_QUERY 1
@@ -71,6 +72,7 @@
#define NV_PARSER_STATUS_NO_VALUE 7
#define NV_PARSER_STATUS_TRAILING_GARBAGE 8
#define NV_PARSER_STATUS_UNKNOWN_ATTR_NAME 9
+#define NV_PARSER_STATUS_MISSING_COMMA 10
/*
* define useful types
diff --git a/src/query-assign.c b/src/query-assign.c
index 8f0366e..cdd7190 100644
--- a/src/query-assign.c
+++ b/src/query-assign.c
@@ -45,7 +45,7 @@ static int process_attribute_assignments(int, char**, const char *);
static int query_all(const char *);
-static void print_valid_values(char *, NVCTRLAttributeValidValuesRec);
+static void print_valid_values(char *, uint32, NVCTRLAttributeValidValuesRec);
static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
int screen, char *whence);
@@ -395,8 +395,15 @@ static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
}
break;
case ATTRIBUTE_TYPE_RANGE:
- if ((a->val < valid.u.range.min) || (a->val > valid.u.range.max)) {
- bad_val = NV_TRUE;
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ if (((a->val >> 16) < (valid.u.range.min >> 16)) ||
+ ((a->val >> 16) > (valid.u.range.max >> 16)) ||
+ ((a->val & 0xffff) < (valid.u.range.min & 0xffff)) ||
+ ((a->val & 0xffff) > (valid.u.range.max & 0xffff)))
+ bad_val = NV_TRUE;
+ } else {
+ if ((a->val < valid.u.range.min) || (a->val > valid.u.range.max))
+ bad_val = NV_TRUE;
}
break;
case ATTRIBUTE_TYPE_INT_BITS:
@@ -411,11 +418,19 @@ static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
}
if (bad_val) {
- nv_warning_msg("The value %d for attribute '%s' (%s%s) "
- "specified %s is invalid.",
- a->val, a->name, h->screen_names[screen],
- d_str, whence);
- print_valid_values(a->name, valid);
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_warning_msg("The value pair %d,%d for attribute '%s' (%s%s) "
+ "specified %s is invalid.",
+ a->val >> 16, a->val & 0xffff,
+ a->name, h->screen_names[screen],
+ d_str, whence);
+ } else {
+ nv_warning_msg("The value %d for attribute '%s' (%s%s) "
+ "specified %s is invalid.",
+ a->val, a->name, h->screen_names[screen],
+ d_str, whence);
+ }
+ print_valid_values(a->name, a->flags, valid);
return NV_FALSE;
}
return NV_TRUE;
@@ -429,7 +444,8 @@ static int validate_value(CtrlHandles *h, ParsedAttribute *a, uint32 d,
* attribute.
*/
-static void print_valid_values(char *name, NVCTRLAttributeValidValuesRec valid)
+static void print_valid_values(char *name, uint32 flags,
+ NVCTRLAttributeValidValuesRec valid)
{
int bit, first, last;
char str[256];
@@ -439,7 +455,11 @@ static void print_valid_values(char *name, NVCTRLAttributeValidValuesRec valid)
switch (valid.type) {
case ATTRIBUTE_TYPE_INTEGER:
- nv_msg(INDENT, "'%s' is an integer attribute.", name);
+ if (flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(INDENT, "'%s' is a packed integer attribute.", name);
+ } else {
+ nv_msg(INDENT, "'%s' is an integer attribute.", name);
+ }
break;
case ATTRIBUTE_TYPE_BITMASK:
@@ -452,9 +472,16 @@ static void print_valid_values(char *name, NVCTRLAttributeValidValuesRec valid)
break;
case ATTRIBUTE_TYPE_RANGE:
- nv_msg(INDENT, "The valid values for '%s' are in the range "
- "%d - %d (inclusive).", name,
- valid.u.range.min, valid.u.range.max);
+ if (flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(INDENT, "The valid values for '%s' are in the ranges "
+ "%d - %d, %d - %d (inclusive).", name,
+ valid.u.range.min >> 16, valid.u.range.max >> 16,
+ valid.u.range.min & 0xffff, valid.u.range.max & 0xffff);
+ } else {
+ nv_msg(INDENT, "The valid values for '%s' are in the range "
+ "%d - %d (inclusive).", name,
+ valid.u.range.min, valid.u.range.max);
+ }
break;
case ATTRIBUTE_TYPE_INT_BITS:
@@ -532,6 +559,10 @@ static int query_all(const char *display_name)
"Attribute '%s' (screen: %s): 0x%08x.";
static const char *__fmt_str_hex_display =
"Attribute '%s' (screen: %s; display: %s): 0x%08x.";
+ static const char *__fmt_str_packed_int =
+ "Attribute '%s' (screen: %s): %d,%d.";
+ static const char *__fmt_str_packed_int_display =
+ "Attribute '%s' (screen: %s; display: %s): %d,%d.";
h = nv_alloc_ctrl_handles(display_name);
@@ -586,6 +617,9 @@ static int query_all(const char *display_name)
if (valid.type == ATTRIBUTE_TYPE_BITMASK) {
fmt = __fmt_str_hex;
fmt_display = __fmt_str_hex_display;
+ } else if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ fmt = __fmt_str_packed_int;
+ fmt_display = __fmt_str_packed_int_display;
} else {
fmt = __fmt_str_int;
fmt_display = __fmt_str_int_display;
@@ -596,19 +630,30 @@ static int query_all(const char *display_name)
tmp_d_str =
display_device_mask_to_display_device_name(mask);
- nv_msg(INDENT, fmt_display, a->name,
- h->screen_names[screen], tmp_d_str, val);
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(INDENT, fmt_display, a->name,
+ h->screen_names[screen], tmp_d_str,
+ val >> 16, val & 0xffff);
+ } else {
+ nv_msg(INDENT, fmt_display, a->name,
+ h->screen_names[screen], tmp_d_str, val);
+ }
free(tmp_d_str);
- print_valid_values(a->name, valid);
+ print_valid_values(a->name, a->flags, valid);
continue;
} else {
- nv_msg(INDENT, fmt, a->name, h->screen_names[screen], val);
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(INDENT, fmt, a->name, h->screen_names[screen],
+ val >> 16, val & 0xffff);
+ } else {
+ nv_msg(INDENT, fmt, a->name, h->screen_names[screen],val);
+ }
- print_valid_values(a->name, valid);
+ print_valid_values(a->name, a->flags, valid);
/* fall through to exit_bit_loop */
}
@@ -674,8 +719,14 @@ static int process_parsed_attribute_internal(CtrlHandles *h,
}
if (verbose) {
- nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d.",
- a->name, h->screen_names[screen], str, a->val);
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d,%d.",
+ a->name, h->screen_names[screen], str,
+ a->val >> 16, a->val & 0xffff);
+ } else {
+ nv_msg(" ", "Attribute '%s' (%s%s) assigned value %d.",
+ a->name, h->screen_names[screen], str, a->val);
+ }
}
} else { /* query */
@@ -694,9 +745,15 @@ static int process_parsed_attribute_internal(CtrlHandles *h,
NvCtrlAttributesStrError(status));
return NV_FALSE;
} else {
- nv_msg(" ", "Attribute '%s' (%s%s): %d.",
- a->name, h->screen_names[screen], str, a->val);
- print_valid_values(a->name, valid);
+ if (a->flags & NV_PARSER_TYPE_PACKED_ATTRIBUTE) {
+ nv_msg(" ", "Attribute '%s' (%s%s): %d,%d.",
+ a->name, h->screen_names[screen], str,
+ a->val >> 16, a->val & 0xffff);
+ } else {
+ nv_msg(" ", "Attribute '%s' (%s%s): %d.",
+ a->name, h->screen_names[screen], str, a->val);
+ }
+ print_valid_values(a->name, a->flags, valid);
}
}