Rhythmboxで1曲ループを実現する −5−

はい、ということで前回の続きです。

 

早速ですが、前回扱ったrb_shell_player_get_playback_state関数が使われているrb_shell_player_sync_control_state関数をいじります。

 

static void
rb_shell_player_sync_control_state (RBShellPlayer *player)
{
	gboolean shuffle, repeat;
	GAction *action;
	rb_debug ("syncing control state");

	if (!rb_shell_player_get_playback_state (player, &shuffle,
						 &repeat))
		return;


	action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-shuffle");
	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (shuffle));

	action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-repeat");
	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (repeat));
}

 ここはボタンの状態とそのフラグを同期させる処理を行う部分です。このままだとシャッフルか通常ループにした対応していないので、ここに1曲ループに関する記述を加えます。

 

また、シャッフルや通常ループがonの時、1曲ループはoffになり、1曲ループがonの時はその他はoffになっている方が自然です。

これも対応させましょう。

static void
rb_shell_player_sync_control_state (RBShellPlayer *player)
{
	gboolean shuffle, repeat, repeat1;
	GAction *action;
	rb_debug ("syncing control state");

	if (!rb_shell_player_get_playback_state_loop1 (player, &repeat1))
	{
		if (!rb_shell_player_get_playback_state (player, &shuffle,&repeat))
		{
			return;
		}
		action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
						     "play-shuffle");
		g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (shuffle));
	
		action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
						     "play-repeat");
		g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (repeat));

		repeat1 = 0;
		action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-repeat1");
		g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (repeat1));

		return;
	}

	shuffle = 0;
	repeat = 0;
	loop1_flag = repeat1;

	action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-shuffle");
	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (shuffle));

	action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-repeat");
	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (repeat));

	action = g_action_map_lookup_action (G_ACTION_MAP (g_application_get_default ()),
					     "play-repeat1");
	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (repeat1));
}

 

こんな感じです。

 

何をしているかというと、

①現在の状態を調べる。それが"linear1"か"linear-loop1"のいずれかであればif文を素通り。別の状態であれば元々の処理(+1曲ループボタンをoffにする処理)を行って関数を抜ける。

②"linear1"か"linear-loop1"ならシャッフルボタンと通常ループボタンをoffにし、かつ、1曲ループボタンをフラグに合わせて関数を抜ける。

と言った具合です。

 

ふぅ。

 

これで大きな部分は終わりです。細かいところを直していきます。

まずは念の為loop1_flagを初期化。

前回state_to_play_order_loop1を書いた次の行あたりに、

gboolean loop1_flag = FALSE;

と一行書きましょう。

 

次。

play_repeat_action_cbとplay_shuffle_action_cb内でloop1_flagをFALSEにします。

static void
play_repeat_action_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
	RBShellPlayer *player = RB_SHELL_PLAYER (user_data);
	const char *neworder;
	gboolean shuffle = FALSE;
	gboolean repeat = FALSE;
	rb_debug ("repeat changed");

	if (player->priv->syncing_state)
		return;

	rb_shell_player_get_playback_state (player, &shuffle, &repeat);

	repeat = !repeat;
	loop1_flag = FALSE;
	
	neworder = state_to_play_order[shuffle ? 1 : 0][repeat ? 1 : 0];
	g_settings_set_string (player->priv->settings, "play-order", neworder);
}

 

static void
play_shuffle_action_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
	RBShellPlayer *player = RB_SHELL_PLAYER (user_data);
	const char *neworder;
	gboolean shuffle = FALSE;
	gboolean repeat = FALSE;

	if (player->priv->syncing_state)
		return;

	rb_debug ("shuffle changed");

	rb_shell_player_get_playback_state (player, &shuffle, &repeat);

	shuffle = !shuffle;
	loop1_flag = FALSE;
	
	neworder = state_to_play_order[shuffle ? 1 : 0][repeat ? 1 : 0];
	g_settings_set_string (player->priv->settings, "play-order", neworder);
}

 

更にもうひとつ。

rb_shell_player_init関数内で、

(前略)

    rb_shell_player_add_play_order (player, "linear", N_("Linear"),
					RB_TYPE_LINEAR_PLAY_ORDER, FALSE);
    rb_shell_player_add_play_order (player, "linear-loop", N_("Linear looping"),
					RB_TYPE_LINEAR_PLAY_ORDER_LOOP, FALSE);
    rb_shell_player_add_play_order (player, "linear1", N_("Linear1"),
					RB_TYPE_LINEAR_PLAY_ORDER, FALSE);
    rb_shell_player_add_play_order (player, "linear-loop1", N_("Linear looping one"),
					RB_TYPE_LINEAR_PLAY_ORDER, FALSE);
    rb_shell_player_add_play_order (player, "shuffle", N_("Shuffle"),
					RB_TYPE_SHUFFLE_PLAY_ORDER, FALSE);
(後略)

 

他と対応するように青字を追加します。

これでrb-shell-player.cに対する変更は終わりです。

 

最後の最後。

rb-shell-player.hで関数を宣言するのとrb-shell.cにボタンの構築に関する記述をして実装完了です。長かった……。

 

ではrb-shell-player.h内で

(前略)
gboolean                rb_shell_player_get_playback_state(RBShellPlayer *player,
							   gboolean *shuffle,
							   gboolean *repeat);

gboolean                rb_shell_player_get_playback_state_loop1(RBShellPlayer *player,
							   	 gboolean *repeat1);
(後略)

 青字部分を宣言します。

 

そしてrb-shell.c内のconstruct_load_ui関数にて、

static void
construct_load_ui (RBShell *shell)
{

(中略)

	/* this seems a bit unnecessary */
	gtk_actionable_set_action_target_value (GTK_ACTIONABLE (gtk_builder_get_object (builder, "shuffle-button")),
						g_variant_new_boolean (TRUE));
	gtk_actionable_set_action_target_value (GTK_ACTIONABLE (gtk_builder_get_object (builder, "repeat-button")),
						g_variant_new_boolean (TRUE));
	gtk_actionable_set_action_target_value (GTK_ACTIONABLE (gtk_builder_get_object (builder, "repeat1-button")),
						g_variant_new_boolean (TRUE));
(後略)

 

……はい。

これで完成です!!

やったあ!!

 

次回はまとめとちょっとしたおまけです。