| 777 | | enum |
| | 777 | SIGNAL_STARTUP_COMPLETE, |
| | 778 | SIGNAL_SHUTDOWN_COMPLETE, |
| | 779 | SIGNAL_QUIT, |
| | 780 | N_SIGNALS, |
| | 781 | }; |
| | 782 | |
| | 783 | static guint signals[N_SIGNALS]; |
| | 784 | |
| | 785 | static gpointer parent_class; |
| | 786 | |
| | 787 | static GType |
| | 788 | get_type (); |
| | 789 | |
| | 790 | static DBusMPX * |
| | 791 | create (Player &, DBusGConnection*); |
| | 792 | |
| | 793 | static void |
| | 794 | class_init (gpointer klass, |
| | 795 | gpointer class_data); |
| | 796 | |
| | 797 | static GObject * |
| | 798 | constructor (GType type, |
| | 799 | guint n_construct_properties, |
| | 800 | GObjectConstructParam * construct_properties); |
| | 801 | |
| | 802 | static gboolean |
| | 803 | ui_raise (DBusMPX * self, |
| | 804 | GError ** error); |
| | 805 | |
| | 806 | static gboolean |
| | 807 | startup (DBusMPX * self, |
| | 808 | int no_network, |
| | 809 | GError ** error); |
| | 810 | |
| | 811 | static void |
| | 812 | startup_complete (DBusMPX * self); |
| | 813 | |
| | 814 | static void |
| | 815 | shutdown_complete (DBusMPX * self); |
| | 816 | |
| | 817 | static void |
| | 818 | quit (DBusMPX * self); |
| | 819 | }; |
| | 820 | |
| | 821 | gpointer Player::DBusMPX::parent_class = 0; |
| | 822 | guint Player::DBusMPX::signals[N_SIGNALS] = { 0 }; |
| | 823 | |
| | 824 | // HACK: Hackery to rename functions in glue |
| | 825 | #define mpx_startup startup |
| | 826 | #define mpx_ui_raise ui_raise |
| | 827 | |
| | 828 | #include "dbus-obj-MPX-glue.h" |
| | 829 | |
| | 830 | void |
| | 831 | Player::DBusMPX::class_init (gpointer klass, gpointer class_data) |
| | 832 | { |
| | 833 | parent_class = g_type_class_peek_parent (klass); |
| | 834 | |
| | 835 | GObjectClass *gobject_class = reinterpret_cast<GObjectClass*>(klass); |
| | 836 | gobject_class->constructor = &DBusMPX::constructor; |
| | 837 | |
| | 838 | signals[SIGNAL_STARTUP_COMPLETE] = |
| | 839 | g_signal_new ("startup-complete", |
| | 840 | G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)), |
| | 841 | GSignalFlags (G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED), |
| | 842 | 0, |
| | 843 | NULL, NULL, |
| | 844 | g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); |
| | 845 | |
| | 846 | signals[SIGNAL_SHUTDOWN_COMPLETE] = |
| | 847 | g_signal_new ("shutdown-complete", |
| | 848 | G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)), |
| | 849 | GSignalFlags (G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED), |
| | 850 | 0, |
| | 851 | NULL, NULL, |
| | 852 | g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); |
| | 853 | |
| | 854 | signals[SIGNAL_QUIT] = |
| | 855 | g_signal_new ("quit", |
| | 856 | G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)), |
| | 857 | GSignalFlags (G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED), |
| | 858 | 0, |
| | 859 | NULL, NULL, |
| | 860 | g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); |
| | 861 | } |
| | 862 | |
| | 863 | GObject * |
| | 864 | Player::DBusMPX::constructor (GType type, |
| | 865 | guint n_construct_properties, |
| | 866 | GObjectConstructParam* construct_properties) |
| | 867 | { |
| | 868 | GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties); |
| | 869 | |
| | 870 | return object; |
| | 871 | } |
| | 872 | |
| | 873 | Player::DBusMPX * |
| | 874 | Player::DBusMPX::create (Player & player, DBusGConnection * session_bus) |
| | 875 | { |
| | 876 | dbus_g_object_type_install_info (TYPE_DBUS_OBJ_MPX, &dbus_glib_mpx_object_info); |
| | 877 | |
| | 878 | DBusMPX * self = DBUS_OBJ_MPX (g_object_new (TYPE_DBUS_OBJ_MPX, NULL)); |
| | 879 | self->player = &player; |
| | 880 | |
| | 881 | if(session_bus) |
| | 882 | { |
| | 883 | dbus_g_connection_register_g_object (session_bus, "/MPX", G_OBJECT(self)); |
| | 884 | g_message("%s: /MPX Object registered on session DBus", G_STRLOC); |
| | 885 | } |
| | 886 | |
| | 887 | return self; |
| | 888 | } |
| | 889 | |
| | 890 | GType |
| | 891 | Player::DBusMPX::get_type () |
| | 892 | { |
| | 893 | static GType type = 0; |
| | 894 | |
| | 895 | if (G_UNLIKELY (type == 0)) |
| 804 | | g_message("LOADING Source plugin: %s", mpath.c_str ()); |
| 805 | | |
| 806 | | module.make_resident(); |
| 807 | | |
| 808 | | SourcePluginPtr plugin = SourcePluginPtr (new SourcePlugin()); |
| 809 | | if (!g_module_symbol (module.gobj(), "get_instance", (gpointer*)(&plugin->get_instance))) |
| 810 | | { |
| 811 | | g_message("Source plugin load FAILURE '%s': get_instance hook missing", mpath.c_str ()); |
| 812 | | return false; |
| 813 | | } |
| 814 | | |
| 815 | | if (!g_module_symbol (module.gobj(), "del_instance", (gpointer*)(&plugin->del_instance))) |
| 816 | | { |
| 817 | | g_message("Source plugin load FAILURE '%s': del_instance hook missing", mpath.c_str ()); |
| 818 | | return false; |
| 819 | | } |
| 820 | | |
| 821 | | |
| 822 | | PlaybackSource * p = plugin->get_instance(*this); |
| 823 | | Gtk::Alignment * a = new Gtk::Alignment; |
| 824 | | p->get_ui()->reparent(*a); |
| 825 | | a->show(); |
| 826 | | m_ref_xml->get_widget("sourcepages", m_MainNotebook); |
| 827 | | m_MainNotebook->append_page(*a); |
| 828 | | m_Sources->addSource( p->get_name(), p->get_icon() ); |
| 829 | | m_SourceV.push_back(p); |
| 830 | | install_source(m_SourceCtr++, /* tab # */ m_PageCtr++); |
| 831 | | |
| 832 | | return false; |
| 833 | | } |
| 834 | | |
| 835 | | void |
| 836 | | Player::on_volume_value_changed (double volume) |
| 837 | | { |
| 838 | | m_Play->property_volume() = volume*100; |
| 839 | | mcs->key_set("mpx","volume", int(volume*100)); |
| 840 | | } |
| 841 | | |
| 842 | | bool |
| 843 | | Player::on_seek_event (GdkEvent *event) |
| 844 | | { |
| 845 | | if( event->type == GDK_KEY_PRESS ) |
| 846 | | { |
| 847 | | GdkEventKey * ev = ((GdkEventKey*)(event)); |
| 848 | | gint64 status = m_Play->property_status().get_value(); |
| 849 | | if((status == PLAYSTATUS_PLAYING) || (status == PLAYSTATUS_PAUSED)) |
| 850 | | { |
| 851 | | gint64 pos = m_Play->property_position().get_value(); |
| 852 | | |
| 853 | | int delta = (ev->state & GDK_SHIFT_MASK) ? 1 : 15; |
| 854 | | |
| 855 | | if(ev->keyval == GDK_Left) |
| 856 | | { |
| 857 | | m_Play->seek( pos - delta ); |
| 858 | | return true; |
| 859 | | } |
| 860 | | else if(ev->keyval == GDK_Right) |
| 861 | | { |
| 862 | | m_Play->seek( pos + delta ); |
| 863 | | return true; |
| 864 | | } |
| 865 | | } |
| 866 | | return false; |
| 867 | | } |
| 868 | | else if( event->type == GDK_BUTTON_PRESS ) |
| 869 | | { |
| 870 | | g_atomic_int_set(&m_Seeking,1); |
| 871 | | goto SET_SEEK_POSITION; |
| 872 | | } |
| 873 | | else if( event->type == GDK_BUTTON_RELEASE && g_atomic_int_get(&m_Seeking)) |
| 874 | | { |
| 875 | | g_atomic_int_set(&m_Seeking,0); |
| 876 | | m_Play->seek (gint64(m_Seek->get_value())); |
| 877 | | } |
| 878 | | else if( event->type == GDK_MOTION_NOTIFY && g_atomic_int_get(&m_Seeking)) |
| 879 | | { |
| 880 | | SET_SEEK_POSITION: |
| 881 | | |
| 882 | | guint64 duration = m_Play->property_duration().get_value(); |
| 883 | | guint64 position = m_Seek->get_value(); |
| 884 | | |
| 885 | | guint64 m_pos = position / 60; |
| 886 | | guint64 m_dur = duration / 60; |
| 887 | | guint64 s_pos = position % 60; |
| 888 | | guint64 s_dur = duration % 60; |
| 889 | | |
| 890 | | static boost::format time_f ("%02d:%02d ⊠%02d:%02d"); |
| 891 | | |
| 892 | | m_TimeLabel->set_text ((time_f % m_pos % s_pos % m_dur % s_dur).str()); |
| 893 | | } |
| 894 | | return false; |
| 895 | | } |
| 896 | | |
| 897 | | void |
| 898 | | Player::on_play_metadata (MPXGstMetadataField field) |
| 899 | | { |
| 900 | | MPXGstMetadata const& m = m_Play->get_metadata(); |
| 901 | | |
| 902 | | switch (field) |
| 903 | | { |
| 904 | | case FIELD_IMAGE: |
| 905 | | m_Metadata.Image = m.m_image.get(); |
| 906 | | m_InfoArea->set_image (m.m_image.get()->scale_simple (72, 72, Gdk::INTERP_HYPER)); |
| 907 | | return; |
| 908 | | |
| 909 | | case FIELD_TITLE: |
| 910 | | return; |
| 911 | | |
| 912 | | case FIELD_ALBUM: |
| 913 | | break; |
| 914 | | |
| 915 | | case FIELD_AUDIO_BITRATE: |
| 916 | | break; |
| 917 | | |
| 918 | | case FIELD_AUDIO_CODEC: |
| 919 | | break; |
| 920 | | |
| 921 | | case FIELD_VIDEO_CODEC: |
| 922 | | break; |
| 923 | | } |
| 924 | | } |
| 925 | | |
| 926 | | void |
| 927 | | Player::on_play_position (guint64 position) |
| 928 | | { |
| 929 | | if (g_atomic_int_get(&m_Seeking)) |
| 930 | | return; |
| 931 | | |
| 932 | | guint64 duration = m_Play->property_duration().get_value(); |
| 933 | | |
| 934 | | if( (duration > 0) && (position <= duration) && (position >= 0) ) |
| 935 | | { |
| 936 | | if (duration <= 0) |
| 937 | | return; |
| 938 | | |
| 939 | | if (position < 0) |
| 940 | | return; |
| 941 | | |
| 942 | | guint64 m_pos = position / 60; |
| 943 | | guint64 s_pos = position % 60; |
| 944 | | guint64 m_dur = duration / 60; |
| 945 | | guint64 s_dur = duration % 60; |
| 946 | | |
| 947 | | static boost::format time_f ("%02d:%02d ⊠%02d:%02d"); |
| 948 | | |
| 949 | | m_TimeLabel->set_text((time_f % m_pos % s_pos % m_dur % s_dur).str()); |
| 950 | | m_Seek->set_range(0., duration); |
| 951 | | m_Seek->set_value(double (position)); |
| 952 | | |
| 953 | | #if 0 |
| 954 | | if( m_popup ) |
| 955 | | { |
| 956 | | m_popup->set_position (position, duration); |
| 957 | | } |
| 958 | | #endif |
| 959 | | |
| 960 | | } |
| 961 | | } |
| | 913 | return type; |
| | 914 | } |
| | 915 | |
| | 916 | gboolean |
| | 917 | Player::DBusMPX::ui_raise (DBusMPX* self, GError** error) |
| | 918 | { |
| | 919 | return TRUE; |
| | 920 | } |
| | 921 | |
| | 922 | gboolean |
| | 923 | Player::DBusMPX::startup (DBusMPX* self, |
| | 924 | int no_network, |
| | 925 | GError** error) |
| | 926 | { |
| | 927 | return TRUE; |
| | 928 | } |
| | 929 | |
| | 930 | void |
| | 931 | Player::DBusMPX::startup_complete (DBusMPX* self) |
| | 932 | { |
| | 933 | g_signal_emit (self, signals[SIGNAL_STARTUP_COMPLETE], 0); |
| | 934 | } |
| | 935 | |
| | 936 | void |
| | 937 | Player::DBusMPX::shutdown_complete (DBusMPX* self) |
| | 938 | { |
| | 939 | g_signal_emit (self, signals[SIGNAL_SHUTDOWN_COMPLETE], 0); |
| | 940 | } |
| | 941 | |
| | 942 | void |
| | 943 | Player::DBusMPX::quit (DBusMPX *self) |
| | 944 | { |
| | 945 | g_signal_emit (self, signals[SIGNAL_QUIT], 0); |
| | 946 | } |
| | 947 | |
| | 1180 | |
| | 1181 | void |
| | 1182 | Player::init_dbus () |
| | 1183 | { |
| | 1184 | DBusGProxy * m_SessionBus_proxy; |
| | 1185 | guint dbus_request_name_result; |
| | 1186 | GError * error = NULL; |
| | 1187 | |
| | 1188 | m_SessionBus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); |
| | 1189 | if (!m_SessionBus) |
| | 1190 | { |
| | 1191 | g_error_free (error); |
| | 1192 | return; |
| | 1193 | } |
| | 1194 | |
| | 1195 | m_SessionBus_proxy = dbus_g_proxy_new_for_name (m_SessionBus, |
| | 1196 | "org.freedesktop.DBus", |
| | 1197 | "/org/freedesktop/DBus", |
| | 1198 | "org.freedesktop.DBus"); |
| | 1199 | |
| | 1200 | if (!dbus_g_proxy_call (m_SessionBus_proxy, "RequestName", &error, |
| | 1201 | G_TYPE_STRING, "info.backtrace.mpx", |
| | 1202 | G_TYPE_UINT, 0, |
| | 1203 | G_TYPE_INVALID, |
| | 1204 | G_TYPE_UINT, &dbus_request_name_result, |
| | 1205 | G_TYPE_INVALID)) |
| | 1206 | { |
| | 1207 | g_critical ("%s: RequestName Request Failed: %s", G_STRFUNC, error->message); |
| | 1208 | g_error_free (error); |
| | 1209 | error = NULL; |
| | 1210 | } |
| | 1211 | else |
| | 1212 | { |
| | 1213 | switch (dbus_request_name_result) |
| | 1214 | { |
| | 1215 | case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: |
| | 1216 | { |
| | 1217 | break; |
| | 1218 | } |
| | 1219 | |
| | 1220 | case DBUS_REQUEST_NAME_REPLY_EXISTS: |
| | 1221 | { |
| | 1222 | g_object_unref(m_SessionBus); |
| | 1223 | m_SessionBus = NULL; |
| | 1224 | return; |
| | 1225 | } |
| | 1226 | } |
| | 1227 | } |
| | 1228 | |
| | 1229 | g_message("%s: info.backtrace.mpx service registered on session DBus", G_STRLOC); |
| | 1230 | } |
| | 1231 | |
| | 1232 | void |
| | 1233 | Player::get_object (PAccess<MPX::Library> & pa) |
| | 1234 | { |
| | 1235 | pa = PAccess<MPX::Library>(m_Library); |
| | 1236 | } |
| | 1237 | |
| | 1238 | void |
| | 1239 | Player::get_object (PAccess<MPX::Amazon::Covers> & pa) |
| | 1240 | { |
| | 1241 | pa = PAccess<MPX::Amazon::Covers>(m_Covers); |
| | 1242 | } |
| | 1243 | |
| | 1244 | bool |
| | 1245 | Player::load_source_plugin (std::string const& path) |
| | 1246 | { |
| | 1247 | enum |
| | 1248 | { |
| | 1249 | LIB_BASENAME, |
| | 1250 | LIB_PLUGNAME, |
| | 1251 | LIB_SUFFIX |
| | 1252 | }; |
| | 1253 | |
| | 1254 | const std::string type = "mpxsource"; |
| | 1255 | |
| | 1256 | std::string basename (path_get_basename (path)); |
| | 1257 | std::string pathname (path_get_dirname (path)); |
| | 1258 | |
| | 1259 | if (!is_module (basename)) |
| | 1260 | return false; |
| | 1261 | |
| | 1262 | StrV subs; |
| | 1263 | split (subs, basename, is_any_of ("-.")); |
| | 1264 | std::string name = type + std::string("-") + subs[LIB_PLUGNAME]; |
| | 1265 | std::string mpath = Module::build_path (build_filename(PLUGIN_DIR, "sources"), name); |
| | 1266 | |
| | 1267 | Module module (mpath, ModuleFlags (0)); |
| | 1268 | if (!module) |
| | 1269 | { |
| | 1270 | g_message("Source plugin load FAILURE '%s': %s", mpath.c_str (), module.get_last_error().c_str()); |
| | 1271 | return false; |
| | 1272 | } |
| | 1273 | |
| | 1274 | g_message("LOADING Source plugin: %s", mpath.c_str ()); |
| | 1275 | |
| | 1276 | module.make_resident(); |
| | 1277 | |
| | 1278 | SourcePluginPtr plugin = SourcePluginPtr (new SourcePlugin()); |
| | 1279 | if (!g_module_symbol (module.gobj(), "get_instance", (gpointer*)(&plugin->get_instance))) |
| | 1280 | { |
| | 1281 | g_message("Source plugin load FAILURE '%s': get_instance hook missing", mpath.c_str ()); |
| | 1282 | return false; |
| | 1283 | } |
| | 1284 | |
| | 1285 | if (!g_module_symbol (module.gobj(), "del_instance", (gpointer*)(&plugin->del_instance))) |
| | 1286 | { |
| | 1287 | g_message("Source plugin load FAILURE '%s': del_instance hook missing", mpath.c_str ()); |
| | 1288 | return false; |
| | 1289 | } |
| | 1290 | |
| | 1291 | |
| | 1292 | PlaybackSource * p = plugin->get_instance(*this); |
| | 1293 | Gtk::Alignment * a = new Gtk::Alignment; |
| | 1294 | p->get_ui()->reparent(*a); |
| | 1295 | a->show(); |
| | 1296 | m_ref_xml->get_widget("sourcepages", m_MainNotebook); |
| | 1297 | m_MainNotebook->append_page(*a); |
| | 1298 | m_Sources->addSource( p->get_name(), p->get_icon() ); |
| | 1299 | m_SourceV.push_back(p); |
| | 1300 | install_source(m_SourceCtr++, /* tab # */ m_PageCtr++); |
| | 1301 | |
| | 1302 | return false; |
| | 1303 | } |
| | 1304 | |
| | 1305 | void |
| | 1306 | Player::on_volume_value_changed (double volume) |
| | 1307 | { |
| | 1308 | m_Play->property_volume() = volume*100; |
| | 1309 | mcs->key_set("mpx","volume", int(volume*100)); |
| | 1310 | } |
| | 1311 | |
| | 1312 | bool |
| | 1313 | Player::on_seek_event (GdkEvent *event) |
| | 1314 | { |
| | 1315 | if( event->type == GDK_KEY_PRESS ) |
| | 1316 | { |
| | 1317 | GdkEventKey * ev = ((GdkEventKey*)(event)); |
| | 1318 | gint64 status = m_Play->property_status().get_value(); |
| | 1319 | if((status == PLAYSTATUS_PLAYING) || (status == PLAYSTATUS_PAUSED)) |
| | 1320 | { |
| | 1321 | gint64 pos = m_Play->property_position().get_value(); |
| | 1322 | |
| | 1323 | int delta = (ev->state & GDK_SHIFT_MASK) ? 1 : 15; |
| | 1324 | |
| | 1325 | if(ev->keyval == GDK_Left) |
| | 1326 | { |
| | 1327 | m_Play->seek( pos - delta ); |
| | 1328 | return true; |
| | 1329 | } |
| | 1330 | else if(ev->keyval == GDK_Right) |
| | 1331 | { |
| | 1332 | m_Play->seek( pos + delta ); |
| | 1333 | return true; |
| | 1334 | } |
| | 1335 | } |
| | 1336 | return false; |
| | 1337 | } |
| | 1338 | else if( event->type == GDK_BUTTON_PRESS ) |
| | 1339 | { |
| | 1340 | g_atomic_int_set(&m_Seeking,1); |
| | 1341 | goto SET_SEEK_POSITION; |
| | 1342 | } |
| | 1343 | else if( event->type == GDK_BUTTON_RELEASE && g_atomic_int_get(&m_Seeking)) |
| | 1344 | { |
| | 1345 | g_atomic_int_set(&m_Seeking,0); |
| | 1346 | m_Play->seek (gint64(m_Seek->get_value())); |
| | 1347 | } |
| | 1348 | else if( event->type == GDK_MOTION_NOTIFY && g_atomic_int_get(&m_Seeking)) |
| | 1349 | { |
| | 1350 | SET_SEEK_POSITION: |
| | 1351 | |
| | 1352 | guint64 duration = m_Play->property_duration().get_value(); |
| | 1353 | guint64 position = m_Seek->get_value(); |
| | 1354 | |
| | 1355 | guint64 m_pos = position / 60; |
| | 1356 | guint64 m_dur = duration / 60; |
| | 1357 | guint64 s_pos = position % 60; |
| | 1358 | guint64 s_dur = duration % 60; |
| | 1359 | |
| | 1360 | static boost::format time_f ("%02d:%02d ⊠%02d:%02d"); |
| | 1361 | |
| | 1362 | m_TimeLabel->set_text ((time_f % m_pos % s_pos % m_dur % s_dur).str()); |
| | 1363 | } |
| | 1364 | return false; |
| | 1365 | } |
| | 1366 | |
| | 1367 | void |
| | 1368 | Player::on_play_metadata (MPXGstMetadataField field) |
| | 1369 | { |
| | 1370 | MPXGstMetadata const& m = m_Play->get_metadata(); |
| | 1371 | |
| | 1372 | switch (field) |
| | 1373 | { |
| | 1374 | case FIELD_IMAGE: |
| | 1375 | m_Metadata.Image = m.m_image.get(); |
| | 1376 | m_InfoArea->set_image (m.m_image.get()->scale_simple (72, 72, Gdk::INTERP_HYPER)); |
| | 1377 | return; |
| | 1378 | |
| | 1379 | case FIELD_TITLE: |
| | 1380 | return; |
| | 1381 | |
| | 1382 | case FIELD_ALBUM: |
| | 1383 | break; |
| | 1384 | |
| | 1385 | case FIELD_AUDIO_BITRATE: |
| | 1386 | break; |
| | 1387 | |
| | 1388 | case FIELD_AUDIO_CODEC: |
| | 1389 | break; |
| | 1390 | |
| | 1391 | case FIELD_VIDEO_CODEC: |
| | 1392 | break; |
| | 1393 | } |
| | 1394 | } |
| | 1395 | |
| | 1396 | void |
| | 1397 | Player::on_play_position (guint64 position) |
| | 1398 | { |
| | 1399 | if (g_atomic_int_get(&m_Seeking)) |
| | 1400 | return; |
| | 1401 | |
| | 1402 | guint64 duration = m_Play->property_duration().get_value(); |
| | 1403 | |
| | 1404 | if( (duration > 0) && (position <= duration) && (position >= 0) ) |
| | 1405 | { |
| | 1406 | if (duration <= 0) |
| | 1407 | return; |
| | 1408 | |
| | 1409 | if (position < 0) |
| | 1410 | return; |
| | 1411 | |
| | 1412 | guint64 m_pos = position / 60; |
| | 1413 | guint64 s_pos = position % 60; |
| | 1414 | guint64 m_dur = duration / 60; |
| | 1415 | guint64 s_dur = duration % 60; |
| | 1416 | |
| | 1417 | static boost::format time_f ("%02d:%02d ⊠%02d:%02d"); |
| | 1418 | |
| | 1419 | m_TimeLabel->set_text((time_f % m_pos % s_pos % m_dur % s_dur).str()); |
| | 1420 | m_Seek->set_range(0., duration); |
| | 1421 | m_Seek->set_value(double (position)); |
| | 1422 | |
| | 1423 | #if 0 |
| | 1424 | if( m_popup ) |
| | 1425 | { |
| | 1426 | m_popup->set_position (position, duration); |
| | 1427 | } |
| | 1428 | #endif |
| | 1429 | } |
| | 1430 | } |