2
* nvidia-settings: A tool for configuring the NVIDIA X driver on Unix
5
* Copyright (C) 2004 NVIDIA Corporation.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of Version 2 of the GNU General Public
9
* License as published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See Version 2
14
* of the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the:
19
* Free Software Foundation, Inc.
20
* 59 Temple Place - Suite 330
21
* Boston, MA 02111-1307, USA
26
#include <NvCtrlAttributes.h>
31
#include "ctkframelock.h"
34
#include "frame_lock_banner.h"
35
#include "led_green.h"
39
#include "rj45_input.h"
40
#include "rj45_output.h"
46
#define DEFAULT_UPDATE_STATUS_TIME_INTERVAL 1000
47
#define DEFAULT_TEST_LINK_TIME_INTERVAL 2000
48
#define DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL 10000
50
#define POLARITY_RISING 0x1
51
#define POLARITY_FALLING 0x2
52
#define POLARITY_BOTH 0x3
55
* functions for the FrameLock Widget
58
static void ctk_framelock_class_init(CtkFramelockClass *ctk_framelock_class);
60
static gpointer add_x_screen(CtkFramelock *, const gchar *, gboolean);
61
static GtkWidget *create_add_x_screen_dialog(CtkFramelock *ctk_framelock);
62
static GtkWidget *create_remove_x_screen_dialog(CtkFramelock *ctk_framelock);
63
static GtkWidget *create_error_msg_dialog(CtkFramelock *ctk_framelock);
64
static GtkWidget *create_sync_state_button(CtkFramelock *ctk_framelock);
66
static gboolean update_status(gpointer user_data);
67
static gboolean check_for_ethernet(gpointer user_data);
69
static void test_link(GtkWidget *button, CtkFramelock *ctk_framelock);
70
static gint test_link_done(gpointer data);
72
static void toggle_sync_state_button(GtkWidget *button,
73
CtkFramelock *ctk_framelock);
75
static void show_remove_x_screen_dialog(GtkWidget *, CtkFramelock *);
76
static void error_msg(CtkFramelock *ctk_framelock, const gchar *fmt, ...);
80
static void create_list_store(CtkFramelock *ctk_framelock);
81
static void add_member_to_list_store(CtkFramelock *ctk_framelock,
82
const gpointer handle);
84
static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock,
87
static GtkWidget *add_house_sync_controls(CtkFramelock *ctk_framelock);
88
static void update_house_sync_controls(CtkFramelock *ctk_framelock);
90
static void add_columns_to_treeview(CtkFramelock *ctk_framelock);
92
static void sync_interval_entry_activate(GtkEntry *, gpointer);
93
static void house_sync_format_entry_activate(GtkEditable *, gpointer);
95
static gboolean find_master(CtkFramelock *, GtkTreeIter *,
96
NvCtrlAttributeHandle **);
113
COLUMN_SYNC_INTERVAL,
122
* helper functions for displaying the correct thing in the columns of
126
static void led_renderer_func (GtkTreeViewColumn *tree_column,
127
GtkCellRenderer *cell,
132
static void rj45_renderer_func (GtkTreeViewColumn *tree_column,
133
GtkCellRenderer *cell,
138
static void rate_renderer_func (GtkTreeViewColumn *tree_column,
139
GtkCellRenderer *cell,
144
static void polarity_renderer_func (GtkTreeViewColumn *tree_column,
145
GtkCellRenderer *cell,
150
static void sync_skew_renderer_func (GtkTreeViewColumn *tree_column,
151
GtkCellRenderer *cell,
156
/* callback functions */
158
static void master_toggled(GtkCellRendererToggle *cell,
162
static void rising_edge_toggled(GtkCellRendererToggle *cell,
166
static void falling_edge_toggled(GtkCellRendererToggle *cell,
170
static void sync_skew_edited(GtkCellRendererText *cell,
171
const gchar *path_string,
172
const gchar *new_text,
175
static GObjectClass *parent_class;
180
* ctk_framelock_get_type() - register the FrameLock class and
181
* return the unique type id.
184
GType ctk_framelock_get_type(
188
static GType ctk_framelock_type = 0;
190
if (!ctk_framelock_type) {
191
static const GTypeInfo ctk_framelock_info = {
192
sizeof (CtkFramelockClass),
193
NULL, /* base_init */
194
NULL, /* base_finalize */
195
(GClassInitFunc) ctk_framelock_class_init,
196
NULL, /* class_finalize */
197
NULL, /* class_data */
198
sizeof (CtkFramelock),
200
NULL, /* instance_init */
203
ctk_framelock_type = g_type_register_static
204
(GTK_TYPE_VBOX, "CtkFramelock", &ctk_framelock_info, 0);
207
return ctk_framelock_type;
209
} /* ctk_framelock_get_type() */
215
* ctk_framelock_class_init() - initialize the object structure
218
static void ctk_framelock_class_init(
219
CtkFramelockClass *ctk_framelock_class
222
GObjectClass *gobject_class;
224
gobject_class = (GObjectClass *) ctk_framelock_class;
225
parent_class = g_type_class_peek_parent(ctk_framelock_class);
227
} /* ctk_framelock_class_init() */
232
* ctk_framelock_new() - return a new instance of the FrameLock
236
GtkWidget* ctk_framelock_new(NvCtrlAttributeHandle *handle,
237
GtkWidget *parent_window, CtkConfig *ctk_config,
241
CtkFramelock *ctk_framelock;
248
GtkWidget *hseparator;
251
guint8 *image_buffer = NULL;
252
const nv_image_t *img;
254
/* make sure we have a handle */
256
g_return_val_if_fail(handle != NULL, NULL);
259
* Only expose FrameLock if the current NV-CONTROL handle supports
260
* FrameLock. This isn't absolutely necessary, because the
261
* FrameLock control page does not have to include the current
262
* NV-CONTROL handle in the FrameLock Group. However, we don't
263
* want to expose the FrameLock page unconditionally (it would
264
* only confuse most users), so this is as good a condition as
268
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK, &value);
269
if (value != NV_CTRL_FRAMELOCK_SUPPORTED) return NULL;
271
/* create a new instance of the object */
273
object = g_object_new(CTK_TYPE_FRAMELOCK, NULL);
275
ctk_framelock = CTK_FRAMELOCK(object);
276
ctk_framelock->attribute_handle = handle;
277
ctk_framelock->parent_window = GTK_WINDOW(parent_window);
279
gtk_box_set_spacing(GTK_BOX(ctk_framelock), 10);
283
hbox = gtk_hbox_new(FALSE, 0);
284
gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 0);
286
frame = gtk_frame_new(NULL);
287
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
289
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
291
img = &frame_lock_banner_image;
293
image_buffer = decompress_image_data(img);
295
image = gtk_image_new_from_pixbuf
296
(gdk_pixbuf_new_from_data(image_buffer, GDK_COLORSPACE_RGB,
297
FALSE, 8, img->width, img->height,
298
img->width * img->bytes_per_pixel,
299
free_decompressed_image, NULL));
301
gtk_container_add(GTK_CONTAINER(frame), image);
303
/* scrollable list */
305
sw = gtk_scrolled_window_new(NULL, NULL);
306
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
308
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
309
GTK_POLICY_AUTOMATIC,
311
gtk_box_pack_start(GTK_BOX(object), sw, TRUE, TRUE, 0);
313
/* create the list store and treeview */
315
create_list_store(ctk_framelock);
317
/* plug the treeview into the scrollable window */
319
gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(ctk_framelock->treeview));
321
hseparator = gtk_hseparator_new();
322
gtk_box_pack_start(GTK_BOX(object), hseparator, FALSE, TRUE, 0);
324
/* Sync Interval and House Sync Format controls */
326
hbox = add_house_sync_controls(ctk_framelock);
327
gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, TRUE, 0);
329
hseparator = gtk_hseparator_new();
330
gtk_box_pack_start(GTK_BOX(object), hseparator, FALSE, TRUE, 0);
332
/* create any needed dialog windows */
334
ctk_framelock->add_x_screen_dialog =
335
create_add_x_screen_dialog(ctk_framelock);
337
ctk_framelock->remove_x_screen_dialog =
338
create_remove_x_screen_dialog(ctk_framelock);
340
ctk_framelock->error_msg_dialog =
341
create_error_msg_dialog(ctk_framelock);
345
hbox = gtk_hbox_new(FALSE, 5);
346
gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, TRUE, 0);
348
/* "Add X Screen..." button */
350
label = gtk_label_new("Add X Screen...");
351
hbox2 = gtk_hbox_new(FALSE, 0);
352
ctk_framelock->add_x_screen_button = gtk_button_new();
354
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15);
355
gtk_container_add(GTK_CONTAINER(ctk_framelock->add_x_screen_button),
358
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->add_x_screen_button,
361
g_signal_connect_swapped(G_OBJECT(ctk_framelock->add_x_screen_button),
362
"clicked", G_CALLBACK(gtk_widget_show_all),
363
(gpointer) ctk_framelock->add_x_screen_dialog);
365
/* "Remove X Screen..." button */
367
label = gtk_label_new("Remove X Screen...");
368
hbox2 = gtk_hbox_new(FALSE, 0);
369
ctk_framelock->remove_x_screen_button = gtk_button_new();
371
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15);
372
gtk_container_add(GTK_CONTAINER(ctk_framelock->remove_x_screen_button),
375
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->remove_x_screen_button,
377
gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, FALSE);
379
g_signal_connect(G_OBJECT(ctk_framelock->remove_x_screen_button),
380
"clicked", G_CALLBACK(show_remove_x_screen_dialog),
381
GTK_OBJECT(ctk_framelock));
383
/* "Test Link" button */
385
label = gtk_label_new("Test Link");
386
hbox2 = gtk_hbox_new(FALSE, 0);
387
ctk_framelock->test_link_button = gtk_toggle_button_new();
389
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 15);
390
gtk_container_add(GTK_CONTAINER(ctk_framelock->test_link_button), hbox2);
392
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->test_link_button,
395
gtk_widget_set_sensitive(ctk_framelock->test_link_button, FALSE);
397
g_signal_connect(G_OBJECT(ctk_framelock->test_link_button), "toggled",
398
G_CALLBACK(test_link), GTK_OBJECT(ctk_framelock));
400
/* Sync State button */
402
ctk_framelock->sync_state_button = create_sync_state_button(ctk_framelock);
404
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->sync_state_button,
407
gtk_widget_set_sensitive(ctk_framelock->sync_state_button, FALSE);
409
g_signal_connect(G_OBJECT(ctk_framelock->sync_state_button), "toggled",
410
G_CALLBACK(toggle_sync_state_button),
411
GTK_OBJECT(ctk_framelock));
415
gtk_widget_show_all(GTK_WIDGET(object));
417
/* register a timer callback to update the status of the page */
419
ctk_config_add_timer(ctk_config, DEFAULT_UPDATE_STATUS_TIME_INTERVAL,
420
"FrameLock Connection Status",
421
(GSourceFunc) update_status,
422
(gpointer) ctk_framelock);
424
/* register a timer callback to check the rj45 ports */
426
ctk_config_add_timer(ctk_config, DEFAULT_CHECK_FOR_ETHERNET_TIME_INTERVAL,
427
"FrameLock RJ45 Check",
428
(GSourceFunc) check_for_ethernet,
429
(gpointer) ctk_framelock);
431
ctk_framelock->ctk_config = ctk_config;
433
/* create the watch cursor */
435
ctk_framelock->wait_cursor = gdk_cursor_new(GDK_WATCH);
437
/* apply the parsed attribute list */
439
apply_parsed_attribute_list(ctk_framelock, p);
441
return GTK_WIDGET(object);
443
} /* ctk_framelock_new() */
447
/**************************************************************************/
449
static gchar *houseFormatStrings[] = {
450
"Composite, Auto", /* VIDEO_MODE_COMPOSITE_AUTO */
451
"TTL", /* VIDEO_MODE_TTL */
452
"Composite, Bi-Level", /* VIDEO_MODE_COMPOSITE_BI_LEVEL */
453
"Composite, Tri-Level", /* VIDEO_MODE_COMPOSITE_TRI_LEVEL */
456
static void detect_house_sync_format_toggled(GtkToggleButton *togglebutton,
460
* House Sync autodetection scheme: a modal push button is used to
461
* request auto detection. When the button is pressed, we program the
462
* first format type and then start a timer.
464
* From the timer, we check if we are getting a house sync; if we are,
465
* then update the settings and unpress the button. If we are not,
466
* program the next format in the sequence and try again.
471
* detect_house_sync_format_timer() -
474
static gboolean detect_house_sync_format_timer(gpointer user_data)
476
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
477
NvCtrlAttributeHandle *handle = NULL;
481
if (!find_master(ctk_framelock, &iter, &handle)) {
485
/* check if we now have house sync */
487
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house);
490
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
492
* We found house sync; use the current_detect_format
495
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
496
COLUMN_HOUSE, house, -1);
497
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
499
ctk_framelock->current_detect_format, -1);
501
update_house_sync_controls(ctk_framelock);
503
ctk_config_statusbar_message(ctk_framelock->ctk_config,
504
"House Sync format detected as %s.",
506
[ctk_framelock->current_detect_format]);
512
* we did not find house sync, yet, so move to the next format
515
switch (ctk_framelock->current_detect_format) {
517
case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO:
518
ctk_framelock->current_detect_format =
519
NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL;
522
case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL:
523
ctk_framelock->current_detect_format =
524
NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL;
527
case NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL:
528
ctk_framelock->current_detect_format =
529
NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL;
532
case NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL:
533
ctk_framelock->current_detect_format =
534
NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO;
535
ctk_config_statusbar_message(ctk_framelock->ctk_config,
536
"Unable to detect house sync format.");
542
* Set the new video format
545
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE,
546
ctk_framelock->current_detect_format);
552
/* untoggle the detect button */
554
g_signal_handlers_block_by_func
555
(G_OBJECT(ctk_framelock->house_format_detect),
556
G_CALLBACK(detect_house_sync_format_toggled),
557
(gpointer) ctk_framelock);
559
gtk_toggle_button_set_active
560
(GTK_TOGGLE_BUTTON(ctk_framelock->house_format_detect), FALSE);
562
g_signal_handlers_unblock_by_func
563
(G_OBJECT(ctk_framelock->house_format_detect),
564
G_CALLBACK(detect_house_sync_format_toggled),
565
(gpointer) ctk_framelock);
567
/* do not call this timer any more */
571
} /* detect_house_sync_format_timer() */
576
* detect_house_sync_format_toggled() - called when the house sync
577
* "detect" button is toggled. If the toggle button is active, then
578
* start the detect sequence by programming
579
* NV_CTRL_FRAMELOCK_VIDEO_MODE to COMPOSITE_AUTO
581
* XXX what happens if the master gets changed while we are doing
585
static void detect_house_sync_format_toggled(GtkToggleButton *togglebutton,
588
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
589
NvCtrlAttributeHandle *handle = NULL;
591
if (gtk_toggle_button_get_active(togglebutton)) {
594
* the toggle button is active: we now start scanning through
595
* the possible input video modes and enable the house sync
599
if (!find_master(ctk_framelock, NULL, &handle)) {
601
g_signal_handlers_block_by_func
602
(G_OBJECT(ctk_framelock->house_format_detect),
603
G_CALLBACK(detect_house_sync_format_toggled),
604
(gpointer) ctk_framelock);
606
gtk_toggle_button_set_active
607
(GTK_TOGGLE_BUTTON(ctk_framelock->house_format_detect), FALSE);
609
g_signal_handlers_unblock_by_func
610
(G_OBJECT(ctk_framelock->house_format_detect),
611
G_CALLBACK(detect_house_sync_format_toggled),
612
(gpointer) ctk_framelock);
617
ctk_framelock->current_detect_format =
618
NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO;
620
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE,
621
ctk_framelock->current_detect_format);
623
ctk_framelock->house_format_detect_timer =
624
g_timeout_add(500, detect_house_sync_format_timer, user_data);
626
ctk_config_statusbar_message(ctk_framelock->ctk_config,
627
"Attempting to detect house sync...");
631
* the toggle button is no longer active: disable the timer
634
g_source_remove(ctk_framelock->house_format_detect_timer);
635
ctk_framelock->house_format_detect_timer = 0;
637
ctk_config_statusbar_message(ctk_framelock->ctk_config,
638
"Aborted house sync detection.");
641
} /* detect_house_sync_format_toggled() */
646
* add_house_sync_controls() -
649
static GtkWidget *add_house_sync_controls(CtkFramelock *ctk_framelock)
656
hbox = gtk_hbox_new(FALSE, 5);
660
ctk_framelock->sync_interval_frame = gtk_frame_new(NULL);
661
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->sync_interval_frame,
664
hbox2 = gtk_hbox_new(FALSE, 5);
665
gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_interval_frame),hbox2);
667
label = gtk_label_new("Sync Interval:");
668
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, TRUE, 5);
670
ctk_framelock->sync_interval_entry = gtk_entry_new();
671
gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry), "0");
672
gtk_entry_set_width_chars
673
(GTK_ENTRY(ctk_framelock->sync_interval_entry), 4);
675
(GTK_BOX(hbox2), ctk_framelock->sync_interval_entry, FALSE, TRUE, 5);
677
g_signal_connect(G_OBJECT(ctk_framelock->sync_interval_entry),
678
"activate", G_CALLBACK(sync_interval_entry_activate),
679
(gpointer) ctk_framelock);
683
ctk_framelock->house_format_frame = gtk_frame_new(NULL);
684
gtk_box_pack_start(GTK_BOX(hbox),
685
ctk_framelock->house_format_frame, FALSE, TRUE, 0);
687
hbox2 = gtk_hbox_new(FALSE, 5);
688
gtk_container_add(GTK_CONTAINER(ctk_framelock->house_format_frame), hbox2);
690
label = gtk_label_new("House Sync Format:");
691
gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, TRUE, 5);
693
ctk_framelock->house_format_combo = gtk_combo_new();
696
glist = g_list_append
698
houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO]);
700
glist = g_list_append
702
houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL]);
704
glist = g_list_append
706
houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL]);
708
glist = g_list_append
709
(glist, houseFormatStrings[NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL]);
711
gtk_combo_set_popdown_strings
712
(GTK_COMBO(ctk_framelock->house_format_combo), glist);
713
gtk_editable_set_editable
714
(GTK_EDITABLE(GTK_COMBO(ctk_framelock->house_format_combo)->entry),
718
(G_OBJECT(GTK_EDITABLE
719
(GTK_COMBO(ctk_framelock->house_format_combo)->entry)),
720
"changed", G_CALLBACK(house_sync_format_entry_activate),
721
(gpointer) ctk_framelock);
723
gtk_box_pack_start(GTK_BOX(hbox2),
724
ctk_framelock->house_format_combo, FALSE, TRUE, 5);
728
ctk_framelock->house_format_detect =
729
gtk_toggle_button_new_with_label("Detect");
730
gtk_box_pack_start(GTK_BOX(hbox2),
731
ctk_framelock->house_format_detect, FALSE, TRUE, 5);
733
g_signal_connect(G_OBJECT(ctk_framelock->house_format_detect), "toggled",
734
G_CALLBACK(detect_house_sync_format_toggled),
739
} /* add_house_sync_controls() */
744
* update_house_sync_controls() - update the gui with the current
745
* sw-state of the house sync control values.
748
static void update_house_sync_controls(CtkFramelock *ctk_framelock)
750
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
751
gboolean house = FALSE, sensitive;
752
gint sync_interval, house_format;
756
if (find_master(ctk_framelock, &iter, NULL)) {
757
gtk_tree_model_get(model, &iter,
758
COLUMN_HOUSE, &house,
759
COLUMN_SYNC_INTERVAL, &sync_interval,
760
COLUMN_HOUSE_FORMAT, &house_format,
763
snprintf(str, 32, "%d", sync_interval);
764
gtk_entry_set_text(GTK_ENTRY(ctk_framelock->sync_interval_entry),str);
766
if (house_format < NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE)
767
house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE;
768
if (house_format > NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV)
769
house_format = NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV;
772
(GTK_ENTRY(GTK_COMBO(ctk_framelock->house_format_combo)->entry),
773
houseFormatStrings[house_format]);
776
if (ctk_framelock->framelock_enabled) {
782
gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, sensitive);
783
gtk_widget_set_sensitive(ctk_framelock->house_format_frame, sensitive);
785
} /* update_house_sync_controls() */
789
static void sync_interval_entry_activate(GtkEntry *entry, gpointer user_data)
791
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
792
NvCtrlAttributeHandle *handle = NULL;
793
const gchar *str = gtk_entry_get_text(entry);
796
interval = strtol(str, NULL, 10);
798
if (find_master(ctk_framelock, NULL, &handle)) {
799
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL, interval);
803
static void house_sync_format_entry_activate(GtkEditable *editable,
806
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
807
const gchar *str = gtk_entry_get_text
808
(GTK_ENTRY(GTK_COMBO(ctk_framelock->house_format_combo)->entry));
809
NvCtrlAttributeHandle *handle = NULL;
812
for (mode = NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE;
813
mode <= NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV; mode++) {
815
if (strcmp(houseFormatStrings[mode], str) == 0) {
817
if (find_master(ctk_framelock, NULL, &handle)) {
818
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, mode);
823
} /* house_sync_format_entry_activate() */
828
* add_columns_to_treeview() - add the columns to the treeview,
829
* assigning renderer functions as necessary
832
static void add_columns_to_treeview(CtkFramelock *ctk_framelock)
834
GtkCellRenderer *renderer;
835
GtkTreeViewColumn *column;
837
/* column for display name */
839
renderer = gtk_cell_renderer_text_new();
840
column = gtk_tree_view_column_new_with_attributes("Display",
845
gtk_tree_view_append_column(ctk_framelock->treeview, column);
846
gtk_tree_view_column_set_resizable(column, TRUE);
848
/* column for master toggles */
850
renderer = gtk_cell_renderer_toggle_new();
851
gtk_cell_renderer_toggle_set_radio((GtkCellRendererToggle*)renderer, TRUE);
852
g_signal_connect(renderer, "toggled",
853
G_CALLBACK(master_toggled), ctk_framelock);
855
column = gtk_tree_view_column_new_with_attributes("Master",
860
gtk_tree_view_append_column(ctk_framelock->treeview, column);
861
gtk_tree_view_column_set_resizable(column, TRUE);
864
/* column for stereo */
866
renderer = gtk_cell_renderer_pixbuf_new();
867
column = gtk_tree_view_column_new_with_attributes("Stereo Sync",
871
gtk_tree_view_column_set_cell_data_func(column,
875
(COLUMN_STEREO_SYNC),
878
gtk_tree_view_append_column(ctk_framelock->treeview, column);
879
gtk_tree_view_column_set_resizable(column, TRUE);
881
/* column for timing */
883
renderer = gtk_cell_renderer_pixbuf_new();
884
column = gtk_tree_view_column_new_with_attributes("Timing",
889
* led_renderer_func() needs the ctk_framelock, but only when
890
* dealing with the Timing column; so hook a pointer to
891
* ctk_framelock off of this ViewColumn widget.
894
g_object_set_data(G_OBJECT(column), "ctk_framelock", ctk_framelock);
896
gtk_tree_view_column_set_cell_data_func(column,
899
GINT_TO_POINTER(COLUMN_TIMING),
902
gtk_tree_view_append_column(ctk_framelock->treeview, column);
903
gtk_tree_view_column_set_resizable(column, TRUE);
905
/* column for sync_ready */
907
renderer = gtk_cell_renderer_pixbuf_new();
908
column = gtk_tree_view_column_new_with_attributes("Sync Ready",
912
gtk_tree_view_column_set_cell_data_func(column,
915
GINT_TO_POINTER(COLUMN_SYNC_READY),
918
gtk_tree_view_append_column(ctk_framelock->treeview, column);
919
gtk_tree_view_column_set_resizable(column, TRUE);
922
/* column for sync_rate */
924
renderer = gtk_cell_renderer_text_new();
925
column = gtk_tree_view_column_new_with_attributes("Sync Rate",
928
gtk_tree_view_column_set_cell_data_func(column,
931
GINT_TO_POINTER(COLUMN_SYNC_RATE),
933
gtk_tree_view_append_column(ctk_framelock->treeview, column);
934
gtk_tree_view_column_set_resizable(column, TRUE);
937
/* column for house */
939
renderer = gtk_cell_renderer_pixbuf_new();
940
column = gtk_tree_view_column_new_with_attributes("House",
944
gtk_tree_view_column_set_cell_data_func(column,
947
GINT_TO_POINTER(COLUMN_HOUSE),
950
gtk_tree_view_append_column(ctk_framelock->treeview, column);
951
gtk_tree_view_column_set_resizable(column, TRUE);
953
/* column for rj45 port0 */
955
renderer = gtk_cell_renderer_pixbuf_new();
956
column = gtk_tree_view_column_new_with_attributes("Port0",
959
gtk_tree_view_column_set_cell_data_func(column,
962
GINT_TO_POINTER(COLUMN_RJ45_PORT0),
965
gtk_tree_view_append_column(ctk_framelock->treeview, column);
966
gtk_tree_view_column_set_resizable(column, TRUE);
968
/* column for rj45 port1 */
970
renderer = gtk_cell_renderer_pixbuf_new();
971
column = gtk_tree_view_column_new_with_attributes("Port1",
975
gtk_tree_view_column_set_cell_data_func(column,
978
GINT_TO_POINTER(COLUMN_RJ45_PORT1),
981
gtk_tree_view_append_column(ctk_framelock->treeview, column);
982
gtk_tree_view_column_set_resizable(column, TRUE);
985
/* column for rising edge */
987
renderer = gtk_cell_renderer_toggle_new();
989
g_signal_connect(renderer, "toggled",
990
G_CALLBACK(rising_edge_toggled), ctk_framelock);
992
column = gtk_tree_view_column_new_with_attributes("Rising", renderer,
994
gtk_tree_view_column_set_cell_data_func(column, renderer,
995
polarity_renderer_func,
996
GUINT_TO_POINTER(POLARITY_RISING),
999
gtk_tree_view_append_column(ctk_framelock->treeview, column);
1000
gtk_tree_view_column_set_resizable(column, TRUE);
1003
/* column for falling edge */
1005
renderer = gtk_cell_renderer_toggle_new();
1007
g_signal_connect(renderer, "toggled",
1008
G_CALLBACK(falling_edge_toggled), ctk_framelock);
1010
column = gtk_tree_view_column_new_with_attributes("Falling",
1013
gtk_tree_view_column_set_cell_data_func(column, renderer,
1014
polarity_renderer_func,
1015
GUINT_TO_POINTER(POLARITY_FALLING),
1019
gtk_tree_view_append_column(ctk_framelock->treeview, column);
1020
gtk_tree_view_column_set_resizable(column, TRUE);
1023
/* column for sync skew */
1025
renderer = gtk_cell_renderer_text_new();
1027
g_signal_connect(renderer, "edited",
1028
G_CALLBACK(sync_skew_edited), ctk_framelock);
1030
column = gtk_tree_view_column_new_with_attributes("Sync Skew",
1038
gtk_tree_view_column_set_cell_data_func(column,
1040
sync_skew_renderer_func,
1041
GINT_TO_POINTER(COLUMN_SYNC_SKEW),
1044
gtk_tree_view_append_column(ctk_framelock->treeview, column);
1045
gtk_tree_view_column_set_resizable(column, TRUE);
1047
} /* add_columns_to_treeview() */
1052
* led_renderer_func() - set the cell's pixbuf to either a green or a
1053
* red LED, based on the value in the model for this iter.
1056
static void led_renderer_func(GtkTreeViewColumn *tree_column,
1057
GtkCellRenderer *cell,
1058
GtkTreeModel *model,
1062
static GdkPixbuf *led_green_pixbuf = NULL;
1063
static GdkPixbuf *led_red_pixbuf = NULL;
1064
static GdkPixbuf *led_grey_pixbuf = NULL;
1065
gboolean value, master, framelock_enabled;
1067
gint column, house = 0;
1070
* we hooked a pointer to the ctk_framelock off the ViewColumn
1074
obj = g_object_get_data(G_OBJECT(tree_column), "ctk_framelock");
1076
column = GPOINTER_TO_INT(data);
1078
gtk_tree_model_get(model, iter, column, &value,
1079
COLUMN_MASTER, &master, -1);
1081
framelock_enabled = FALSE;
1083
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(obj);
1084
if (ctk_framelock->framelock_enabled) framelock_enabled = TRUE;
1087
gtk_tree_model_get(model, iter, COLUMN_HOUSE, &house, -1);
1090
* make the master's Timing LED grey if framelock is enabled
1091
* (otherwise, it will be red when framelock is enabled, which is
1094
* If we are receiving house sync, then light the LED green.
1097
if ((column == COLUMN_TIMING) && master && framelock_enabled && !house) {
1098
if (!led_grey_pixbuf)
1099
led_grey_pixbuf = gdk_pixbuf_new_from_xpm_data(led_grey_xpm);
1100
g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", led_grey_pixbuf, NULL);
1101
} else if (value || (house && framelock_enabled && master)) {
1102
if (!led_green_pixbuf)
1103
led_green_pixbuf = gdk_pixbuf_new_from_xpm_data(led_green_xpm);
1104
g_object_set(GTK_CELL_RENDERER(cell),
1105
"pixbuf", led_green_pixbuf, NULL);
1107
if (!led_red_pixbuf)
1108
led_red_pixbuf = gdk_pixbuf_new_from_xpm_data(led_red_xpm);
1109
g_object_set(GTK_CELL_RENDERER(cell), "pixbuf", led_red_pixbuf, NULL);
1111
} /* led_renderer_func() */
1116
* rj45_renderer_func() - set the cell's pixbuf either to the "input"
1117
* rj45 pixbuf or the "output" rj45 pixbuf, based on the value in the
1118
* model for this iter.
1120
* XXX should there be an "unknown" state?
1123
static void rj45_renderer_func(GtkTreeViewColumn *tree_column,
1124
GtkCellRenderer *cell,
1125
GtkTreeModel *model,
1129
static GdkPixbuf *rj45_input_pixbuf = NULL;
1130
static GdkPixbuf *rj45_output_pixbuf = NULL;
1134
column = GPOINTER_TO_INT(data);
1136
gtk_tree_model_get (model, iter, column, &value, -1);
1138
if (value == NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT) {
1139
if (!rj45_input_pixbuf)
1140
rj45_input_pixbuf = gdk_pixbuf_new_from_xpm_data(rj45_input_xpm);
1141
g_object_set(GTK_CELL_RENDERER(cell), "pixbuf",
1142
rj45_input_pixbuf, NULL);
1144
if (!rj45_output_pixbuf)
1145
rj45_output_pixbuf = gdk_pixbuf_new_from_xpm_data(rj45_output_xpm);
1146
g_object_set(GTK_CELL_RENDERER(cell), "pixbuf",
1147
rj45_output_pixbuf, NULL);
1149
} /* rj45_renderer_func() */
1154
* rate_renderer_func() - set the cell's "text" attribute to a string
1155
* representation of the rate in the model at this iter.
1158
static void rate_renderer_func(GtkTreeViewColumn *tree_column,
1159
GtkCellRenderer *cell,
1160
GtkTreeModel *model,
1164
gint column = GPOINTER_TO_INT(data);
1169
gtk_tree_model_get (model, iter, column, &value, -1);
1171
fvalue = (float) value / 1000.0;
1173
snprintf(str, 32, "%6.2f Hz", fvalue);
1175
g_object_set(GTK_CELL_RENDERER(cell), "text", str, NULL);
1177
} /* rate_renderer_func() */
1182
* polarity_renderer_func() - set the attribute "active" to either
1183
* true or false, based on if the bit specified in mask is present in
1184
* the model for this iter.
1187
static void polarity_renderer_func(GtkTreeViewColumn *tree_column,
1188
GtkCellRenderer *cell,
1189
GtkTreeModel *model,
1193
guint value, mask = GPOINTER_TO_UINT(data);
1195
gtk_tree_model_get(model, iter, COLUMN_POLARITY, &value, -1);
1198
g_object_set(GTK_CELL_RENDERER(cell), "active", TRUE, NULL);
1200
g_object_set(GTK_CELL_RENDERER(cell), "active", FALSE, NULL);
1202
} /* polarity_renderer_func() */
1207
* sync_skew_renderer_func() - set the cell's "text" attribute to a
1208
* string representation of the sync delay in the model at this iter.
1211
static void sync_skew_renderer_func(GtkTreeViewColumn *tree_column,
1212
GtkCellRenderer *cell,
1213
GtkTreeModel *model,
1217
gint column = GPOINTER_TO_INT(data);
1222
gtk_tree_model_get (model, iter, column, &value, -1);
1224
delay = ((gfloat) value) * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR;
1226
snprintf(str, 32, "%10.2f uS", delay);
1228
g_object_set (GTK_CELL_RENDERER(cell), "text", str, NULL);
1230
} /* sync_skew_renderer_func() */
1235
* master_toggled() - called whenever a master is assigned.
1238
static void master_toggled(GtkCellRendererToggle *cell,
1242
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(data);
1243
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
1244
GtkTreeIter iter, walking_iter;
1245
GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1246
gboolean master, valid;
1247
gchar *display_name;
1249
NvCtrlAttributeHandle *handle;
1251
/* do not change the master while framelock is enabled */
1253
if (ctk_framelock->framelock_enabled) {
1254
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1255
"Cannot change master while "
1256
"FrameLock is enabled.");
1260
/* get toggled iter */
1262
gtk_tree_model_get_iter(model, &iter, path);
1263
gtk_tree_path_free(path);
1265
/* if we're already the master, do nothing */
1267
gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master,
1268
COLUMN_DISPLAY_NAME, &display_name, -1);
1272
/* walk through the model, and turn off any other masters */
1274
valid = gtk_tree_model_get_iter_first(model, &walking_iter);
1276
gboolean walking_master;
1277
gtk_tree_model_get(model, &walking_iter,
1278
COLUMN_MASTER, &walking_master, -1);
1280
if (walking_master) {
1281
gtk_tree_model_get(model, &walking_iter,
1282
COLUMN_HANDLE, &handle, -1);
1284
gtk_list_store_set(GTK_LIST_STORE(model), &walking_iter,
1285
COLUMN_MASTER, FALSE, -1);
1286
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER,
1287
NV_CTRL_FRAMELOCK_MASTER_FALSE);
1291
valid = gtk_tree_model_iter_next(model, &walking_iter);
1295
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COLUMN_MASTER,
1298
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1);
1299
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER,
1300
NV_CTRL_FRAMELOCK_MASTER_TRUE);
1302
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1303
"X Screen '%s' assigned master.",
1306
update_house_sync_controls(ctk_framelock);
1308
} /* master_toggled() */
1310
static void polarity_toggled(GtkCellRendererToggle *cell,
1311
CtkFramelock *ctk_framelock,
1315
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
1320
NvCtrlAttributeHandle *handle;
1321
gchar *polarity_str;
1323
path = gtk_tree_path_new_from_string(path_string);
1324
gtk_tree_model_get_iter(model, &iter, path);
1325
gtk_tree_path_free(path);
1327
gtk_tree_model_get(model, &iter, COLUMN_POLARITY, &polarity, -1);
1329
g_object_get(GTK_CELL_RENDERER(cell), "active", &enabled, NULL);
1333
/* don't allow the user to turn off the rising edge */
1335
if (mask == NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE) enabled = TRUE;
1337
if (enabled) polarity |= mask;
1338
else polarity &= ~mask;
1340
gtk_list_store_set(ctk_framelock->list_store, &iter,
1341
COLUMN_POLARITY, polarity, -1);
1343
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1);
1345
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_POLARITY, polarity);
1348
case NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE:
1349
polarity_str = "rising";
1351
case NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES:
1352
polarity_str = "rising and falling";
1358
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1359
"Set edge polarity to %s.", polarity_str);
1362
static void rising_edge_toggled(GtkCellRendererToggle *cell,
1366
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
1368
polarity_toggled(cell, ctk_framelock, path_string, POLARITY_RISING);
1371
static void falling_edge_toggled(GtkCellRendererToggle *cell,
1375
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
1377
polarity_toggled(cell, ctk_framelock, path_string, POLARITY_FALLING);
1381
static void sync_skew_edited(GtkCellRendererText *cell,
1382
const gchar *path_string,
1383
const gchar *new_text,
1386
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(data);
1387
NvCtrlAttributeHandle *handle;
1388
GtkTreeModel *model;
1394
delay = strtod(new_text, (char **)NULL);
1396
value = (gint) (delay / NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR);
1398
if (value < 0) value = 0;
1399
if (value > NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX)
1400
value = NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX;
1402
delay = ((gfloat) value) * NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR;
1404
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1405
path = gtk_tree_path_new_from_string(path_string);
1406
gtk_tree_model_get_iter(model, &iter, path);
1407
gtk_tree_path_free(path);
1409
gtk_list_store_set(ctk_framelock->list_store, &iter,
1410
COLUMN_SYNC_SKEW, value, -1);
1412
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1);
1414
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_DELAY, value);
1416
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1417
"Sync delay set to %.2f uS", delay);
1422
/************************************************************************/
1424
* functions relating to add_x_screen_dialog
1429
* add_x_screen_response() - this function gets called in response to
1430
* the "response" event from the "Add X Screen..." dialog box.
1433
static void add_x_screen_response(GtkWidget *button, gint response,
1436
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
1437
const gchar *display_name;
1439
/* hide the dialog box */
1441
gtk_widget_hide_all(ctk_framelock->add_x_screen_dialog);
1443
/* set the focus back to the text entry */
1445
gtk_widget_grab_focus(ctk_framelock->add_x_screen_entry);
1447
/* if the response is not "OK" then we're done */
1449
if (response != GTK_RESPONSE_OK) return;
1451
/* get the display name specified by the user */
1454
gtk_entry_get_text(GTK_ENTRY(ctk_framelock->add_x_screen_entry));
1456
add_x_screen(ctk_framelock, display_name, TRUE);
1461
static gpointer add_x_screen(CtkFramelock *ctk_framelock,
1462
const gchar *display_name, gboolean error_dialog)
1464
GtkTreeModel *model;
1472
/* if no display name specified, print an error and return */
1474
if (!display_name || (display_name[0] == '\0')) {
1477
error_msg(ctk_framelock, "<span weight=\"bold\" size=\"larger\">"
1478
"Unable to add X screen to FrameLock group.</span>\n\n"
1479
"No X Screen specified.");
1481
nv_error_msg("Unable to add X screen to FrameLock group; "
1482
"no X Screen specified.");
1488
* try to prevent users from adding the same X screen more than
1489
* once XXX this is not an absolute check: this does not catch
1490
* "localhost:0.0" versus ":0.0", for example.
1493
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1494
valid = gtk_tree_model_get_iter_first(model, &iter);
1496
gtk_tree_model_get(model, &iter, COLUMN_DISPLAY_NAME, &tmp, -1);
1497
if (nv_strcasecmp(display_name, tmp)) {
1499
error_msg(ctk_framelock, "<span weight=\"bold\" "
1500
"size=\"larger\">Unable to add X screen "
1501
"to FrameLock Group</span>\n\n"
1502
"The X screen %s already belongs to the FrameLock "
1503
"Group.", display_name);
1505
nv_error_msg("Unable to add X screen to FrameLock Group; "
1506
"the X screen %s already belongs to the "
1507
"FrameLock Group.", display_name);
1511
valid = gtk_tree_model_iter_next(model, &iter);
1514
/* open an X Display connection to that X screen */
1516
display = XOpenDisplay(display_name);
1519
error_msg(ctk_framelock, "<span weight=\"bold\" "
1520
"size=\"larger\">Unable "
1521
"to add X screen to FrameLock group</span>\n\nUnable to "
1522
"connect to X Display '%s'.", display_name);
1524
nv_error_msg("Unable to add X screen to FrameLock group; unable "
1525
"to connect to X Display '%s'.", display_name);
1530
/* create a new NV-CONTROL handle */
1532
screen = DefaultScreen(display);
1534
h = NvCtrlAttributeInit(display, screen,
1535
NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM);
1539
error_msg(ctk_framelock, "<span weight=\"bold\" "
1540
"size=\"larger\">Unable "
1541
"to add X screen to FrameLock group</span>\n\nXXX need "
1542
"descriptive message.");
1544
nv_error_msg("Unable to add X screen to FrameLock group.");
1549
/* does this NV-CONTROL handle support FrameLock? */
1551
NvCtrlGetAttribute(h, NV_CTRL_FRAMELOCK, &value);
1552
if (value != NV_CTRL_FRAMELOCK_SUPPORTED) {
1554
error_msg(ctk_framelock, "<span weight=\"bold\" "
1555
"size=\"larger\">Unable "
1556
"to add X screen to FrameLock group</span>\n\n"
1557
"This X Screen does not support FrameLock.");
1559
nv_error_msg("Unable to add X screen to FrameLock group; "
1560
"this X Screen does not support FrameLock.");
1562
NvCtrlAttributeClose(h);
1566
/* XXX need to check that the current modeline matches */
1568
/* add the screen to the list store */
1570
add_member_to_list_store(ctk_framelock, h);
1572
/* update the house sync controls */
1574
update_house_sync_controls(ctk_framelock);
1576
/* enable the "Test Link" and "Enable Framelock" buttons */
1578
gtk_widget_set_sensitive(ctk_framelock->sync_state_button, TRUE);
1580
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1581
"Added X Screen '%s'", display_name);
1585
static GtkWidget *create_add_x_screen_dialog(CtkFramelock *ctk_framelock)
1590
GtkWidget *label, *descr;
1593
GtkWidget *alignment;
1595
dialog = gtk_dialog_new_with_buttons("Add X Screen",
1596
ctk_framelock->parent_window,
1598
GTK_DIALOG_DESTROY_WITH_PARENT |
1599
GTK_DIALOG_NO_SEPARATOR,
1601
GTK_RESPONSE_CANCEL,
1606
g_signal_connect (GTK_OBJECT(dialog), "response",
1607
G_CALLBACK(add_x_screen_response),
1608
GTK_OBJECT(ctk_framelock));
1610
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
1611
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1613
hbox = gtk_hbox_new(FALSE, 12);
1614
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
1615
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
1617
pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION,
1618
GTK_ICON_SIZE_DIALOG, NULL);
1619
image = gtk_image_new_from_pixbuf(pixbuf);
1620
g_object_unref(pixbuf);
1622
label = gtk_label_new("X Screen:");
1623
descr = gtk_label_new("Please specify the X screen to be added to the "
1624
"FrameLock group.");
1626
ctk_framelock->add_x_screen_entry = gtk_entry_new();
1628
gtk_entry_set_text(GTK_ENTRY(ctk_framelock->add_x_screen_entry),
1629
NvCtrlGetDisplayName
1630
(ctk_framelock->attribute_handle));
1632
gtk_entry_set_width_chars
1633
(GTK_ENTRY(ctk_framelock->add_x_screen_entry), 16);
1635
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
1636
gtk_container_add(GTK_CONTAINER(alignment), image);
1637
gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2);
1639
vbox = gtk_vbox_new(FALSE, 12);
1640
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
1642
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
1643
gtk_container_add(GTK_CONTAINER(alignment), descr);
1644
gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
1646
hbox = gtk_hbox_new(FALSE, 12);
1647
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1649
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1650
gtk_box_pack_start(GTK_BOX(hbox), ctk_framelock->add_x_screen_entry,
1655
} /* create_add_x_screen_dialog() */
1658
/************************************************************************/
1660
* functions relating to remove_x_screen_dialog
1664
static void tree_selection_changed(GtkTreeSelection *selection,
1667
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
1669
if (gtk_tree_selection_get_selected(selection, NULL, NULL)) {
1670
gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, TRUE);
1672
gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button,FALSE);
1678
static void remove_x_screen(GtkWidget *button, gint response,
1681
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(user_data);
1683
GtkTreeModel *model;
1685
gchar *display_name;
1687
gtk_widget_hide_all(ctk_framelock->remove_x_screen_dialog);
1689
if (response != GTK_RESPONSE_OK) return;
1691
gtk_tree_model_get(GTK_TREE_MODEL(ctk_framelock->list_store),
1692
&ctk_framelock->remove_x_screen_iter,
1693
COLUMN_DISPLAY_NAME, &display_name, -1);
1695
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1696
"Removed X Screen '%s'", display_name);
1698
/* XXX disable anything that we need to in the X server */
1700
gtk_list_store_remove(GTK_LIST_STORE(ctk_framelock->list_store),
1701
&ctk_framelock->remove_x_screen_iter);
1704
* if there are no entries left, then disable the "Test Link" and
1705
* "Enable FrameLock" buttons.
1708
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1709
valid = gtk_tree_model_get_iter_first(model, &iter);
1711
gtk_widget_set_sensitive(ctk_framelock->sync_state_button, FALSE);
1715
static void show_remove_x_screen_dialog(GtkWidget *button,
1716
CtkFramelock *ctk_framelock)
1719
GtkTreeSelection *selection;
1720
gchar *str, *display_name;
1722
selection = gtk_tree_view_get_selection(ctk_framelock->treeview);
1724
if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1726
gtk_tree_model_get(GTK_TREE_MODEL(ctk_framelock->list_store), &iter,
1727
COLUMN_DISPLAY_NAME, &display_name, -1);
1729
str = g_strconcat("Remove X Screen '", display_name, "'?", NULL);
1730
gtk_label_set_text(GTK_LABEL(ctk_framelock->remove_x_screen_label), str);
1733
ctk_framelock->remove_x_screen_iter = iter;
1735
gtk_widget_show_all(ctk_framelock->remove_x_screen_dialog);
1740
static GtkWidget *create_remove_x_screen_dialog(
1741
CtkFramelock *ctk_framelock
1748
GtkWidget *alignment;
1751
dialog = gtk_dialog_new_with_buttons("Remove X Screen",
1752
ctk_framelock->parent_window,
1754
GTK_DIALOG_DESTROY_WITH_PARENT |
1755
GTK_DIALOG_NO_SEPARATOR,
1757
GTK_RESPONSE_CANCEL,
1762
g_signal_connect(GTK_OBJECT(dialog), "response",
1763
G_CALLBACK(remove_x_screen),
1764
GTK_OBJECT(ctk_framelock));
1766
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
1767
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
1769
hbox = gtk_hbox_new(FALSE, 12);
1770
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
1771
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
1773
pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_QUESTION,
1774
GTK_ICON_SIZE_DIALOG, NULL);
1775
image = gtk_image_new_from_pixbuf(pixbuf);
1776
g_object_unref(pixbuf);
1778
ctk_framelock->remove_x_screen_label = gtk_label_new(NULL);
1780
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
1781
gtk_container_add(GTK_CONTAINER(alignment), image);
1782
gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2);
1784
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
1785
gtk_container_add(GTK_CONTAINER(alignment),
1786
ctk_framelock->remove_x_screen_label);
1787
gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0);
1791
} /* create_remove_x_screen_dialog() */
1795
/************************************************************************/
1797
* function for updating the status
1802
* update_status() - query the following from each member of the sync
1805
* NV_CTRL_FRAMELOCK_STEREO_SYNC
1806
* NV_CTRL_FRAMELOCK_TIMING
1807
* NV_CTRL_FRAMELOCK_SYNC_READY
1808
* NV_CTRL_FRAMELOCK_SYNC_RATE
1809
* NV_CTRL_FRAMELOCK_HOUSE_STATUS
1810
* NV_CTRL_FRAMELOCK_PORT0_STATUS
1811
* NV_CTRL_FRAMELOCK_PORT1_STATUS
1813
* XXX maybe rather than have a button to do this, the app could be
1814
* set to poll (and auto update the gui) periodically?
1817
static gboolean update_status(gpointer user_data)
1821
gint stereo_sync, timing, sync_ready, sync_rate, house, port0, port1;
1822
GtkTreeModel *model;
1823
NvCtrlAttributeHandle *handle;
1824
CtkFramelock *ctk_framelock;
1826
ctk_framelock = CTK_FRAMELOCK(user_data);
1828
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1830
valid = gtk_tree_model_get_iter_first(model, &iter);
1832
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle, -1);
1835
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, &stereo_sync);
1836
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_TIMING, &timing);
1837
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_READY, &sync_ready);
1838
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &sync_rate);
1839
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house);
1840
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT0_STATUS, &port0);
1841
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT1_STATUS, &port1);
1843
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1844
COLUMN_STEREO_SYNC, stereo_sync, -1);
1845
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1846
COLUMN_TIMING, timing, -1);
1847
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1848
COLUMN_SYNC_READY, sync_ready, -1);
1849
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1850
COLUMN_SYNC_RATE, sync_rate, -1);
1851
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1852
COLUMN_HOUSE, house, -1);
1853
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1854
COLUMN_RJ45_PORT0, port0, -1);
1855
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1856
COLUMN_RJ45_PORT1, port1, -1);
1858
valid = gtk_tree_model_iter_next(model, &iter);
1863
} /* update_status() */
1870
* test_link() - tell the master to enable the test signal, update
1871
* everyone's status, and then disable the test signal.
1874
static void test_link(GtkWidget *button, CtkFramelock *ctk_framelock)
1876
gboolean valid, master, enabled;
1878
NvCtrlAttributeHandle *handle;
1879
GtkTreeModel *model;
1881
enabled = gtk_toggle_button_get_active
1882
(GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button));
1884
if (!enabled) return;
1886
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1888
/* find the master handle */
1892
valid = gtk_tree_model_get_iter_first(model, &iter);
1894
gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master, -1);
1896
gtk_tree_model_get(model, &iter, COLUMN_HANDLE,
1900
valid = gtk_tree_model_iter_next(model, &iter);
1903
if (!handle) return;
1905
/* enable the test signal */
1907
gdk_window_set_cursor
1908
((GTK_WIDGET(ctk_framelock->parent_window))->window,
1909
ctk_framelock->wait_cursor);
1911
gtk_grab_add(button);
1913
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_TEST_SIGNAL,
1914
NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE);
1916
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1917
"Test Link started.");
1919
/* register the "done" function */
1921
g_timeout_add(DEFAULT_TEST_LINK_TIME_INTERVAL,
1922
test_link_done, (gpointer) ctk_framelock);
1927
static gint test_link_done(gpointer data)
1929
CtkFramelock *ctk_framelock = (CtkFramelock *) data;
1930
gboolean valid, master;
1932
NvCtrlAttributeHandle *handle;
1933
GtkTreeModel *model;
1935
model = GTK_TREE_MODEL(ctk_framelock->list_store);
1937
/* find the master handle */
1941
valid = gtk_tree_model_get_iter_first(model, &iter);
1943
gtk_tree_model_get(model, &iter, COLUMN_MASTER, &master, -1);
1945
gtk_tree_model_get(model, &iter, COLUMN_HANDLE,
1949
valid = gtk_tree_model_iter_next(model, &iter);
1952
if (!handle) return FALSE;
1954
/* disable the test signal */
1956
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_TEST_SIGNAL,
1957
NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE);
1959
gtk_grab_remove(ctk_framelock->test_link_button);
1961
gdk_window_set_cursor((GTK_WIDGET(ctk_framelock->parent_window))->window,
1964
ctk_config_statusbar_message(ctk_framelock->ctk_config,
1965
"Test Link complete.");
1967
/* un-press the testlink button */
1969
g_signal_handlers_block_by_func
1970
(G_OBJECT(ctk_framelock->test_link_button),
1971
G_CALLBACK(test_link),
1972
(gpointer) ctk_framelock);
1974
gtk_toggle_button_set_active
1975
(GTK_TOGGLE_BUTTON(ctk_framelock->test_link_button), FALSE);
1977
g_signal_handlers_unblock_by_func
1978
(G_OBJECT(ctk_framelock->test_link_button),
1979
G_CALLBACK(test_link),
1980
(gpointer) ctk_framelock);
1986
static GtkWidget *create_sync_state_button(CtkFramelock *ctk_framelock)
1989
GtkWidget *hbox, *hbox2;
1991
GtkWidget *image = NULL;
1994
button = gtk_toggle_button_new();
1996
/* create the enable syncing icon */
1998
pixbuf = gtk_widget_render_icon(button,
2000
GTK_ICON_SIZE_BUTTON,
2001
"enable framelock");
2002
if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf);
2003
label = gtk_label_new("Enable FrameLock");
2005
hbox = gtk_hbox_new(FALSE, 2);
2007
if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2);
2008
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2010
hbox2 = gtk_hbox_new(FALSE, 0);
2011
gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15);
2013
gtk_widget_show_all(hbox2);
2016
* XXX increment the reference count, so that when we do
2017
* gtk_container_remove() later, it doesn't get destroyed
2020
gtk_object_ref(GTK_OBJECT(hbox2));
2022
ctk_framelock->enable_syncing_label = hbox2;
2025
/* create the disable syncing icon */
2027
pixbuf = gtk_widget_render_icon(button,
2029
GTK_ICON_SIZE_BUTTON,
2030
"disable framelock");
2031
if (pixbuf) image = gtk_image_new_from_pixbuf(pixbuf);
2032
label = gtk_label_new("Disable FrameLock");
2034
hbox = gtk_hbox_new(FALSE, 2);
2036
if (image) gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 2);
2037
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
2039
hbox2 = gtk_hbox_new(FALSE, 0);
2040
gtk_box_pack_start(GTK_BOX(hbox2), hbox, FALSE, FALSE, 15);
2042
gtk_widget_show_all(hbox2);
2045
* XXX increment the reference count, so that when we do
2046
* gtk_container_remove() later, it doesn't get destroyed
2049
gtk_object_ref(GTK_OBJECT(hbox2));
2051
ctk_framelock->disable_syncing_label = hbox2;
2053
/* start with syncing disabled */
2055
gtk_container_add(GTK_CONTAINER(button),
2056
ctk_framelock->enable_syncing_label);
2062
static void toggle_sync_state_button(GtkWidget *button,
2063
CtkFramelock *ctk_framelock)
2067
NvCtrlAttributeHandle *handle;
2068
guint display_mask, val;
2070
GtkTreeSelection *selection;
2072
GtkTreeModel *model;
2074
enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
2076
if (enabled) val = NV_CTRL_FRAMELOCK_SYNC_ENABLE;
2077
else val = NV_CTRL_FRAMELOCK_SYNC_DISABLE;
2080
* set the NV_CTRL_FRAMELOCK_SYNC status on each member of the
2085
model = GTK_TREE_MODEL(ctk_framelock->list_store);
2086
valid = gtk_tree_model_get_iter_first(model, &iter);
2088
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle,
2089
COLUMN_DISPLAY_MASK, &display_mask, -1);
2090
if (!handle) return; /* XXX */
2092
NvCtrlSetDisplayAttribute(handle, display_mask,
2093
NV_CTRL_FRAMELOCK_SYNC, val);
2094
valid = gtk_tree_model_iter_next(model, &iter);
2098
* toggle the TEST_SIGNAL, to guarantee accuracy of the universal
2099
* frame count (as returned by the glXQueryFrameCountNV() function
2100
* in the GLX_NV_swap_group extension)
2103
if (enabled && find_master(ctk_framelock, NULL, &handle)) {
2104
NvCtrlSetAttribute(handle,
2105
NV_CTRL_FRAMELOCK_TEST_SIGNAL,
2106
NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE);
2107
NvCtrlSetAttribute(handle,
2108
NV_CTRL_FRAMELOCK_TEST_SIGNAL,
2109
NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE);
2112
/* alter the button */
2115
if (!ctk_framelock->framelock_enabled) {
2117
gtk_container_remove
2118
(GTK_CONTAINER(ctk_framelock->sync_state_button),
2119
ctk_framelock->enable_syncing_label);
2120
gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_state_button),
2121
ctk_framelock->disable_syncing_label);
2125
* disable the "Add Screen" and "Remove Screen" buttons;
2126
* enable the "Test Link" button
2129
gtk_widget_set_sensitive(ctk_framelock->add_x_screen_button, FALSE);
2130
gtk_widget_set_sensitive(ctk_framelock->remove_x_screen_button, FALSE);
2131
gtk_widget_set_sensitive(ctk_framelock->test_link_button, TRUE);
2133
/* disable the house sync controls */
2135
gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, FALSE);
2136
gtk_widget_set_sensitive(ctk_framelock->house_format_frame, FALSE);
2139
if (ctk_framelock->framelock_enabled) {
2140
gtk_container_remove
2141
(GTK_CONTAINER(ctk_framelock->sync_state_button),
2142
ctk_framelock->disable_syncing_label);
2143
gtk_container_add(GTK_CONTAINER(ctk_framelock->sync_state_button),
2144
ctk_framelock->enable_syncing_label);
2147
/* enable the "Add Screen" button; disable the "Test Link" button */
2149
gtk_widget_set_sensitive(ctk_framelock->add_x_screen_button, TRUE);
2150
gtk_widget_set_sensitive(ctk_framelock->test_link_button, FALSE);
2152
/* check if the "Remove Screen" button should be enabled */
2154
selection = gtk_tree_view_get_selection(ctk_framelock->treeview);
2155
tree_selection_changed(selection, GTK_OBJECT(ctk_framelock));
2157
/* enable the house sync controls */
2159
gtk_widget_set_sensitive(ctk_framelock->sync_interval_frame, TRUE);
2160
gtk_widget_set_sensitive(ctk_framelock->house_format_frame, TRUE);
2163
ctk_framelock->framelock_enabled = enabled;
2165
ctk_config_statusbar_message(ctk_framelock->ctk_config,
2167
enabled ? "enabled" : "disabled");
2169
} /* toggle_sync_state_button() */
2172
/************************************************************************/
2174
* functions relating to the error_msg_dialog
2177
static GtkWidget *create_error_msg_dialog(CtkFramelock *ctk_framelock)
2182
GtkWidget *alignment;
2186
dialog = gtk_dialog_new_with_buttons("Error",
2187
ctk_framelock->parent_window,
2189
GTK_DIALOG_DESTROY_WITH_PARENT |
2190
GTK_DIALOG_NO_SEPARATOR,
2195
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
2196
G_CALLBACK(gtk_widget_hide_all),
2197
GTK_OBJECT(dialog));
2199
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
2200
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
2202
hbox = gtk_hbox_new(FALSE, 12);
2203
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
2204
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
2206
pixbuf = gtk_widget_render_icon(dialog, GTK_STOCK_DIALOG_ERROR,
2207
GTK_ICON_SIZE_DIALOG, NULL);
2208
image = gtk_image_new_from_pixbuf(pixbuf);
2209
g_object_unref(pixbuf);
2211
ctk_framelock->error_msg_label = gtk_label_new(NULL);
2213
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
2214
gtk_container_add(GTK_CONTAINER(alignment), image);
2215
gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 2);
2217
alignment = gtk_alignment_new(0.0, 0.0, 0, 0);
2218
gtk_container_add(GTK_CONTAINER(alignment),
2219
ctk_framelock->error_msg_label);
2220
gtk_box_pack_start(GTK_BOX(hbox), alignment, FALSE, FALSE, 0);
2225
static void error_msg(CtkFramelock *ctk_framelock, const gchar *fmt, ...)
2231
msg = nv_build_vararg_string(fmt, ap);
2234
gtk_label_set_line_wrap(GTK_LABEL(ctk_framelock->error_msg_label), TRUE);
2235
gtk_label_set_use_markup(GTK_LABEL(ctk_framelock->error_msg_label), TRUE);
2236
gtk_label_set_markup(GTK_LABEL(ctk_framelock->error_msg_label), msg);
2237
gtk_widget_show_all(ctk_framelock->error_msg_dialog);
2244
/************************************************************************/
2246
* Functions for manipulating the List Store
2250
static void create_list_store(CtkFramelock *ctk_framelock)
2252
GtkTreeSelection *selection;
2254
ctk_framelock->list_store =
2255
gtk_list_store_new(NUM_COLUMNS,
2256
G_TYPE_POINTER, /* HANDLE */
2257
G_TYPE_UINT, /* DISPLAY_MASK */
2258
G_TYPE_STRING, /* DISPLAY_NAME */
2259
G_TYPE_BOOLEAN, /* MASTER */
2260
G_TYPE_BOOLEAN, /* STEREO_SYNC */
2261
G_TYPE_BOOLEAN, /* TIMING */
2262
G_TYPE_BOOLEAN, /* SYNC_READY */
2263
G_TYPE_UINT, /* SYNC_RATE */
2264
G_TYPE_BOOLEAN, /* HOUSE */
2265
G_TYPE_BOOLEAN, /* RJ45_PORT0 */
2266
G_TYPE_BOOLEAN, /* RJ45_PORT1 */
2267
G_TYPE_UINT, /* POLARITY */
2268
G_TYPE_UINT, /* SYNC_SKEW */
2269
G_TYPE_UINT, /* SYNC_INTERVAL */
2270
G_TYPE_UINT); /* HOUSE_FORMAT */
2272
/* create the treeview */
2274
ctk_framelock->treeview =
2275
GTK_TREE_VIEW(gtk_tree_view_new_with_model
2276
(GTK_TREE_MODEL(ctk_framelock->list_store)));
2278
gtk_tree_view_set_rules_hint(ctk_framelock->treeview, TRUE);
2280
g_object_unref(ctk_framelock->list_store);
2282
/* watch for selection changes to the treeview */
2284
selection = gtk_tree_view_get_selection(ctk_framelock->treeview);
2286
g_signal_connect(selection, "changed",
2287
G_CALLBACK(tree_selection_changed),
2288
GTK_OBJECT(ctk_framelock));
2290
/* add columns to the tree view */
2292
add_columns_to_treeview(ctk_framelock);
2294
} /* create_list_store() */
2299
* add_member_to_list_store()
2302
static void add_member_to_list_store(CtkFramelock *ctk_framelock,
2303
const gpointer handle)
2306
GtkTreeModel *model;
2307
gint master, stereo_sync, timing, sync_ready, sync_rate;
2308
gint house, port0, port1, polarity, sync_skew, display_mask;
2309
gint sync_interval, house_format;
2310
gboolean valid, have_master;
2311
gchar *display_name;
2314
* If we don't have a master already, make this the master; if we
2315
* do have a master already, make sure this isn't the master.
2318
have_master = FALSE;
2319
model = GTK_TREE_MODEL(ctk_framelock->list_store);
2321
valid = gtk_tree_model_get_iter_first(model, &iter);
2323
gtk_tree_model_get(model, &iter, COLUMN_MASTER, &have_master, -1);
2324
if (have_master) break;
2325
valid = gtk_tree_model_iter_next(model, &iter);
2328
master = !have_master;
2330
NvCtrlSetAttribute(handle, NV_CTRL_FRAMELOCK_MASTER, master);
2332
/* query all the other fields */
2334
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_STEREO_SYNC, &stereo_sync);
2335
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_TIMING, &timing);
2336
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_READY, &sync_ready);
2337
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_RATE, &sync_rate);
2338
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_HOUSE_STATUS, &house);
2339
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT0_STATUS, &port0);
2340
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_PORT1_STATUS, &port1);
2341
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_POLARITY, &polarity);
2342
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_DELAY, &sync_skew);
2343
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_SYNC_INTERVAL,&sync_interval);
2344
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_VIDEO_MODE, &house_format);
2346
NvCtrlGetAttribute(handle, NV_CTRL_ENABLED_DISPLAYS, &display_mask);
2348
gtk_list_store_append(ctk_framelock->list_store, &iter);
2350
display_name = NvCtrlGetDisplayName(handle);
2352
gtk_list_store_set(ctk_framelock->list_store, &iter,
2353
COLUMN_HANDLE, handle,
2354
COLUMN_DISPLAY_MASK, display_mask,
2355
COLUMN_DISPLAY_NAME, display_name,
2356
COLUMN_MASTER, master,
2357
COLUMN_STEREO_SYNC, stereo_sync,
2358
COLUMN_TIMING, timing,
2359
COLUMN_SYNC_READY, sync_ready,
2360
COLUMN_SYNC_RATE, sync_rate,
2361
COLUMN_HOUSE, house,
2362
COLUMN_RJ45_PORT0, port0,
2363
COLUMN_RJ45_PORT1, port1,
2364
COLUMN_POLARITY, polarity,
2365
COLUMN_SYNC_SKEW, sync_skew,
2366
COLUMN_SYNC_INTERVAL, sync_interval,
2367
COLUMN_HOUSE_FORMAT, house_format,
2370
} /* add_member_to_list_store() */
2373
static gboolean check_for_ethernet(gpointer user_data)
2375
CtkFramelock *ctk_framelock;
2377
GtkTreeModel *model;
2379
NvCtrlAttributeHandle *handle;
2380
gchar *display_name;
2384
ctk_framelock = CTK_FRAMELOCK(user_data);
2385
model = GTK_TREE_MODEL(ctk_framelock->list_store);
2387
valid = gtk_tree_model_get_iter_first(model, &iter);
2389
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &handle,
2390
COLUMN_DISPLAY_NAME, &display_name, -1);
2393
NvCtrlGetAttribute(handle, NV_CTRL_FRAMELOCK_ETHERNET_DETECTED, &val);
2395
if (val != NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_NONE) {
2396
error_msg(ctk_framelock, "<span weight=\"bold\" size=\"larger\">"
2397
"FrameLock RJ45 Error</span>\n\n"
2398
"Either an Ethernet LAN cable is connected to the "
2399
"framelock board on X Screen '%s' or the linked PC is "
2401
"Either disconnect the LAN cable or turn on the linked "
2402
"PC for proper operation.",
2405
ctk_config_remove_timer(ctk_framelock->ctk_config,
2406
(GSourceFunc) check_for_ethernet);
2410
valid = gtk_tree_model_iter_next(model, &iter);
2418
static gboolean find_master(CtkFramelock *ctk_framelock,
2419
GtkTreeIter *return_iter,
2420
NvCtrlAttributeHandle **return_handle)
2422
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
2423
NvCtrlAttributeHandle *handle = NULL;
2424
gboolean master = FALSE, valid;
2427
valid = gtk_tree_model_get_iter_first(model, &iter);
2429
gtk_tree_model_get(model, &iter,
2430
COLUMN_MASTER, &master,
2431
COLUMN_HANDLE, &handle,
2435
valid = gtk_tree_model_iter_next(model, &iter);
2438
if (return_iter) *return_iter = iter;
2439
if (return_handle) *return_handle = handle;
2447
* ctk_framelock_config_file_attributes() - add to the ParsedAttribute
2448
* list any attributes that we want saved in the config file.
2451
void ctk_framelock_config_file_attributes(GtkWidget *w, ParsedAttribute *head)
2453
CtkFramelock *ctk_framelock = CTK_FRAMELOCK(w);
2454
GtkTreeModel *model = GTK_TREE_MODEL(ctk_framelock->list_store);
2456
gboolean master, valid;
2457
gchar *display_name;
2458
guint polarity, display_mask;
2459
gint delay, sync_interval, house_format;
2462
valid = gtk_tree_model_get_iter_first(model, &iter);
2466
* XXX is it sufficient to use sw state, or should we query
2470
gtk_tree_model_get(model, &iter,
2471
COLUMN_DISPLAY_NAME, &display_name,
2472
COLUMN_MASTER, &master,
2473
COLUMN_POLARITY, &polarity,
2474
COLUMN_SYNC_SKEW, &delay,
2475
COLUMN_DISPLAY_MASK, &display_mask,
2476
COLUMN_SYNC_INTERVAL,&sync_interval,
2477
COLUMN_HOUSE_FORMAT, &house_format,
2480
#define __ADD_ATTR(x,y,z) \
2481
a.display = display_name; \
2484
a.display_device_mask = (z); \
2485
nv_parsed_attribute_add(head, &a);
2487
__ADD_ATTR(NV_CTRL_FRAMELOCK_MASTER, master, 0);
2488
__ADD_ATTR(NV_CTRL_FRAMELOCK_POLARITY, polarity, 0);
2489
__ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_DELAY, delay, 0);
2490
__ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC,
2491
ctk_framelock->framelock_enabled, display_mask);
2494
__ADD_ATTR(NV_CTRL_FRAMELOCK_SYNC_INTERVAL, sync_interval, 0);
2495
__ADD_ATTR(NV_CTRL_FRAMELOCK_VIDEO_MODE, house_format, 0);
2500
valid = gtk_tree_model_iter_next(model, &iter);
2502
} /* ctk_framelock_config_file_attributes() */
2507
* apply_parsed_attribute_list() - given a list of parsed attributes
2508
* from the config file, apply the FrameLock settings contained
2512
static void apply_parsed_attribute_list(CtkFramelock *ctk_framelock,
2515
GtkTreeModel *model;
2518
gboolean valid, enable = FALSE;
2519
gchar *display_name, *display_name_tmp;
2523
if (!p->next) goto next_attribute;
2525
if (!(p->flags & NV_PARSER_TYPE_FRAMELOCK)) goto next_attribute;
2528
* canonicalize the display name, so that we have a better
2529
* chance of finding matches when we compare them below
2532
display_name = nv_standardize_screen_name(p->display, -1);
2535
* find the NvCtrlAttributeHandle associated with this display
2536
* name; either there is already an entry in the model with
2537
* the same display name, and we can use its handle; or we add
2538
* this display to the model and get a new handle. As a side
2539
* effect, we should end up with an iter that points into the
2540
* correct entry in the model.
2545
model = GTK_TREE_MODEL(ctk_framelock->list_store);
2546
valid = gtk_tree_model_get_iter_first(model, &iter);
2549
gtk_tree_model_get(model, &iter, COLUMN_DISPLAY_NAME,
2550
&display_name_tmp, -1);
2551
if (nv_strcasecmp(display_name_tmp, display_name)) {
2552
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &h, -1);
2556
valid = gtk_tree_model_iter_next(model, &iter);
2560
h = add_x_screen(ctk_framelock, display_name, FALSE);
2562
if (!h) goto next_attribute;
2564
model = GTK_TREE_MODEL(ctk_framelock->list_store);
2565
valid = gtk_tree_model_get_iter_first(model, &iter);
2568
gtk_tree_model_get(model, &iter, COLUMN_HANDLE, &h_tmp, -1);
2570
if (h == h_tmp) break;
2571
valid = gtk_tree_model_iter_next(model, &iter);
2576
* now that we have an NvCtrlAttributeHandle and iter, apply
2577
* the setting; note that this only really updates the gui,
2578
* but the attributes have already been sent to the X server
2579
* by the config file parser.
2583
case NV_CTRL_FRAMELOCK_MASTER:
2585
/* XXX only allow one master */
2587
gtk_list_store_set(ctk_framelock->list_store, &iter,
2588
COLUMN_MASTER, p->val, -1);
2591
case NV_CTRL_FRAMELOCK_POLARITY:
2592
gtk_list_store_set(ctk_framelock->list_store, &iter,
2593
COLUMN_POLARITY, p->val, -1);
2596
case NV_CTRL_FRAMELOCK_SYNC_DELAY:
2597
gtk_list_store_set(ctk_framelock->list_store, &iter,
2598
COLUMN_SYNC_SKEW, p->val, -1);
2601
case NV_CTRL_FRAMELOCK_SYNC:
2602
if (p->val) enable = TRUE;
2605
case NV_CTRL_FRAMELOCK_SYNC_INTERVAL:
2606
gtk_list_store_set(ctk_framelock->list_store, &iter,
2607
COLUMN_SYNC_INTERVAL, p->val, -1);
2610
case NV_CTRL_FRAMELOCK_VIDEO_MODE:
2611
gtk_list_store_set(ctk_framelock->list_store, &iter,
2612
COLUMN_HOUSE_FORMAT, p->val, -1);
2622
* set the state of the toggle button appropriately; this will
2623
* trigger toggle_sync_state_button()
2626
gtk_toggle_button_set_active
2627
(GTK_TOGGLE_BUTTON(ctk_framelock->sync_state_button), enable);
2629
} /* apply_parsed_attribute_list () */
2633
GtkTextBuffer *ctk_framelock_create_help(GtkTextTagTable *table)
2638
b = gtk_text_buffer_new(table);
2640
gtk_text_buffer_get_iter_at_offset(b, &i, 0);
2642
ctk_help_title(b, &i, "FrameLock Help");
2644
ctk_help_para(b, &i, "The FrameLock control page provides a way to "
2645
"manage an entire cluster of workstations in a FrameLock "
2648
ctk_help_heading(b, &i, "Add X Screen...");
2649
ctk_help_para(b, &i, "Use this button to add an X Screen to the "
2650
"FrameLock group. If the X Screen is remote, be sure "
2651
"you have configured remote access (via `xhost`, "
2652
"for example) such that you are allowed to establish "
2655
ctk_help_heading(b, &i, "Remove X Screen...");
2656
ctk_help_para(b, &i, "Use this button to remove the currently selected "
2657
"X Screen from the FrameLock group. If no X Screen is "
2658
"currently selected, then this button is greyed out.");
2660
ctk_help_heading(b, &i, "Test Link");
2661
ctk_help_para(b, &i, "Use this toggle button to enable testing of "
2662
"the cabling between all members of the FrameLock group. "
2663
"This will cause all FrameLock boards to receive a sync "
2664
"pulse, but the GPUs will not lock to the FrameLock "
2665
"pulse. When Test Link is enabled, no other settings may "
2666
"be changed until you disable Test Link.");
2668
ctk_help_heading(b, &i, "Enable FrameLock");
2669
ctk_help_para(b, &i, "This will lock the refresh rates of all members "
2670
"in the FrameLock group. When FrameLock is enabled, "
2671
"you cannot add or remove any X screens from the FrameLock "
2672
"group, nor can you enable the Test Link.");
2674
ctk_help_heading(b, &i, "Display");
2675
ctk_help_para(b, &i, "The 'Display' column lists the name of each X "
2676
"Screen in the FrameLock group.");
2678
ctk_help_heading(b, &i, "Master");
2679
ctk_help_para(b, &i, "This radio button indicates which X Screen in the "
2680
"FrameLock group will emit the master sync pulse to which "
2681
"all other group members will latch.");
2683
ctk_help_heading(b, &i, "Stereo Sync");
2684
ctk_help_para(b, &i, "This indicates that the GPU stereo signal is in "
2685
"sync with the framelock stereo signal.");
2687
ctk_help_heading(b, &i, "Timing");
2688
ctk_help_para(b, &i, "This indicates that the FrameLock board is "
2689
"receiving a timing input.");
2691
ctk_help_heading(b, &i, "Sync Ready");
2692
ctk_help_para(b, &i, "This indicates whether the FrameLock board is "
2693
"receiving sync pulses. Green means syncing; red "
2694
"means not syncing.");
2696
ctk_help_heading(b, &i, "Sync Rate");
2697
ctk_help_para(b, &i, "This is the sync rate that the FrameLock board "
2700
ctk_help_heading(b, &i, "House");
2701
ctk_help_para(b, &i, "This indicates whether the FrameLock board is "
2702
"receiving synchronization from the house (BNC) connector.");
2704
ctk_help_heading(b, &i, "Port0, Port1");
2705
ctk_help_para(b, &i, "These indicate the status of the RJ45 ports on "
2706
"the backplane of the FrameLock board. Green LEDs "
2707
"indicate that the port is configured for input, while "
2708
"yellow LEDs indicate that the port is configured for "
2711
ctk_help_heading(b, &i, "Rising/Falling");
2712
ctk_help_para(b, &i, "These control which edge(s) of the sync pulse "
2715
ctk_help_heading(b, &i, "Sync Delay");
2716
ctk_help_para(b, &i, "The delay (in microseconds) between the FrameLock "
2717
"pulse and the GPU pulse.");
2719
ctk_help_heading(b, &i, "Miscellaneous");
2720
ctk_help_para(b, &i, "The FrameLock control page registers several timers "
2721
"that are executed periodically; these are listed "
2722
"in the 'Active Timers' section of the 'nvidia-settings "
2723
"Configuration' page. Most notably is the "
2724
"'FrameLock Connection Status' "
2725
"timer: this will poll all members of the FrameLock group "
2726
"for status information.");