21
21
#include "application.h"
23
#include "devices_dialog.h"
24
#include <dbus/dbus-glib.h>
25
#include <dbus/dbus-glib-lowlevel.h>
26
27
#define GCONF_PATH "/apps/me-tv"
27
#define CURRENT_DATABASE_VERSION 5
30
void on_record(GtkObject *object, gpointer user_data)
32
g_debug("Handler: %s", __PRETTY_FUNCTION__);
33
get_application().on_record();
38
get_application().get_main_window().hide();
42
void on_next_channel(GtkObject *object, gpointer user_data)
44
g_debug("Handler: %s", __PRETTY_FUNCTION__);
45
get_application().next_channel();
48
void on_previous_channel(GtkObject *object, gpointer user_data)
50
g_debug("Handler: %s", __PRETTY_FUNCTION__);
51
get_application().previous_channel();
54
void on_change_view_mode(GtkObject *object, gpointer user_data)
56
g_debug("Handler: %s", __PRETTY_FUNCTION__);
57
get_application().get_main_window().on_change_view_mode();
60
void on_devices(GtkObject *object, gpointer user_data)
62
g_debug("Handler: %s", __PRETTY_FUNCTION__);
63
get_application().get_main_window().on_devices();
68
g_debug("Handler: %s", __PRETTY_FUNCTION__);
69
get_application().get_main_window().on_channels();
72
void on_scheduled_recordings()
74
g_debug("Handler: %s", __PRETTY_FUNCTION__);
75
get_application().get_main_window().on_scheduled_recordings();
80
g_debug("Handler: %s", __PRETTY_FUNCTION__);
81
get_application().get_main_window().on_meters();
84
void on_preferences(GtkObject *object, gpointer user_data)
86
g_debug("Handler: %s", __PRETTY_FUNCTION__);
87
get_application().get_main_window().on_preferences();
92
g_debug("Handler: %s", __PRETTY_FUNCTION__);
93
get_application().get_main_window().on_fullscreen();
98
g_debug("Handler: %s", __PRETTY_FUNCTION__);
99
get_application().get_main_window().on_mute();
102
void on_audio_channel_both()
104
g_debug("Handler: %s", __PRETTY_FUNCTION__);
105
get_application().get_main_window().on_audio_channel_both();
108
void on_audio_channel_left()
110
g_debug("Handler: %s", __PRETTY_FUNCTION__);
111
get_application().get_main_window().on_audio_channel_left();
114
void on_audio_channel_right()
116
g_debug("Handler: %s", __PRETTY_FUNCTION__);
117
get_application().get_main_window().on_audio_channel_right();
122
g_debug("Handler: %s", __PRETTY_FUNCTION__);
123
get_application().get_main_window().on_about();
28
#define CURRENT_DATABASE_VERSION 6
127
30
Application* Application::current = NULL;
186
85
g_debug("Loading UI files");
188
87
builder = Gtk::Builder::create_from_file(PACKAGE_DATA_DIR"/me-tv/glade/me-tv.ui");
189
builder->add_from_file(PACKAGE_DATA_DIR"/me-tv/glade/me-tv-actions.ui");
89
toggle_action_fullscreen = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("toggle_action_fullscreen"));
90
toggle_action_mute = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("toggle_action_mute"));
91
toggle_action_record = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("toggle_action_record"));
93
action_about = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_about"));
94
action_channels = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_channels"));
95
action_change_view_mode = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_change_view_mode"));
96
action_epg_event_search = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_epg_event_search"));
97
action_next_channel = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_next_channel"));
98
action_preferences = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_preferences"));
99
action_previous_channel = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_previous_channel"));
100
action_quit = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_quit"));
101
action_scheduled_recordings = Glib::RefPtr<Gtk::Action>::cast_dynamic(builder->get_object("action_scheduled_recordings"));
103
Glib::RefPtr<Gtk::ActionGroup> action_group = Gtk::ActionGroup::create();
104
action_group->add(toggle_action_record, Gtk::AccelKey("R"));
105
action_group->add(toggle_action_fullscreen, Gtk::AccelKey("F"));
106
action_group->add(toggle_action_mute, Gtk::AccelKey("M"));
108
action_group->add(action_about, Gtk::AccelKey("F1"));
109
action_group->add(action_channels);
110
action_group->add(action_change_view_mode, Gtk::AccelKey("V"));
111
action_group->add(action_epg_event_search);
112
action_group->add(action_next_channel, Gtk::AccelKey("<Ctrl>Down"));
113
action_group->add(action_preferences);
114
action_group->add(action_previous_channel, Gtk::AccelKey("<Ctrl>Up"));
115
action_group->add(action_quit);
116
action_group->add(action_scheduled_recordings);
118
action_group->add(Gtk::Action::create("action_file", _("_File")));
119
action_group->add(Gtk::Action::create("action_view", _("_View")));
120
action_group->add(Gtk::Action::create("action_video", _("_Video")));
121
action_group->add(Gtk::Action::create("action_audio", _("_Audio")));
122
action_group->add(Gtk::Action::create("action_help", _("_Help")));
124
action_group->add(Gtk::Action::create("action_subtitle_streams", _("Subtitles")));
125
action_group->add(Gtk::Action::create("action_audio_streams", _("_Streams")));
126
action_group->add(Gtk::Action::create("action_audio_channels", _("_Channels")));
128
Gtk::RadioButtonGroup radio_button_group_audio_channel;
129
action_group->add(Gtk::RadioAction::create(radio_button_group_audio_channel, "action_audio_channel_both", _("_Both")));
130
action_group->add(Gtk::RadioAction::create(radio_button_group_audio_channel, "action_audio_channel_left", _("_Left")));
131
action_group->add(Gtk::RadioAction::create(radio_button_group_audio_channel, "action_audio_channel_right", _("_Right")));
133
action_quit->signal_activate().connect(sigc::ptr_fun(Gtk::Main::quit));
134
toggle_action_record->signal_activate().connect(sigc::mem_fun(*this, &Application::on_record));
135
action_next_channel->signal_activate().connect(sigc::mem_fun(*this, &Application::on_next_channel));
136
action_previous_channel->signal_activate().connect(sigc::mem_fun(*this, &Application::on_previous_channel));
138
ui_manager = Gtk::UIManager::create();
139
ui_manager->insert_action_group(action_group);
191
141
g_debug("Application constructed");
213
170
g_debug("Application destructor complete");
173
void Application::on_record()
175
Glib::RecMutex::Lock lock(mutex);
177
if (toggle_action_record->get_active())
181
start_recording(stream_manager.get_display_channel());
183
catch (const Glib::Exception& exception)
185
toggle_action_record->set_active(false);
186
throw Exception(exception.what());
190
toggle_action_record->set_active(false);
191
throw Exception(_("Failed to start recording"));
196
stream_manager.stop_recording(stream_manager.get_display_channel());
197
g_debug("Recording stopped");
203
void Application::on_previous_channel()
205
/* Channel* channel = channel_manager.get_previous_channel();
208
set_display_channel(*channel);
213
void Application::on_next_channel()
215
/* Channel* channel = channel_manager.get_next_channel();
218
set_display_channel(*channel);
222
void Application::on_quit()
224
get_application().get_main_window().hide();
216
228
void Application::make_directory_with_parents(const Glib::ustring& path)
218
230
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(path);
219
231
if (!file->query_exists())
221
233
Glib::RefPtr<Gio::File> parent = file->get_parent();
222
if (parent->query_exists())
224
g_debug("Creating directory '%s'", path.c_str());
225
file->make_directory();
234
if (!parent->query_exists())
229
236
make_directory_with_parents(parent->get_path());
239
g_debug("Creating directory '%s'", path.c_str());
240
file->make_directory();
301
311
table_scheduled_recording.name = "scheduled_recording";
302
312
table_scheduled_recording.columns.add("scheduled_recording_id", Data::DATA_TYPE_INTEGER, 0, false);
303
313
table_scheduled_recording.columns.add("description", Data::DATA_TYPE_STRING, 200, false);
304
table_scheduled_recording.columns.add("type", Data::DATA_TYPE_INTEGER, 0, false);
314
table_scheduled_recording.columns.add("recurring_type", Data::DATA_TYPE_INTEGER, 0, false);
315
table_scheduled_recording.columns.add("action_after", Data::DATA_TYPE_INTEGER, 0, false);
305
316
table_scheduled_recording.columns.add("channel_id", Data::DATA_TYPE_INTEGER, 0, false);
306
317
table_scheduled_recording.columns.add("start_time", Data::DATA_TYPE_INTEGER, 0, false);
307
318
table_scheduled_recording.columns.add("duration", Data::DATA_TYPE_INTEGER, 0, false);
391
402
void Application::set_string_configuration_default(const Glib::ustring& key, const Glib::ustring& value)
393
404
Glib::ustring path = get_configuration_path(key);
394
Gnome::Conf::Value v = client->get(path);
405
Gnome::Conf::Value v = gconf_client->get(path);
395
406
if (v.get_type() == Gnome::Conf::VALUE_INVALID)
397
408
g_debug("Setting string configuration value '%s' = '%s'", key.c_str(), value.c_str());
398
client->set(path, value);
409
gconf_client->set(path, value);
402
413
void Application::set_int_configuration_default(const Glib::ustring& key, gint value)
404
415
Glib::ustring path = get_configuration_path(key);
405
Gnome::Conf::Value v = client->get(path);
416
Gnome::Conf::Value v = gconf_client->get(path);
406
417
if (v.get_type() == Gnome::Conf::VALUE_INVALID)
408
419
g_debug("Setting int configuration value '%s' = '%d'", path.c_str(), value);
409
client->set(path, value);
420
gconf_client->set(path, value);
413
424
void Application::set_boolean_configuration_default(const Glib::ustring& key, gboolean value)
415
426
Glib::ustring path = get_configuration_path(key);
416
Gnome::Conf::Value v = client->get(path);
427
Gnome::Conf::Value v = gconf_client->get(path);
417
428
if (v.get_type() == Gnome::Conf::VALUE_INVALID)
419
430
g_debug("Setting int configuration value '%s' = '%s'", path.c_str(), value ? "true" : "false");
420
client->set(path, (bool)value);
431
gconf_client->set(path, (bool)value);
435
StringList Application::get_string_list_configuration_value(const Glib::ustring& key)
437
return gconf_client->get_string_list(get_configuration_path(key));
424
440
Glib::ustring Application::get_string_configuration_value(const Glib::ustring& key)
426
return client->get_string(get_configuration_path(key));
442
return gconf_client->get_string(get_configuration_path(key));
429
445
gint Application::get_int_configuration_value(const Glib::ustring& key)
431
return client->get_int(get_configuration_path(key));
447
return gconf_client->get_int(get_configuration_path(key));
434
450
gint Application::get_boolean_configuration_value(const Glib::ustring& key)
436
return client->get_bool(get_configuration_path(key));
452
return gconf_client->get_bool(get_configuration_path(key));
455
void Application::set_string_list_configuration_value(const Glib::ustring& key, const StringList& value)
457
gconf_client->set_string_list(get_configuration_path(key), value);
439
460
void Application::set_string_configuration_value(const Glib::ustring& key, const Glib::ustring& value)
441
client->set(get_configuration_path(key), value);
462
gconf_client->set(get_configuration_path(key), value);
444
465
void Application::set_int_configuration_value(const Glib::ustring& key, gint value)
446
client->set(get_configuration_path(key), (gint)value);
467
gconf_client->set(get_configuration_path(key), (gint)value);
449
470
void Application::set_boolean_configuration_value(const Glib::ustring& key, gboolean value)
451
client->set(get_configuration_path(key), (bool)value);
472
gconf_client->set(get_configuration_path(key), (bool)value);
454
475
void Application::select_channel_to_play()
456
const ChannelArray& channels = channel_manager.get_channels();
477
ChannelArray& channels = channel_manager.get_channels();
457
478
if (channels.size() > 0)
459
480
gint last_channel_id = get_application().get_int_configuration_value("last_channel");
468
489
g_debug("Last channel '%d' not found", last_channel_id);
469
channel_manager.select_display_channel();
490
set_display_channel(channels[0]);
474
495
void Application::run()
477
497
GdkLock gdk_lock;
479
if (initialise_database())
499
if (!initialise_database())
481
g_debug("Me TV database initialised successfully");
483
const FrontendList& frontends = device_manager.get_frontends();
485
if (!default_device.empty())
487
Dvb::Frontend* default_frontend = device_manager.find_frontend_by_path(default_device);
489
if (default_frontend == NULL)
491
Glib::ustring message = Glib::ustring::compose(
492
_("Failed to load default device '%1'"), default_device);
493
throw Exception(message);
496
device_manager.set_frontend(*default_frontend);
500
if (frontends.size() > 0)
502
device_manager.set_frontend(**frontends.begin());
501
throw Exception(_("Failed to initialise database"));
504
g_debug("Me TV database initialised");
506
status_icon = new StatusIcon();
507
main_window = MainWindow::create(builder);
506
511
channel_manager.load(connection);
508
status_icon = new StatusIcon();
509
main_window = MainWindow::create(builder);
511
timeout_source = gdk_threads_add_timeout(1000, &Application::on_timeout, this);
515
if (!device_manager.get_frontends().empty())
517
scheduled_recording_manager.load(connection);
526
main_window->show_preferences_dialog();
513
stream_manager.load();
514
stream_manager.start();
516
ChannelArray& channels = channel_manager.get_channels();
518
const FrontendList& frontends = device_manager.get_frontends();
519
if (!frontends.empty())
521
scheduled_recording_manager.load(connection);
523
if (!channels.empty())
525
select_channel_to_play();
535
main_window->show_preferences_dialog();
530
ChannelArray& channels = channel_manager.get_channels();
539
// Check that there's a device
540
device_manager.check_frontend();
531
542
if (channels.empty())
533
main_window->show_channels_dialog();
536
select_channel_to_play();
539
if (channel_manager.has_display_channel())
541
stream_manager.start();
546
if (status_icon != NULL)
552
if (main_window != NULL)
544
main_window->show_channels_dialog();
549
main_window->on_exception();
552
timeout_source = gdk_threads_add_timeout(1000, &Application::on_timeout, this);
562
556
Application& Application::get_current()
612
593
set_display_channel(channel_manager.get_channel_by_index(channel_index));
615
void Application::set_display_channel(const Channel& channel)
596
void Application::set_display_channel(Channel& channel)
617
598
g_message(_("Changing channel to '%s'"), channel.name.c_str());
619
if (channel_manager.has_display_channel())
621
Channel& current_channel = channel_manager.get_display_channel();
622
if (current_channel.transponder == channel.transponder)
624
g_message(_("Already tuned to correct frequency"));
628
if (stream_manager.is_recording())
630
Glib::ustring message = Glib::ustring::compose(
631
_("You cannot tune to channel '%1' because you are recording."),
633
throw Exception(message);
637
if (current_channel != channel)
639
main_window->stop_engine();
643
channel_manager.set_display_channel(channel);
644
stream_manager.set_display_stream(channel);
600
main_window->stop_engine();
603
stream_manager.start_display(channel);
607
main_window->on_exception();
609
toggle_action_record->set_active(stream_manager.is_recording(stream_manager.get_display_channel()));
645
611
main_window->start_engine();
647
613
set_int_configuration_value("last_channel", channel.channel_id);
682
std::list<StreamManager::ChannelStream>& streams = stream_manager.get_streams();
683
for (std::list<StreamManager::ChannelStream>::iterator i = streams.begin(); i != streams.end(); i++)
648
FrontendThreadList& frontend_threads = stream_manager.get_frontend_threads();
649
for (FrontendThreadList::iterator i = frontend_threads.begin(); i != frontend_threads.end(); i++)
685
StreamManager::ChannelStream& channel_stream = *i;
687
channel_stream.type == StreamManager::CHANNEL_STREAM_TYPE_SCHEDULED_RECORDING &&
688
!scheduled_recording_manager.is_recording(channel_stream.channel))
651
FrontendThread& frontend_thread = **i;
652
ChannelStreamList& streams = frontend_thread.get_streams();
653
for (ChannelStreamList::iterator j = streams.begin(); j != streams.end(); j++)
690
stream_manager.stop_recording(channel_stream.channel);
655
ChannelStream& channel_stream = **j;
656
guint scheduled_recording_id = scheduled_recording_manager.is_recording(channel_stream.channel);
658
channel_stream.type == CHANNEL_STREAM_TYPE_SCHEDULED_RECORDING &&
659
(signed)scheduled_recording_id >= 0)
661
stream_manager.stop_recording(channel_stream.channel);
662
action_after(scheduled_recording_id);
671
void Application::action_after(guint action)
673
if (action == SCHEDULED_RECORDING_ACTION_AFTER_CLOSE)
675
g_message("Me-TV closed by Scheduled Recording");
676
action_quit->activate();
678
else if (action == SCHEDULED_RECORDING_ACTION_AFTER_SHUTDOWN)
680
g_message("Computer Shutdown by Scheduled Recording");
682
GError *error = NULL;
683
DBusGConnection *connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
684
if (connection == NULL)
686
throw Exception("Failed to get DBus session");
689
DBusGProxy* proxy = dbus_g_proxy_new_for_name (connection,
690
"org.gnome.SessionManager",
691
"/org/gnome/SessionManager",
692
"org.gnome.SessionManager");
695
throw Exception("Failed to get org.gnome.SessionManager proxy");
698
if (!dbus_g_proxy_call(proxy, "Shutdown", &error, G_TYPE_INVALID, G_TYPE_INVALID))
700
throw Exception("Failed to call Shutdown method");
703
g_message("Shutdown requested");
698
707
gboolean Application::on_timeout(gpointer data)
700
709
return ((Application*)data)->on_timeout();
719
727
last_seconds = seconds;
726
Glib::ustring Application::make_recording_filename(Channel& channel, const Glib::ustring& description)
728
Glib::ustring start_time = get_local_time_text("%c");
729
Glib::ustring filename;
730
Glib::ustring title = description;
735
if (channel.epg_events.get_current(epg_event))
737
title = epg_event.get_title();
743
filename = Glib::ustring::compose
752
filename = Glib::ustring::compose
762
Glib::ustring::size_type position = Glib::ustring::npos;
763
while ((position = filename.find('/')) != Glib::ustring::npos)
765
filename.replace(position, 1, "_");
768
if (get_boolean_configuration_value("remove_colon"))
770
while ((position = filename.find(':')) != Glib::ustring::npos )
772
filename.replace(position, 1, "_");
776
Glib::ustring fixed_filename = Glib::filename_from_utf8(filename);
778
return Glib::build_filename(get_string_configuration_value("recording_directory"), fixed_filename);
781
732
Glib::StaticRecMutex& Application::get_mutex()
786
void Application::on_error(const Glib::ustring& message)
737
void Application::start_recording(Channel& channel)
788
g_debug("Error message: '%s'", message.c_str());
789
if (main_window != NULL)
791
FullscreenBugWorkaround fullscreen_bug_workaround;
792
Gtk::MessageDialog dialog(*main_window, message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
793
dialog.set_title(_("Me TV - Error Message"));
798
Gtk::MessageDialog dialog(message, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
799
dialog.set_title(_("Me TV - Error Message"));
739
stream_manager.start_recording(channel);
804
void Application::start_recording(Channel& channel, const Glib::ustring& description, gboolean scheduled)
743
void Application::start_recording(Channel& channel, const ScheduledRecording& scheduled_recording)
806
stream_manager.start_recording(channel, make_recording_filename(channel, description), scheduled);
745
stream_manager.start_recording(channel, scheduled_recording);
809
g_debug("Recording started");
812
749
void Application::stop_recording(Channel& channel)
814
751
stream_manager.stop_recording(channel);
818
void Application::on_record()
820
Glib::RecMutex::Lock lock(mutex);
823
if (Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("record"))->get_active())
827
start_recording(channel_manager.get_display_channel());
829
catch (const Glib::Exception& exception)
831
Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("record"))->set_active(false);
832
throw Exception(exception.what());
836
Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(builder->get_object("record"))->set_active(false);
837
throw Exception(_("Failed to start recording"));
842
stream_manager.stop_recording(channel_manager.get_display_channel());
843
g_debug("Recording stopped");