Prompterプログラムの解説(2/3)
GUIの設定
次にGUIの設定の中味を見てみましょう。pmpt_gui_config()は「gui.c」で定義されています。
void pmpt_gui_config (PmptGUI* gui) { /* 1. note window setting */ pmpt_gui_note_window_config (gui); /* 2. slide window setting */ if (pmpt_opt_is_fullscreen (gui->ctrl->opt)) { pmpt_gui_slide_window_config (gui); } /* 3. current slide window setting */ if (pmpt_opt_is_currentslide (gui->ctrl->opt)) { pmpt_gui_current_window_config (gui); } /* 4. next slide window setting */ if (pmpt_opt_is_nextslide (gui->ctrl->opt)) { pmpt_gui_next_window_config (gui); } }
順番に、ノート表示のウィンドウ設定、外部ディスプレイに出力するスライド表示の設定、発表者画面に出す現在のスライドのウィンドウ設定、同じく次のスライドのウィンドウ設定の順番で設定用の関数を呼んでいます。ノート表示以外は、表示するかしないかをオプションで選べるため、if文で選択的に呼び出すようになっています。
ノート表示ウィンドウの設定
少し長いのですが、ノート表示用のウィンドウを設定する関数を次に示します。大まかに説明すると、トップレベルのウィンドウ(GtkWindow)の中にスクロール用のウィンドウ(GtkScrolledWindow)を配置し、さらにその中にテキスト表示用のウィジット(GtkTextView)を入れ込んでいます。なおGtkTextViewに関連付けられたテキストバッファGtkTextBufferは後から内容を変更できるように、PmptGUI型のデータから参照できるようにしています。
static void pmpt_gui_note_window_config (PmptGUI* gui) { GtkWidget* window; GtkWidget* scroll_window; GtkWidget* text; GtkTextBuffer* text_buffer; gchar* str = pmpt_data_get_current_page (gui->ctrl->data) ->note; /* get the note text of the first page */ text_buffer = gtk_text_buffer_new (gtk_text_tag_table_new ()); gtk_text_buffer_set_text (text_buffer, str, -1); text = gtk_text_view_new_with_buffer (text_buffer); /* GtkTextView settings */ gtk_text_view_set_editable (GTK_TEXT_VIEW (text), false); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text), GTK_WRAP_CHAR); /* GtkWindow settings */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); scroll_window = gtk_scrolled_window_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (window), scroll_window); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll_window), text); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_window_set_title (GTK_WINDOW (window), "Prompt"); gtk_window_resize (GTK_WINDOW (window), gui->textarea_width, gui->textarea_height); gtk_widget_show_all (window); /* signal bindings (& key press handling) */ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (pmpt_gui_quit), NULL); gtk_key_snooper_install (pmpt_gui_key_press_handler, gui); gui->text_buffer = text_buffer; }
この関数で、gtk_widget_show_all()の呼び出しまでが、GUIと関連するテキストバッファの設定です。すべてのウィジットの関連を構築した後で、gtk_widget_show_all()を呼び出すことによってGUIが画面に表示されます。
次にgtk_signal_connect()関数で、ユーザーの操作などで生じたイベント(GTK+ではシグナルと呼びます)と呼び出される関数の設定を行います。ウィンドウマネージャなどによってウィンドウの破棄が行われると、「destroy」シグナルが発生します。ここではそのシグナルに対してpmpt_gui_quit()が呼ばれるように設定しています。
またその次の関数gtk_key_snooper_install()では、イベントループが回っている間に、キーボードから何か押されたときに呼び出されるべき関数を設定しています。この設定により、キーボードから入力があるとpmpt_gui_key_press_handler()が呼び出されるようになります。
スライド表示の設定
スライド表示はウィンドウを全画面サイズに拡げて表示させることで実現しています。構造は比較的簡単で、トップレベルのウィンドウ(GtkWindow)の中にイメージ表示用のウィジット(GtkImage)を貼り込んでいるだけです。
static void pmpt_gui_slide_window_config (PmptGUI* gui) { GtkWidget* window; GtkWidget* image_widget; PmptPage* page = pmpt_data_get_current_page (gui->ctrl->data); PmptOpt* opt = gui->ctrl->opt; gchar* image_filename = page->image_filename; int width, height; /* get the display name which shows slides */ gchar* slide_display_name = pmpt_opt_get_slide_display (opt); GdkDisplay* display = gdk_display_open (slide_display_name); GdkScreen* screen; if (display == NULL) { g_warning ("cannot open display: %s", slide_display_name); exit (-1); } screen = gdk_display_get_default_screen (display); /* GtkWindow settings */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_screen (GTK_WINDOW (window), screen); image_widget = gtk_image_new (); gtk_container_add (GTK_CONTAINER (window), image_widget); gtk_window_set_title (GTK_WINDOW (window), "Slide Show"); /* set fullscreen mode */ width = gdk_screen_get_width (screen); height = gdk_screen_get_height (screen); gtk_window_fullscreen (GTK_WINDOW (window)); gtk_widget_show_all (window); /* signal bindings (& key press handling) */ gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (pmpt_gui_quit), NULL); gui->slide_window = image_widget; gui->slide_width = width; gui->slide_height = height; /* set the first slide image */ pmpt_gui_update_slide (gui, image_filename); }
ここでのポイントは次の部分です。GTK+の低レベル描画レイヤを提供するGDK(Graphics Drawing Kit)のAPIを利用して、スライドを表示するディスプレイを選択します。ここでリモートPCのXサーバが提供するディスプレイを指定すれば、スライドはネットワークで接続された投影用PCに表示されるという仕掛けです。
GdkDisplay* display = gdk_display_open (slide_display_name); GdkScreen* screen; if (display == NULL) { g_warning ("cannot open display: %s", slide_display_name); exit (-1); } screen = gdk_display_get_default_screen (display); /* GtkWindow settings */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_screen (GTK_WINDOW (window), screen);
なおここでも、設定終了後にウィジットを表示させ、シグナルを結びつけています。キーボード入力のピックアップは既に設定済みなので必要ありません。また最後にpmpt_gui_update_slide()を呼び出して1枚めのスライドを表示するようにしています。
発表者画面に表示するウィンドウの設定
発表者画面に出す現在のスライドのウィンドウと、次のスライドのウィンドウの設定も同様です。やはりトップレベルのウィンドウ(GtkWindow)の中にイメージ表示用のウィジット(GtkImage)を配置した構造になっています。それぞれの関数の記述はほとんど同じなので、ここでの解説は割愛します。別のディスプレイへの表示や全画面表示のための設定がないぶん、より単純な定義になっています。
