diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:23:46 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2008-02-12 21:23:46 -0800 |
commit | 389b71f6f2e4bdcfee1b7bdcad0bf36f6ba43e5b (patch) | |
tree | 37a5d58b6ece4db47664507d7a54c3ace4046138 | |
parent | 4256beee1897d25700b9cd6bf51728bc31c86627 (diff) |
1.0-76671.0-7667
-rw-r--r-- | src/gtk+-2.x/ctkgvo.c | 1822 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkgvo.h | 65 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkutils.c | 15 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkutils.h | 4 | ||||
-rw-r--r-- | src/gtk+-2.x/ctkwindow.c | 108 | ||||
-rw-r--r-- | src/libXNVCtrl/NVCtrl.h | 10 | ||||
-rw-r--r-- | src/libXNVCtrl/libXNVCtrl.a | bin | 13488 -> 13488 bytes | |||
-rw-r--r-- | src/parse.c | 16 | ||||
-rw-r--r-- | src/parse.h | 2 | ||||
-rw-r--r-- | src/query-assign.c | 103 |
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 Binary files differindex a94e166..324775e 100644 --- a/src/libXNVCtrl/libXNVCtrl.a +++ b/src/libXNVCtrl/libXNVCtrl.a 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); } } |