--- /dev/null
+Index: mythplugins/mythweb/themes/wml/header.php
+===================================================================
+--- mythplugins/mythweb/themes/wml/header.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/themes/wml/header.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -26,4 +26,4 @@
+ <p><a href="<?php echo root ?>tv/upcoming"><?php echo t('Upcoming Recordings') ?></a></p>
+ <p><a href="<?php echo root ?>tv/recorded"><?php echo t('Recorded Programs') ?></a></p>
+ <p><a href="<?php echo root ?>tv/search"><?php echo t('Search') ?></a></p>
+-<p><a href="<?php echo root ?>status?xml"><?php echo t('Backend Status') ?></a></p>
++<p><a href="<?php echo root ?>status/xml"><?php echo t('Backend Status') ?></a></p>
+Index: mythplugins/mythweb/themes/default/weather/weather.php
+===================================================================
+--- mythplugins/mythweb/themes/default/weather/weather.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/themes/default/weather/weather.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -93,13 +93,13 @@
+ $tomorrow = date("m/d/Y", mktime(0, 0, 0, date("m") , date("d")+1, date("Y")));
+
+ switch($forecast->dayofweek) {
++ case 0: $day = t('Sunday'); break;
+ case 1: $day = t('Monday'); break;
+ case 2: $day = t('Tuesday'); break;
+ case 3: $day = t('Wednesday'); break;
+ case 4: $day = t('Thursday'); break;
+ case 5: $day = t('Friday'); break;
+ case 6: $day = t('Saturday'); break;
+- case 7: $day = t('Sunday'); break;
+ default: $day = $forecast->date; break;
+ }
+
+Index: mythplugins/mythweb/themes/default/music/music.php
+===================================================================
+--- mythplugins/mythweb/themes/default/music/music.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/themes/default/music/music.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -164,10 +164,12 @@
+
+ function print_header($filterPlaylist,$filterArtist,$filterAlbum,$filterGenre) {
+ $this->filterPlaylist=$filterPlaylist;
+-// Set the desired page title
+- $page_title = 'MythWeb - '.t('Music');
+-// Print the page header
+- require_once theme_dir.'/header.php';
++ // Set the desired page title
++ global $page_title, $Modules, $headers;
++ $page_title = 'MythWeb - '.t('Music');
++ // Print the page header
++ require_once theme_dir.'/header.php';
++
+ printf("<form action=\"".root."music\" method=\"GET\" >\n");
+ printf("<input type=\"hidden\" name=\"mode\" value=\"music\" />\n");
+
+Index: mythplugins/mythweb/themes/default/tv/detail.php
+===================================================================
+--- mythplugins/mythweb/themes/default/tv/detail.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/themes/default/tv/detail.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -51,7 +51,7 @@
+ <?php } ?>
+ <div id="program_title">
+ <h1>
+- <a href="<?php echo root ?>tv/search/<?php echo urlencode($program->title) ?>&search_title=yes"><?php echo $schedule->title ?></a>
++ <a href="<?php echo root ?>tv/search/<?php echo str_replace('%2F', '/', rawurlencode($schedule->title)) ?>?search_title=1"><?php echo $schedule->title ?></a>
+ </h1>
+ <div id="program_time">
+ <?php
+Index: mythplugins/mythweb/includes/mythbackend.php
+===================================================================
+--- mythplugins/mythweb/includes/mythbackend.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/mythbackend.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -15,10 +15,6 @@
+ // The character string used by the backend to separate records
+ define('backend_sep', '[]:[]');
+
+-// A couple of global variables to keep duplicate queries to a minimum
+- $Scheduled_Recordings = array();
+- $Recorded_Programs = array();
+-
+ // MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
+ // and should be the current MythTV protocol version.
+ define('MYTH_PROTO_VERSION', 26);
+Index: mythplugins/mythweb/includes/programs.php
+===================================================================
+--- mythplugins/mythweb/includes/programs.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/programs.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -81,7 +81,9 @@
+ /**/
+ function &load_all_program_data($start_time, $end_time, $chanid = false, $single_program = false, $extra_query = '') {
+ global $Channels, $db;
+- // Make a local hash of channel chanid's with references to the actual channel data
++ // Make a local hash of channel chanid's with references to the actual
++ // channel data (Channels are not indexed by anything in particular, so
++ // that the user can sort by chanid or channum).
+ $channel_hash = array();
+ // An array (that later gets converted to a string) containing the id's of channels we want to load
+ $these_channels = array();
+@@ -104,7 +106,7 @@
+ load_all_channels();
+ // Scan through the channels array and actually assign those references
+ foreach (array_keys($Channels) as $key) {
+- $channel_hash[$Channels[$key]->chanid] = &$Channels[$key];
++ $channel_hash[$Channels[$key]->chanid] =& $Channels[$key];
+ // Reinitialize the programs array for this channel
+ $Channels[$key]->programs = array();
+ // Keep track of this channel id in case we're only grabbing info for certain channels - workound included to avoid blank chanid's
+@@ -130,11 +132,13 @@
+ LEFT JOIN programrating USING (chanid, starttime)
+ LEFT JOIN oldrecorded
+ ON oldrecorded.recstatus IN (-3, 11)
+- AND IF(oldrecorded.programid OR oldrecorded.seriesid,
++ AND IF(oldrecorded.programid AND oldrecorded.seriesid,
+ oldrecorded.programid = program.programid
+ AND oldrecorded.seriesid = program.seriesid,
+- oldrecorded.title = program.title
+- AND oldrecorded.subtitle = program.subtitle
++ oldrecorded.title AND oldrecorded.subtitle
++ AND oldrecorded.description
++ AND oldrecorded.title = program.title
++ AND oldrecorded.subtitle = program.subtitle
+ AND oldrecorded.description = program.description
+ )
+ LEFT JOIN channel ON program.chanid = channel.chanid
+@@ -156,8 +160,12 @@
+ // The extra query, if there is one
+ if ($extra_query)
+ $query .= ' AND '.$extra_query;
+- // Group, sort and query
++ // Group and sort
+ $query .= ' GROUP BY program.chanid, program.starttime ORDER BY program.starttime';
++ // Limit
++ if ($single_program)
++ $query .= ' LIMIT 1';
++ // Query
+ $sh = $db->query($query,
+ star_character, max_stars, max_stars);
+ // No results
+@@ -188,12 +196,8 @@
+ // Cleanup
+ $sh->finish();
+ // If channel-specific information was requested, return an array of those programs, or just the first/only one
+- if ($chanid) {
+- if ($single_program)
+- return $channel_hash[$chanid]->programs[0];
+- else
+- return $channel_hash[$chanid]->programs;
+- }
++ if ($chanid && $single_program)
++ return $these_programs[0];
+ // Just in case, return an array of all programs found
+ return $these_programs;
+ }
+@@ -272,18 +276,18 @@
+ $this->endtime = $data[12]; # show end-time
+ // Is this a previously-recorded program? Calculate the filesize
+ if (!empty($this->filename)) {
+- $this->filesize = ($fs_high + ($fs_low < 0)) * 4294967296 + $fs_low;
+- }
+- // Ah, a scheduled recording - let's load more information about it, to be parsed in below
+- elseif ($this->chanid) {
+- unset($this->filename);
+- // Kludge to avoid redefining the object, which doesn't work in php5
+- $tmp = @get_object_vars(load_one_program($this->starttime, $this->chanid));
+- if (is_array($tmp) && count($tmp) > 0) {
+- foreach ($tmp as $key => $value) {
+- $this->$key = $value;
+- }
++ if (function_exists('gmp_add')) {
++ // GMP functions should work better with 64 bit numbers.
++ $size = gmp_add($fs_low,
++ gmp_mul('4294967296',
++ gmp_add($fs_high, $fs_low < 0 ? '1' : '0'))
++ );
++ $this->filesize = gmp_strval($size);
+ }
++ else {
++ // This is inaccurate, but it's the best we can get without GMP.
++ $this->filesize = ($fs_high + ($fs_low < 0)) * 4294967296 + $fs_low;
++ }
+ }
+ // Load the remaining info we got from mythbackend
+ $this->title = $data[0]; # program name/title
+@@ -291,14 +295,14 @@
+ $this->description = $data[2]; # episode description
+ $this->category = $data[3];
+ #$chanid = $data[4]; # Extracted a few lines earlier
+- #$channum = $data[5];
+- #$callsign = $data[6];
++ $this->channum = $data[5];
++ $this->callsign = $data[6];
+ $this->channame = $data[7];
+ #$pathname = $data[8]; # Extracted a few lines earlier
+ #$fs_high = $data[9]; # Extracted a few lines earlier
+ #$fs_low = $data[10]; # Extracted a few lines earlier
+- #$starttime = $data[11]; # Extracted a few lines earlier
+- #$endtime = $data[12]; # Extracted a few lines earlier
++ #$this->starttime = $data[11]; # Extracted a few lines earlier
++ #$this->endtime = $data[12]; # Extracted a few lines earlier
+ $this->hostname = $data[16];
+ #$this->sourceid = $data[17];
+ $this->cardid = $data[18];
+@@ -320,9 +324,9 @@
+ $this->programid = $data[34];
+ $this->lastmodified = $data[35];
+ $this->recpriority = $data[36];
+- #$this->airdate = $data[37];
+- #$this->hasairdate = $data[38];
+- $this->timestretch = $program_data[39];
++ $this->airdate = date('Y-m-d', $data[37]);
++ $this->hasairdate = $data[38];
++ $this->timestretch = $data[39];
+ $this->recpriority2 = $data[40];
+ // Assign the program flags
+ $this->has_commflag = ($progflags & 0x01) ? true : false; // FL_COMMFLAG = 0x01
+@@ -363,8 +367,8 @@
+ $this->title_pronounce = $data['title_pronounce'];
+ $this->recstatus = $data['recstatus'];
+
+- if ($program_data['tsdefault']) {
+- $this->timestretch = $program_data['tsdefault'];
++ if ($data['tsdefault']) {
++ $this->timestretch = $data['tsdefault'];
+ } else {
+ $this->timestretch = 1.0;
+ }
+@@ -387,12 +391,14 @@
+ // Now we really should scan the $Channel array and add a link to this program's channel
+ foreach (array_keys($Channels) as $key) {
+ if ($Channels[$key]->chanid == $this->chanid) {
+- $this->channel = &$Channels[$key];
++ $this->channel =& $Channels[$key];
+ break;
+ }
+ }
++ // Not found
++ if (!$this->channel)
++ $this->channel =& load_one_channel($this->chanid);
+ }
+-
+ // Calculate the duration
+ if ($this->recendts)
+ $this->length = $this->recendts - $this->recstartts;
+Index: mythplugins/mythweb/includes/utils.php
+===================================================================
+--- mythplugins/mythweb/includes/utils.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/utils.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -276,7 +276,7 @@
+ static $first_run=true;
+ if($first_run) {
+ $first_run=false;
+- echo '<script type="text/javascript" src="/js/debug.js"></script>';
++ echo '<script type="text/javascript" src="'.root.'js/debug.js"></script>';
+ }
+ // Put our data into a string
+ if (is_array($data) || is_object($data))
+Index: mythplugins/mythweb/includes/init.php
+===================================================================
+--- mythplugins/mythweb/includes/init.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/init.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -16,28 +16,15 @@
+ *
+ /**/
+
+-/**
+- * $Path is an array of PATH_INFO passed into the script via mod_rewrite or some
+- * other lesser means. It contains most of the information required for
+- * figuring out what functions the user wants to access.
+- *
+- * @global array $GLOBALS['Path']
+- * @name $Path
+-/**/
+- global $Path;
+- $Path = explode('/', preg_replace('/^\/+/', '', // Remove leading slashes
+- preg_replace('/[\s]+/', ' ', // Convert extra whitespace
+- // Grab the path info from various different places.
+- array_key_exists('PATH_INFO', $_SERVER)
+- && $_SERVER['PATH_INFO']
+- ? $_SERVER['PATH_INFO']
+- : (array_key_exists('PATH_INFO', $_ENV)
+- && $_ENV['PATH_INFO']
+- ? $_ENV['PATH_INFO']
+- : $_GET['PATH_INFO']
+- )
+- ))
+- );
++// mod_redirect can do some weird things when php is run in cgi mode
++ $keys = preg_grep('/^REDIRECT_/', array_keys($_SERVER));
++ if (!empty($keys)) {
++ foreach ($keys as $key) {
++ $key = substr($key, 9);
++ if (!array_key_exists($key, $_SERVER))
++ $_SERVER[$key] = $_SERVER["REDIRECT_$key"];
++ }
++ }
+
+ // Clean the document root variable and make sure it doesn't have a trailing slash
+ $_SERVER['DOCUMENT_ROOT'] = preg_replace('/\/+$/', '', $_SERVER['DOCUMENT_ROOT']);
+@@ -94,6 +81,29 @@
+ exit;
+ }
+
++/**
++ * $Path is an array of PATH_INFO passed into the script via mod_rewrite or some
++ * other lesser means. It contains most of the information required for
++ * figuring out what functions the user wants to access.
++ *
++ * @global array $GLOBALS['Path']
++ * @name $Path
++/**/
++ global $Path;
++ $Path = explode('/', preg_replace('/^\/+/', '', // Remove leading slashes
++ preg_replace('/[\s]+/', ' ', // Convert extra whitespace
++ // Grab the path info from various different places.
++ array_key_exists('PATH_INFO', $_SERVER)
++ && $_SERVER['PATH_INFO']
++ ? $_SERVER['PATH_INFO']
++ : (array_key_exists('PATH_INFO', $_ENV)
++ && $_ENV['PATH_INFO']
++ ? $_ENV['PATH_INFO']
++ : $_GET['PATH_INFO']
++ )
++ ))
++ );
++
+ // Load the database connection routines
+ require_once 'includes/db.php';
+
+Index: mythplugins/mythweb/includes/mobile.php
+===================================================================
+--- mythplugins/mythweb/includes/mobile.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/mobile.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -74,58 +74,56 @@
+ * If you don't know the screensize of some mobile terminal then use
+ * an empty array or approximate dimensions.
+ */
+- $mobiles = array(/* Phones using the Series 60 platform, e.g. Nokia 3650 and 6600. */
+- 'Series 60' => array('width' => 176, 'height' => 208),
+- 'Series60' => array('width' => 176, 'height' => 208),
+- 'C500' => array('width'=>176, 'height'=> 220), // SPV C500
++ $mobiles = array(
++ /* Phones using the Series 60 platform, e.g. Nokia 3650 and 6600. */
++ 'Series 60' => array('width' => 176, 'height' => 208),
++ 'Series60' => array('width' => 176, 'height' => 208),
++ 'C500' => array('width'=>176, 'height'=> 220), // SPV C500
++ /* Phones using the Series 90 platform, e.g. Nokia 7710. */
++ 'Series 90' => array('width' => 640, 'height' => 320),
++ 'Series90' => array('width' => 640, 'height' => 320),
++ /* The following strings are added for the Palm browser WebPro
++ * WebPro sometimes supplies the screen dimensions, but sometimes not
++ * but we try to detect the best as possible */
++ '240x320' => array('width' => 240, 'height' => 320), // PocketPC IE
++ '320x320' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models
++ '320x480' => array('width' => 320, 'height' => 480), // For Palm Tungsten T
++ '480x320' => array('width' => 480, 'height' => 320), // For Palm Tungsten T
++ '320x480x16' => array('width' => 320, 'height' => 480), // For Palm Tungsten T
++ '480x320x16' => array('width' => 480, 'height' => 320), // For Palm Tungsten T
++ '320x320x16' => array('width' => 320, 'height' => 320),
++ 'WebPro' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models
++ /* A generic mobile phone using Symbian OS. All Symbian phones don't
++ * necessarily have the same screen size so if you want to include
++ * some specific Symbian phones then place them above this line. */
++ 'Symbian' => array('width' => 176, 'height' => 208),
+
+- /* Phones using the Series 90 platform, e.g. Nokia 7710. */
+- 'Series 90' => array('width' => 640, 'height' => 320),
+- 'Series90' => array('width' => 640, 'height' => 320),
++ 'Nokia' => array(), // Nokia phones and emulators
++ 'Eric' => array(), // Ericsson WAP phones and emulators
++ 'WapI' => array(), // Ericsson WapIDE 2.0
++ 'MC21' => array(), // Ericsson MC218
++ 'AUR ' => array(), // Ericsson R320
++ 'R380' => array(), // Ericsson R380
++ 'UP.B' => array(), // UP.Browser
++ 'WinW' => array(), // WinWAP browser
++ 'UPG1' => array(), // UP.SDK 4.0
++ 'upsi' => array(), // another kind of UP.Browser ??
++ 'QWAP' => array(), // unknown QWAPPER browser
++ 'Jigs' => array(), // unknown JigSaw browser
++ 'Java' => array(), // unknown Java based browser
++ 'Alca' => array(), // unknown Alcatel-BE3 browser (UP based?)
++ 'MITS' => array(), // unknown Mitsubishi browser
++ 'MOT-' => array(), // unknown browser (UP based?)
++ 'My S' => array(), // unknown Ericsson devkit browser ?
++ 'WAPJ' => array(), // Virtual WAPJAG www.wapjag.de
++ 'fetc' => array(), // fetchpage.cgi Perl script from www.wapcab.de
++ 'ALAV' => array(), // yet another unknown UP based browser ?
++ 'Wapa' => array(), // another unknown browser (Web based "Wapalyzer"?)
++ 'LGE-' => array(), // LG phones
+
+- /* The following strings are added for the Palm browser WebPro
+- * WebPro sometimes supplies the screen dimensions, but sometimes not
+- * but we try to detect the best as possible
+- */
+- '320x480' => array('width' => 320, 'height' => 480), // For Palm Tungsten T
+- '480x320' => array('width' => 480, 'height' => 320), // For Palm Tungsten T
+- '320x320' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models
+- '320x480x16' => array('width' => 320, 'height' => 480), // For Palm Tungsten T
+- '480x320x16' => array('width' => 480, 'height' => 320), // For Palm Tungsten T
+- '320x320x16' => array('width' => 320, 'height' => 320),
+- 'WebPro' => array('width' => 320, 'height' => 320), // For all Palm Tungsten models
+-
+- /* A generic mobile phone using Symbian OS. All Symbian phones don't
+- * necessarily have the same screen size so if you want to include
+- * some specific Symbian phones then place them above this line. */
+- 'Symbian' => array('width' => 176, 'height' => 208),
+-
+- 'Nokia' => array(), // Nokia phones and emulators
+- 'Eric' => array(), // Ericsson WAP phones and emulators
+- 'WapI' => array(), // Ericsson WapIDE 2.0
+- 'MC21' => array(), // Ericsson MC218
+- 'AUR ' => array(), // Ericsson R320
+- 'R380' => array(), // Ericsson R380
+- 'UP.B' => array(), // UP.Browser
+- 'WinW' => array(), // WinWAP browser
+- 'UPG1' => array(), // UP.SDK 4.0
+- 'upsi' => array(), // another kind of UP.Browser ??
+- 'QWAP' => array(), // unknown QWAPPER browser
+- 'Jigs' => array(), // unknown JigSaw browser
+- 'Java' => array(), // unknown Java based browser
+- 'Alca' => array(), // unknown Alcatel-BE3 browser (UP based?)
+- 'MITS' => array(), // unknown Mitsubishi browser
+- 'MOT-' => array(), // unknown browser (UP based?)
+- 'My S' => array(), // unknown Ericsson devkit browser ?
+- 'WAPJ' => array(), // Virtual WAPJAG www.wapjag.de
+- 'fetc' => array(), // fetchpage.cgi Perl script from www.wapcab.de
+- 'ALAV' => array(), // yet another unknown UP based browser ?
+- 'Wapa' => array(), // another unknown browser (Web based "Wapalyzer"?)
+- 'LGE-' => array(), // LG phones
+-
+- /* For debugging: you can try out the mobile mode without a mobile phone.
+- * Replace 'Opera' with your browser. Comment out for release version. */
+- //'Opera' => array('width' => 176, 'height' => 208)
++ /* For debugging: you can try out the mobile mode without a mobile phone.
++ * Replace 'Opera' with your browser. Comment out for release version. */
++ //'Opera' => array('width' => 176, 'height' => 208)
+ );
+
+ /* Scan through $mobiles and try to find matching user agent. */
+Index: mythplugins/mythweb/includes/recording_schedules.php
+===================================================================
+--- mythplugins/mythweb/includes/recording_schedules.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/recording_schedules.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -68,10 +68,14 @@
+ // Cleanup
+ mysql_free_result($result);
+
++// Initialize
++ global $Scheduled_Recordings, $Num_Conflicts, $Num_Scheduled;
++ $Scheduled_Recordings = array();
++ $Num_Conflicts = 0;
++ $Num_Scheduled = 0;
++
+ // Load all of the scheduled recordings. We will need them at some point, so we
+ // might as well get it overwith here.
+- global $Scheduled_Recordings, $Num_Conflicts, $Num_Scheduled;
+- $Scheduled_Recordings = array();
+ foreach (get_backend_rows('QUERY_GETALLPENDING', 2) as $key => $program) {
+ // The offset entry
+ if ($key === 'offset') {
+Index: mythplugins/mythweb/includes/session.php
+===================================================================
+--- mythplugins/mythweb/includes/session.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/includes/session.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -19,8 +19,8 @@
+
+ // Start the session
+ session_name('mythweb_id');
+- session_set_cookie_params(60 * 60 * 30, '/'); // 30 day timeout on cookies
+- ini_set('session.gc_maxlifetime', 60 * 60 * 30); // ... and sessions
++ session_set_cookie_params(60 * 60 * 24 * 365, '/'); // 1 year timeout on cookies
++ ini_set('session.gc_maxlifetime', 60 * 60 * 24 * 30); // 30 day timeout on sessions
+ session_set_save_handler('sess_do_nothing', 'sess_do_nothing', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
+ session_start();
+
+Index: mythplugins/mythweb/modules/weather/handler.php
+===================================================================
+--- mythplugins/mythweb/modules/weather/handler.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/modules/weather/handler.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -222,8 +222,10 @@
+
+ $data = explode("|", $data);
+ for($i = 0;$i<5;$i++) {
+- $forecast = new Forecast($data[5 + $i],$data[$i]);
+- $forecast->dayofweek = $data[$i];
++ # mktime uses 0-6; msnbc gives us 1-7; adjust msnbc to match mktime
++ $dayofweek = $data[$i] - 1;
++ $forecast = new Forecast($data[5 + $i],$dayofweek);
++ $forecast->dayofweek = $dayofweek;
+ list($forecast->DescImage,$forecast->DescText) = getImageAndDescFromId($data[15 + $i]);
+ $forecast->DescImage = (strlen($forecast->DescImage) > 0) ? $forecast->DescImage : "unknown.png";
+ $forecast->DescText = (strlen($forecast->DescText) > 0) ? $forecast->DescText : t('Unknown') . " (" . $data[15+$i] . ")";
+Index: mythplugins/mythweb/modules/status/handler.php
+===================================================================
+--- mythplugins/mythweb/modules/status/handler.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/modules/status/handler.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -18,14 +18,17 @@
+ $masterhost = get_backend_setting('MasterServerIP');
+ $statusport = get_backend_setting('BackendStatusPort');
+
++// XML mode?
++ $xml_param = ($Path[1] == 'xml') ? '/xml' : '';
++
+ // Make sure the content is interpreted as UTF-8
+ header('Content-Type: text/html; charset=UTF-8');
+
+ // Load the status page
+ if (function_exists('file_get_contents'))
+- $status = file_get_contents("http://$masterhost:$statusport");
++ $status = file_get_contents("http://$masterhost:$statusport$xml_param");
+ else
+- $status = implode("\n", file("http://$masterhost:$statusport"));
++ $status = implode("\n", file("http://$masterhost:$statusport$xml_param"));
+
+ // Extract the page title
+ preg_match('#<title>(.+?)</title>#s', $status, $title);
+Index: mythplugins/mythweb/modules/backend_log/handler.php
+===================================================================
+--- mythplugins/mythweb/modules/backend_log/handler.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/modules/backend_log/handler.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -16,7 +16,7 @@
+ // Where to start searching from
+ $_GET['start'] = intVal($_GET['start']);
+ if ($_GET['start'] < 1)
+- $_GET['start'] = 1;
++ $_GET['start'] = 0;
+
+ // How many entries to show?
+ $_GET['show'] = intVal($_GET['show']);
+Index: mythplugins/mythweb/modules/tv/upcoming.php
+===================================================================
+--- mythplugins/mythweb/modules/tv/upcoming.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/modules/tv/upcoming.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -103,8 +103,9 @@
+ continue;
+ }
+ // Skip deactivated shows?
+- elseif (!$_SESSION['scheduled_recordings']['disp_deactivated']) {
+- continue;
++ elseif ($show->recstatus != 'Recording') {
++ if (!$_SESSION['scheduled_recordings']['disp_deactivated'])
++ continue;
+ }
+ // Assign a reference to this show to the various arrays
+ $all_shows[] =& $Scheduled_Recordings[$channum][$starttime][$key];
+Index: mythplugins/mythweb/modules/tv/recorded.php
+===================================================================
+--- mythplugins/mythweb/modules/tv/recorded.php (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/modules/tv/recorded.php (.../branches/release-0-19-fixes) (revision 10051)
+@@ -128,9 +128,21 @@
+ continue;
+ // Get the length (27 == recendts; 26 == recstartts)
+ $length = $record[27] - $record[26];
+- // Keep track of the total time and disk space used
++ // Keep track of the total time and disk space used (9 == fs_high; 10 == fs_low)
+ $Total_Time += $length;
+- $Total_Used += ($record[9] + ($record[10] < 0)) * 4294967296 + $record[10]; // 9 == fs_high; 10 == fs_low;
++ if (function_exists('gmp_add')) {
++ // GMP functions should work better with 64 bit numbers.
++ $size = gmp_add($record[10],
++ gmp_mul('4294967296',
++ gmp_add($record[9], $record[10] < 0 ? '1' : '0')
++ )
++ );
++ $Total_Used = gmp_strval(gmp_add($Total_Used, $size));
++ }
++ else {
++ // This is inaccurate, but it's the best we can get without GMP.
++ $Total_Used += ($record[9] + ($record[10] < 0)) * 4294967296 + $record[10];
++ }
+ // keep track of their names and how many episodes we have recorded
+ $Total_Programs++;
+ $Groups[$record[30]]++;
+@@ -223,8 +235,28 @@
+
+ // How much free disk space on the backend machine?
+ list($size_high, $size_low, $used_high, $used_low) = explode(backend_sep, backend_command('QUERY_FREE_SPACE'));
+- define(disk_size, (($size_high + ($size_low < 0)) * 4294967296 + $size_low) * 1024);
+- define(disk_used, (($used_high + ($used_low < 0)) * 4294967296 + $used_low) * 1024);
++ if (function_exists('gmp_add')) {
++ // GMP functions should work better with 64 bit numbers.
++ $size = gmp_mul('1024',
++ gmp_add($size_low,
++ gmp_mul('4294967296',
++ gmp_add($size_high, $size_low < 0 ? '1' : '0'))
++ )
++ );
++ define(disk_size, gmp_strval($size));
++ $size = gmp_mul('1024',
++ gmp_add($used_low,
++ gmp_mul('4294967296',
++ gmp_add($used_high, $used_low < 0 ? '1' : '0'))
++ )
++ );
++ define(disk_used, gmp_strval($size));
++ }
++ else {
++ // This is inaccurate, but it's the best we can get without GMP.
++ define(disk_size, (($size_high + ($size_low < 0)) * 4294967296 + $size_low) * 1024);
++ define(disk_used, (($used_high + ($used_low < 0)) * 4294967296 + $used_low) * 1024);
++ }
+
+ // Load the class for this page
+ require_once theme_dir.'tv/recorded.php';
+Index: mythplugins/mythweb/.htaccess
+===================================================================
+--- mythplugins/mythweb/.htaccess (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/.htaccess (.../branches/release-0-19-fixes) (revision 10051)
+@@ -22,6 +22,7 @@
+ # AuthName "MythTV"
+ # AuthDigestFile /var/www/htdigest
+ # Require valid-user
++# BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
+
+ # MythTV now uses the correct file suffix for mpeg files, so all .nuv files
+ # should actually be NuppleVideo. However, apache probably doesn't know what
+@@ -66,8 +67,6 @@
+
+ php_value memory_limit 32M
+
+- php_value session.save_path php_sessions
+-
+ php_value output_buffering 4096
+ php_value register_globals 0
+ php_value magic_quotes_gpc 0
+Index: mythplugins/mythweb/js/debug.js
+===================================================================
+--- mythplugins/mythweb/js/debug.js (.../tags/release-0-19) (revision 0)
++++ mythplugins/mythweb/js/debug.js (.../branches/release-0-19-fixes) (revision 10051)
+@@ -0,0 +1,24 @@
++/**
++ * A random assortment of javascript debug routines
++ *
++ * @url $URL$
++ * @date $Date$
++ * @version $Revision$
++ * @author $Author$
++ * @copyright Silicon Mechanics
++ * @license LGPL
++ *
++ * @package SiMech
++ * @subpackage Javascript
++ *
++/**/
++
++ var debug_window_handle;
++// Create a debug window and debug into it
++ function debug_window(string) {
++ if (!debug_window_handle || debug_window_handle.closed) {
++ debug_window_handle = window.open('', 'Debug Window','scrollbars, resizable, width=400, height=600');
++ debug_window_handle.document.write('<html><body style="font-size: 9pt; background-color: #f88;">');
++ }
++ debug_window_handle.document.write('<pre>'+string+'</pre><hr>');
++ }
+
+Property changes on: mythplugins/mythweb/js/debug.js
+___________________________________________________________________
+Name: svn:eol-style
+ + native
+Name: svn:mime-type
+ + text/x-javascript
+Name: svn:keywords
+ + Date Revision Author HeadURL
+
+Index: mythplugins/mythweb/js/browser.js
+===================================================================
+--- mythplugins/mythweb/js/browser.js (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/js/browser.js (.../branches/release-0-19-fixes) (revision 10051)
+@@ -215,14 +215,18 @@
+ browser.is_css = (document.body && document.body.style)
+ browser.is_w3c = (browser.is_css && browser.getElementById)
+
+-// Cookie support
+- var tmp = document.cookie;
+- document.cookie = 'cookies=true';
+- browser.cookies = (document.cookie) ? true : false;
+- document.cookie = tmp;
++// Cookie support -- only create a cookie if there isn't one already. It seems
++// that doing this can override the exipiration info in existing cookies.
++ browser.cookies = (document.cookie) ? true : false;
++ if (!browser.cookies) {
++ var tmp = document.cookie;
++ document.cookie = 'cookie_test=true';
++ browser.cookies = (document.cookie) ? true : false;
++ document.cookie = tmp;
++ }
+
+ // Java support
+- browser.java = navigator.javaEnabled();
++ browser.java = navigator.javaEnabled();
+
+ /****************************** Plugin Support ******************************/
+
+Index: mythplugins/mythweb/README
+===================================================================
+--- mythplugins/mythweb/README (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweb/README (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1,18 +1,12 @@
+ This is the README file for the MythWeb package.
+-January 17, 2006
++March 6, 2006
+
+-Version: .19 pre
+-(c) 2002-2006 Thor Sigvaldason <mythtv(a)lamedomainname(o)com>
++Version: .19
++(c) 2002-2006 Chris Petersen <mythweb(a)forevermore(o)net>
+ Isaac Richards <ijr(a)po(o)cwru(o)edu>
+- Chris Petersen <mythweb(a)forevermore(o)net>
++ Thor Sigvaldason <mythtv(a)lamedomainname(o)com>
++ and others... (see mythtv.org commit logs for details)
+
+-with contributions from many people including:
+-
+-Michael Kedl <kedlm(a)knology(o)net>
+-Jonathan Kolb <jkolb(a)greyshift(o)net
+-Ed Wildgoose <edward(o)wildgoose(a)frmhedge(o)com>
+-Kenneth Aafloy <ke-aa(a)frisurf(o)no>
+-
+ MythWeb is distributed under the GNU GENERAL PUBLIC LICENSE version 2, and where
+ noted with the @license tag, the LESSER GENERAL PUBLIC LICENSE version 2.
+ Please see http://www.gnu.org for details and the specific text of the license.
+@@ -63,10 +57,22 @@
+
+ In order for the included .htaccess to work properly, you will need to
+ set apache's "AllowOverride" setting to "All" (or at least "Options") for
+-the root mythweb directory. This directive lives within <Directory/> tags,
+-so make sure you're changing the setting for the correct directory. You will
+-also need to make sure that the following apache modules are enabled:
++the root mythweb directory. This directive lives within <Directory> tags,
++so make sure you're changing the setting for the correct directory. Please
++keep in mind that most distros correctly disable everything for <Directory />,
++and then later override those with something like <Directory /var/www/html>.
++The simplest way to do this is to put a file into /etc/httpd/conf.d (or
++whatever your distro calls it) containing something like:
+
++ <Directory "/var/www/html/mythweb" >
++ Options FollowSymLinks
++ AllowOverride All
++ </Directory>
++
++Just make sure that the path points to your MythWeb installation, since that
++will likely differ from system to system. You will also need to make sure that
++the following apache modules are enabled:
++
+ mod_env
+ mod_rewrite
+
+Index: mythplugins/mythdvd/mtd/jobthread.cpp
+===================================================================
+--- mythplugins/mythdvd/mtd/jobthread.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythdvd/mtd/jobthread.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -11,6 +11,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
++#include <unistd.h>
+
+ #include <iostream>
+ using namespace std;
+Index: mythplugins/mythdvd/mtd/mtd.cpp
+===================================================================
+--- mythplugins/mythdvd/mtd/mtd.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythdvd/mtd/mtd.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -8,6 +8,7 @@
+
+ */
+
++#include <unistd.h>
+ #include <qstringlist.h>
+ #include <qregexp.h>
+ #include <qdir.h>
+Index: mythplugins/mythdvd/mtd/logging.cpp
+===================================================================
+--- mythplugins/mythdvd/mtd/logging.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythdvd/mtd/logging.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -9,6 +9,7 @@
+ */
+ #include "logging.h"
+
++#include <unistd.h>
+ #include <qdatetime.h>
+
+ #include <mythtv/mythcontext.h>
+Index: mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp
+===================================================================
+--- mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -12,6 +12,7 @@
+ #include "metadata.h"
+ #include "metaiooggvorbiscomment.h"
+
++#include <mythtv/mythconfig.h>
+ #include <mythtv/mythcontext.h>
+
+ // static functions for OggVorbis
+@@ -240,8 +241,13 @@
+ seekTime = -1.0;
+ }
+
++#ifdef WORDS_BIGENDIAN
++ len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 1, 2, 1,
++ §ion);
++#else
+ len = ov_read(&oggfile, (char *) (output_buf + output_at), bks, 0, 2, 1,
+ §ion);
++#endif
+
+ if (len > 0) {
+ bitrate = ov_bitrate_instant(&oggfile) / 1000;
+Index: mythplugins/mythmusic/mythmusic/flacdecoder.cpp
+===================================================================
+--- mythplugins/mythmusic/mythmusic/flacdecoder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythmusic/mythmusic/flacdecoder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -12,6 +12,7 @@
+ #include "metadata.h"
+ #include "metaioflacvorbiscomment.h"
+
++#include <mythtv/mythconfig.h>
+ #include <mythtv/mythcontext.h>
+
+ #include <qtimer.h>
+@@ -102,7 +103,11 @@
+ for (channel = 0; channel < chan; channel++)
+ {
+ sample = (FLAC__int8)buffer[channel][cursamp];
++#ifdef WORDS_BIGENDIAN
++ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
++#else
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
++#endif
+ output_bytes += 1;
+ }
+ }
+@@ -114,8 +119,13 @@
+ for (channel = 0; channel < chan; channel++)
+ {
+ sample = (FLAC__int16)buffer[channel][cursamp];
++#ifdef WORDS_BIGENDIAN
++ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
++#else
++ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
++#endif
+ output_bytes += 2;
+ }
+ }
+Index: mythplugins/mythmusic/mythmusic/maddecoder.cpp
+===================================================================
+--- mythplugins/mythmusic/mythmusic/maddecoder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythmusic/mythmusic/maddecoder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -16,6 +16,7 @@
+ #include <mythtv/audiooutput.h>
+ #include "metaioid3v2.h"
+
++#include <mythtv/mythconfig.h>
+ #include <mythtv/mythcontext.h>
+
+ #define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
+@@ -407,7 +408,7 @@
+ flush(TRUE);
+
+ if (output()) {
+- output()->Drain();
++ output()->Drain();
+ }
+
+ done = TRUE;
+@@ -488,15 +489,25 @@
+ flush();
+ }
+ sample = fix_sample(16, *left++);
++#ifdef WORDS_BIGENDIAN
++ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
++#else
++ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
++#endif
+ output_bytes += 2;
+
+ if (channels == 2)
+ {
+ sample = fix_sample(16, *right++);
++#ifdef WORDS_BIGENDIAN
++ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
++#else
++ *(output_buf + output_at++) = ((sample >> 0) & 0xff);
+ *(output_buf + output_at++) = ((sample >> 8) & 0xff);
++#endif
+ output_bytes += 2;
+ }
+ }
+Index: mythplugins/mythweather/mythweather/weather.cpp
+===================================================================
+--- mythplugins/mythweather/mythweather/weather.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythweather/mythweather/weather.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -2571,6 +2571,14 @@
+ return false;
+ }
+
++ int imageCount = 5;
++ QString imagesList = parseData(tempData, "imagenames = new Array( '", ";");
++ if (imagesList != "<NULL>")
++ {
++ QStringList imageURLs = QStringList::split(",", imagesList);
++ imageCount = imageURLs.size();
++ }
++
+ QString fileprefix = MythContext::GetConfDir();
+
+ QDir dir(fileprefix);
+@@ -2587,13 +2595,13 @@
+ cerr << "MythWeather: Map File Prefix: " << fileprefix << endl;
+
+ // delete existing radar maps
+- for (int x = 1; x <= 6; x++)
++ for (int x = 1; x <= 10; x++)
+ QFile::remove(QString(fileprefix + "/radar%1.jpg").arg(x));
+
+ if (debug)
+ cerr << "MythWeather: Copying Map Files from Server (" << imageLoc << ")...\n";
+
+- for (int x = 1; x <= 6; x++)
++ for (int x = 1; x <= imageCount; x++)
+ {
+ QString sFile = QString(fileprefix + "/radar%1.jpg").arg(x);
+ sURL = QString("http://image.weather.com" + imageLoc + "%1L.jpg").arg(x);
+Index: mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp
+===================================================================
+--- mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythcontrols/mythcontrols/mythcontrols.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -46,22 +46,6 @@
+ #include "keygrabber.h"
+
+
+-static QMap<int,QString> FindContexts(const QString &context)
+-{
+- QMap<int,QString> retval;
+- retval.clear();
+- if (context != JUMP_CONTEXT) retval[-1] = JUMP_CONTEXT;
+- retval[0] = context;
+- if (context != JUMP_CONTEXT && context != GLOBAL_CONTEXT)
+- {
+- if (context == "TV Editting")
+- retval[1] = "TV Playback";
+- retval[2] = GLOBAL_CONTEXT;
+- if (context != "qt")
+- retval[3] = "qt";
+- }
+- return retval;
+-}
+
+ static const QString KeyToDisplay(const QString key)
+ {
+@@ -838,7 +822,11 @@
+ refreshKeyInformation();
+ }
+
+-void MythControls::addBindings(QDict<binding_t> &bindings, const QString &context, const QString &contextParent, int bindlevel)
++
++
++void MythControls::addBindings(QDict<binding_t> &bindings,
++ const QString &context,
++ const QString &contextParent, int bindlevel)
+ {
+ QStringList *actions = key_bindings->getActions(context);
+
+@@ -872,18 +860,13 @@
+
+ BindingList *MythControls::getKeyBindings(const QString &context)
+ {
++ QStringList keys;
+ QDict<binding_t> bindings;
+ bindings.clear();
+
+- QMap<int,QString> contextList = FindContexts(context);
+- for (QMap<int,QString>::iterator it = contextList.begin(); it != contextList.end(); ++it)
+- {
+- int level = it.key();
+- QString curcontext = it.data();
+- addBindings(bindings, curcontext, context, level);
+- }
++ for (size_t i = 0; i < contexts.size(); i++)
++ addBindings(bindings, contexts[i], context, i);
+
+- QStringList keys;
+
+ for (QDictIterator<binding_t> it(bindings); it.current(); ++it)
+ {
+Index: mythplugins/mythcontrols/mythcontrols/actionset.cpp
+===================================================================
+--- mythplugins/mythcontrols/mythcontrols/actionset.cpp (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythcontrols/mythcontrols/actionset.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -139,13 +139,19 @@
+ /* method description in header */
+ QStringList * ActionSet::actionStrings(const QString &context_name) const
+ {
+- QStringList *action_strings = new QStringList();
+- QDictIterator<Action> it(*(_contexts[context_name]));
++ Context *c = _contexts[context_name];
+
+- for (; it.current(); ++it)
+- action_strings->append(it.currentKey());
++ if (c == NULL) return NULL;
++ else
++ {
++ QStringList *action_strings = new QStringList();
++ QDictIterator<Action> it(*(_contexts[context_name]));
++
++ for (; it.current(); ++it)
++ action_strings->append(it.currentKey());
+
+- return action_strings;
++ return action_strings;
++ }
+ }
+
+
+Index: mythplugins/mythcontrols/mythcontrols/keybindings.h
+===================================================================
+--- mythplugins/mythcontrols/mythcontrols/keybindings.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythcontrols/mythcontrols/keybindings.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -65,6 +65,8 @@
+ /**
+ * @brief Get a list of the context names.
+ * @return A list of the context names.
++ * @note The returned list is a copy and can be modified without
++ * side-effects.
+ */
+ inline QStringList * getContexts() const
+ {
+Index: mythplugins/mythvideo/mythvideo/videomanager.h
+===================================================================
+--- mythplugins/mythvideo/mythvideo/videomanager.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythvideo/mythvideo/videomanager.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -30,7 +30,7 @@
+ public:
+ VideoManager(MythMainWindow *parent, const char *name = 0);
+ ~VideoManager(void);
+- void VideoManager::processEvents() { qApp->processEvents(); }
++ void processEvents() { qApp->processEvents(); }
+
+ public slots:
+ void slotManualIMDB();
+Index: mythplugins/mythvideo/mythvideo/videoselected.h
+===================================================================
+--- mythplugins/mythvideo/mythvideo/videoselected.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythvideo/mythvideo/videoselected.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -35,7 +35,7 @@
+ VideoSelected(VideoList *lvideolist,
+ MythMainWindow *parent, const char *name = 0, int index = 0);
+ ~VideoSelected();
+- void VideoSelected::processEvents() { qApp->processEvents(); }
++ void processEvents() { qApp->processEvents(); }
+
+
+ protected slots:
+Index: mythplugins/mythphone/mythphone/sipfsm.h
+===================================================================
+--- mythplugins/mythphone/mythphone/sipfsm.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythphone/mythphone/sipfsm.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -618,7 +618,7 @@
+ SipWatcher *CreateWatcherFsm(QString Url);
+ SipIM *CreateIMFsm(QString Url="", QString callIdStr="");
+ void StopWatchers();
+- void SipFsm::KickWatcher(SipUrl *Url);
++ void KickWatcher(SipUrl *Url);
+ void SendIM(QString destUrl, QString CallId, QString imMsg);
+ int numCalls();
+ int getPrimaryCall() { return primaryCall; };
+Index: mythplugins/mythphone/mythphone/vxml.h
+===================================================================
+--- mythplugins/mythphone/mythphone/vxml.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythphone/mythphone/vxml.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -10,7 +10,7 @@
+ {
+ public:
+ vxmlVariable(QString N, QString V);
+- vxmlVariable::vxmlVariable(QString N, short *wav, int S);
++ vxmlVariable(QString N, short *wav, int S);
+ virtual ~vxmlVariable() {};
+ bool isType(QString t) { return (t == Type); };
+ QString getName() { return Name; };
+Index: mythplugins/mythgame/mythgame/gamehandler.h
+===================================================================
+--- mythplugins/mythgame/mythgame/gamehandler.h (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythgame/mythgame/gamehandler.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -106,7 +106,7 @@
+
+ protected:
+ static GameHandler* GetHandler(RomInfo *rominfo);
+- static GameHandler* GameHandler::GetHandlerByName(QString systemname);
++ static GameHandler* GetHandlerByName(QString systemname);
+
+ bool rebuild;
+ int spandisks;
+Index: mythplugins/mythnews/mythnews/news-sites.xml
+===================================================================
+--- mythplugins/mythnews/mythnews/news-sites.xml (.../tags/release-0-19) (revision 10051)
++++ mythplugins/mythnews/mythnews/news-sites.xml (.../branches/release-0-19-fixes) (revision 10051)
+@@ -119,7 +119,7 @@
+
+ <item>
+ <title>Slashdot</title>
+- <url>http://slashdot.org/slashdot.rss</url>
++ <url>http://rss.slashdot.org/Slashdot/slashdot</url>
+ <ico>http://slashdot.org/favicon.ico</ico>
+ </item>
+
+Index: mythtv/libs/libmythtv/NuppelVideoPlayer.h
+===================================================================
+--- mythtv/libs/libmythtv/NuppelVideoPlayer.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/NuppelVideoPlayer.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -150,7 +150,8 @@
+ // Complicated gets
+ long long CalcMaxFFTime(long long ff, bool setjump = true) const;
+ long long CalcRWTime(long long rw) const;
+- void calcSliderPos(struct StatusPosInfo &posInfo);
++ void calcSliderPos(struct StatusPosInfo &posInfo,
++ bool paddedFields = false);
+
+ /// Non-const gets
+ OSD *GetOSD(void) { return osd; }
+@@ -543,6 +544,7 @@
+ QMap<long long, int>::Iterator deleteIter;
+ QMap<long long, int>::Iterator blankIter;
+ QMap<long long, int>::Iterator commBreakIter;
++ bool forcePositionMapSync;
+
+ // Playback (output) speed control
+ /// Lock for next_play_speed and next_normal_speed
+Index: mythtv/libs/libmythtv/osdlistbtntype.h
+===================================================================
+--- mythtv/libs/libmythtv/osdlistbtntype.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/osdlistbtntype.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1,3 +1,4 @@
++// -*- Mode: c++ -*-
+ /* ============================================================
+ * File : uilistbtntype.h
+ * Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
+@@ -22,38 +23,57 @@
+ #ifndef OSDLISTBTNTYPE_H
+ #define OSDLISTBTNTYPE_H
+
+-#include "osdtypes.h"
+-#include "ttfont.h"
++#include <vector>
++using namespace std;
++
++// Qt headers
+ #include <qcolor.h>
+ #include <qptrlist.h>
+ #include <qevent.h>
+ #include <qmutex.h>
++#include <qptrvector.h>
++
++// MythTV headers
++#include "osdtypes.h"
++#include "ttfont.h"
+ #include "generictree.h"
+
++class OSDListBtnType;
+ class OSDListBtnTypeItem;
+-class OSDListBtnType;
++typedef vector<OSDListBtnType*> OSDListBtnList;
++typedef vector<OSDListBtnTypeItem*> OSDListBtnItemList;
+
+ class OSDGenericTree : public GenericTree
+ {
+ public:
+ // This class will _not_ delete the image it's given, if any.
+- OSDGenericTree(OSDGenericTree *parent, const QString &name,
+- const QString &action = "", int check = -1,
+- OSDTypeImage *image = NULL, QString group = "");
++ OSDGenericTree(OSDGenericTree *parent, const QString &name,
++ const QString &action = "", int check = -1,
++ OSDTypeImage *image = NULL, QString group = "") :
++ GenericTree(name), m_image(image), m_action(action),
++ m_group(group), m_checkable(check), m_parentButton(NULL)
++ {
++ m_group = (m_group.isEmpty()) ? action : m_group;
++ setSelectable(!action.isEmpty());
++ if (parent)
++ parent->addNode(this);
++ }
+
+- OSDTypeImage *getImage(void) { return m_image; }
+- QString getAction(void) { return m_action; }
+- int getCheckable(void) { return m_checkable; }
+- QString getGroup(void) { return m_group; }
++ QString getAction(void) const { return m_action; }
++ QString getGroup(void) const { return m_group; }
++ int getCheckable(void) const { return m_checkable; }
++
++ OSDTypeImage *getImage(void) { return m_image; }
++ OSDListBtnTypeItem *getParentButton(void) { return m_parentButton; }
++
+ void setParentButton(OSDListBtnTypeItem *button)
+- { m_parentButton = button; };
+- OSDListBtnTypeItem *getParentButton(void) { return m_parentButton; };
++ { m_parentButton = button; }
+
+ private:
+- OSDTypeImage *m_image;
+- QString m_action;
+- int m_checkable;
+- QString m_group;
++ OSDTypeImage *m_image;
++ QString m_action;
++ QString m_group;
++ int m_checkable;
+ OSDListBtnTypeItem *m_parentButton;
+ };
+
+@@ -62,53 +82,49 @@
+ {
+ Q_OBJECT
+ public:
+- OSDListTreeType(const QString &name, const QRect &area,
+- const QRect &levelsize, int levelspacing,
+- float wmult, float hmult);
++ OSDListTreeType(const QString &name, const QRect &area,
++ const QRect &levelsize, int levelspacing,
++ float wmult, float hmult);
++ ~OSDListTreeType();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ bool IsVisible(void) const { return m_visible; }
++
++ void SetFontActive(TTFFont *font) { m_active = font; }
++ void SetFontInactive(TTFFont *font) { m_inactive = font; }
++
+ void SetGroupCheckState(QString group, int newState = 0);
++ void SetSpacing(uint spacing)
++ { m_unbiasedspacing = (m_spacing = spacing) / m_wmult; }
++ void SetMargin(uint margin)
++ { m_unbiasedmargin = (m_margin = margin) / m_wmult; }
++ void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha)
++ { m_itemRegBeg = beg; m_itemRegEnd = end; m_itemRegAlpha = alpha; }
++ void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha)
++ { m_itemSelBeg = beg; m_itemSelEnd = end; m_itemSelAlpha = alpha; }
++ void SetVisible(bool visible) { m_visible = visible; }
++ void SetAsTree(OSDGenericTree *toplevel, vector<uint> *select = NULL);
+
+- void SetFontActive(TTFFont *font);
+- void SetFontInactive(TTFFont *font);
+- void SetSpacing(int spacing);
+- void SetMargin(int margin);
+- void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha);
+- void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha);
+-
+- void SetAsTree(OSDGenericTree *toplevel);
+-
+- OSDGenericTree *GetCurrentPosition(void);
+-
++ void Reinit(float wmult, float hmult);
+ bool HandleKeypress(QKeyEvent *e);
+-
+ void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+
+- bool IsVisible(void) { return m_visible; }
+- void SetVisible(bool visible) { m_visible = visible; }
+-
+ signals:
+ void itemSelected(OSDListTreeType *parent, OSDGenericTree *item);
+ void itemEntered(OSDListTreeType *parent, OSDGenericTree *item);
+
+ private:
+- void FillLevelFromTree(OSDGenericTree *item, OSDListBtnType *list);
+- OSDListBtnType *GetLevel(int levelnum);
+- void SetCurrentPosition(void);
++ void FillLevelFromTree(OSDGenericTree *item, uint levelnum);
++ OSDListBtnType *GetLevel(uint levelnum);
++ void EnterItem(void);
++ void SelectItem(void);
+
+- int levels;
+- int curlevel;
+-
+ OSDGenericTree *treetop;
+ OSDGenericTree *currentpos;
++ TTFFont *m_active;
++ TTFFont *m_inactive;
+
+- QPtrList<OSDListBtnType> listLevels;
++ OSDListBtnList listLevels;
+
+- OSDListBtnType *currentlevel;
+-
+- TTFFont *m_active;
+- TTFFont *m_inactive;
+-
+ QColor m_itemRegBeg;
+ QColor m_itemRegEnd;
+ QColor m_itemSelBeg;
+@@ -116,62 +132,76 @@
+ uint m_itemRegAlpha;
+ uint m_itemSelAlpha;
+
+- int m_spacing;
+- int m_margin;
++ uint m_spacing;
++ uint m_margin;
++ int m_levelspacing;
+
+- QRect m_totalarea;
+- QRect m_levelsize;
+- int m_levelspacing;
++ QRect m_totalarea;
++ QRect m_levelsize;
+
+- float m_wmult;
+- float m_hmult;
++ float m_unbiasedspacing;
++ float m_unbiasedmargin;
++ QRect m_unbiasedarea;
++ QRect m_unbiasedsize;
+
+- bool m_visible;
+- bool m_arrowAccel;
++ float m_wmult;
++ float m_hmult;
++
++ int m_depth;
++ int m_levelnum;
++ bool m_visible;
++ bool m_arrowAccel;
+ };
+
+ class OSDListBtnType : public OSDType
+ {
++ friend class OSDListBtnTypeItem;
+ Q_OBJECT
++
+ public:
+ OSDListBtnType(const QString &name, const QRect& area,
+ float wmult, float hmult,
+ bool showScrollArrows = false);
+ ~OSDListBtnType();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ // General Gets
++ bool IsVisible() const { return m_visible; }
++
++ // General Sets
++ void SetFontActive(TTFFont *font) { m_fontActive = font; }
++ void SetFontInactive(TTFFont *font) { m_fontInactive = font; }
++ void SetSpacing(int spacing) { m_itemSpacing = spacing; }
++ void SetMargin(int margin) { m_itemMargin = margin; }
++ void SetActive(bool active) { m_active = active; }
++ void SetVisible(bool vis) { m_visible = vis; }
++ void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha)
++ { m_itemRegBeg = beg; m_itemRegEnd = end; m_itemRegAlpha = alpha; }
++ void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha)
++ { m_itemSelBeg = beg; m_itemSelEnd = end; m_itemSelAlpha = alpha; }
+ void SetGroupCheckState(QString group, int newState = 0);
++ void SetItemCurrent(const OSDListBtnTypeItem* item);
++ void SetItemCurrent(uint pos);
+
+- void SetFontActive(TTFFont *font);
+- void SetFontInactive(TTFFont *font);
+- void SetSpacing(int spacing);
+- void SetMargin(int margin);
+- void SetItemRegColor(const QColor& beg, const QColor& end, uint alpha);
+- void SetItemSelColor(const QColor& beg, const QColor& end, uint alpha);
+-
+- void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+-
+- void SetActive(bool active);
+- void Reset();
+-
+- void SetItemCurrent(OSDListBtnTypeItem* item);
+- void SetItemCurrent(int pos);
+- OSDListBtnTypeItem* GetItemCurrent();
+- OSDListBtnTypeItem* GetItemFirst();
+- OSDListBtnTypeItem* GetItemNext(OSDListBtnTypeItem *item);
++ // Item Gets
++ int GetCount(void) const;
++ int GetItemPos(const OSDListBtnTypeItem* item) const;
++ int GetItemCurrentPos() const;
++ OSDListBtnTypeItem* GetItemCurrent(void);
++ OSDListBtnTypeItem* GetItemFirst(void);
++ OSDListBtnTypeItem* GetItemNext(const OSDListBtnTypeItem *item);
+ OSDListBtnTypeItem* GetItemAt(int pos);
+- int GetItemPos(OSDListBtnTypeItem* item);
+- int GetCount();
+
+- void MoveDown();
+- void MoveUp();
++ // Item Sets/Commands
++ void MoveDown(void);
++ void MoveUp(void);
+
+- bool IsVisible() { return m_visible; }
+- void SetVisible(bool vis) { m_visible = vis; }
++ // General Commands
++ void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
++ void Reinit(float,float) {}
++ void Reset(void);
+
+ private:
+-
+- void Init();
++ void Init(void);
+ void InitItem(OSDTypeImage &osdImg, uint width, uint height,
+ QColor beg, QColor end, int alpha);
+ void LoadPixmap(OSDTypeImage& pix, const QString& fileName);
+@@ -179,24 +209,35 @@
+ void InsertItem(OSDListBtnTypeItem *item);
+ void RemoveItem(OSDListBtnTypeItem *item);
+
+- int m_order;
+- QRect m_rect;
+- QRect m_contentsRect;
+- QRect m_arrowsRect;
++ private:
++ int m_order;
++ QRect m_rect;
++ QRect m_contentsRect;
++ QRect m_arrowsRect;
+
+- float m_wmult;
+- float m_hmult;
++ float m_wmult;
++ float m_hmult;
+
+- int m_itemHeight;
+- int m_itemSpacing;
+- int m_itemMargin;
+- uint m_itemsVisible;
++ int m_itemHeight;
++ int m_itemSpacing;
++ int m_itemMargin;
++ uint m_itemsVisible;
+
+- bool m_active;
+- bool m_showScrollArrows;
+- bool m_showUpArrow;
+- bool m_showDnArrow;
++ bool m_active;
++ bool m_showScrollArrows;
++ bool m_showUpArrow;
++ bool m_showDnArrow;
++ bool m_initialized;
++ bool m_clearing;
++ bool m_visible;
+
++ QColor m_itemRegBeg;
++ QColor m_itemRegEnd;
++ QColor m_itemSelBeg;
++ QColor m_itemSelEnd;
++ uint m_itemRegAlpha;
++ uint m_itemSelAlpha;
++
+ OSDTypeImage m_itemRegPix;
+ OSDTypeImage m_itemSelActPix;
+ OSDTypeImage m_itemSelInactPix;
+@@ -209,43 +250,30 @@
+ OSDTypeImage m_checkHalfPix;
+ OSDTypeImage m_checkFullPix;
+
+- QColor m_itemRegBeg;
+- QColor m_itemRegEnd;
+- QColor m_itemSelBeg;
+- QColor m_itemSelEnd;
+- uint m_itemRegAlpha;
+- uint m_itemSelAlpha;
++ TTFFont *m_fontActive;
++ TTFFont *m_fontInactive;
+
+- TTFFont* m_fontActive;
+- TTFFont* m_fontInactive;
++ int m_topIndx;
++ int m_selIndx;
+
+- bool m_initialized;
+- bool m_clearing;
++ OSDListBtnItemList m_itemList;
+
+- OSDListBtnTypeItem* m_topItem;
+- OSDListBtnTypeItem* m_selItem;
+- QPtrList<OSDListBtnTypeItem> m_itemList;
++ mutable QMutex m_update;
+
+- QMutex m_update;
+-
+- bool m_visible;
+-
+- friend class OSDListBtnTypeItem;
+-
+ signals:
+-
+ void itemSelected(OSDListBtnTypeItem* item);
+ };
+
+ class OSDListBtnTypeItem
+ {
++ friend class OSDListBtnType;
+
+ public:
+-
+- enum CheckState {
+- NotChecked=0,
++ enum CheckState
++ {
++ NotChecked = 0,
+ HalfChecked,
+- FullChecked
++ FullChecked,
+ };
+
+ OSDListBtnTypeItem(OSDListBtnType* lbtype, const QString& text,
+@@ -253,41 +281,36 @@
+ bool showArrow = false, CheckState state = NotChecked);
+ ~OSDListBtnTypeItem();
+
+- OSDListBtnType* parent() const;
+- QString text() const;
+- const OSDTypeImage* pixmap() const;
+- bool checkable() const;
+- CheckState state() const;
++ OSDListBtnType* parent(void) const { return m_parent; }
++ QString text(void) const { return m_text; }
++ const OSDTypeImage* pixmap(void) const { return m_pixmap; }
++ bool checkable(void) const { return m_checkable; }
++ CheckState state(void) const { return m_state; }
++ QString getGroup(void) const { return m_group; }
++ void *getData(void) { return m_data; }
+
+- void setChecked(CheckState state);
+- void setData(void *data);
+- void* getData();
+- void setGroup(QString group) { m_group = group; };
+- QString getGroup(void) { return m_group; }
++ void setData(void *data) { m_data = data; }
++ void setGroup(QString grp) { m_group = grp; }
++ void setChecked(CheckState state)
++ { m_state = (m_checkable) ? state : m_state; }
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
+-
++ void Reinit(float,float) {}
+ void paint(OSDSurface *surface, TTFFont *font, int fade, int maxfade,
+ int x, int y);
+
+ protected:
+-
+ OSDListBtnType *m_parent;
+- QString m_text;
+- OSDTypeImage *m_pixmap;
+- bool m_checkable;
+- CheckState m_state;
+- void *m_data;
+- QString m_group;
+-
+- QRect m_checkRect;
+- QRect m_pixmapRect;
+- QRect m_textRect;
+- QRect m_arrowRect;
+-
+- bool m_showArrow;
+-
+- friend class OSDListBtnType;
++ OSDTypeImage *m_pixmap;
++ void *m_data;
++ QString m_text;
++ QString m_group;
++ CheckState m_state;
++ bool m_showArrow;
++ bool m_checkable;
++ QRect m_checkRect;
++ QRect m_arrowRect;
++ QRect m_pixmapRect;
++ QRect m_textRect;
+ };
+
+
+Index: mythtv/libs/libmythtv/NuppelVideoPlayer.cpp
+===================================================================
+--- mythtv/libs/libmythtv/NuppelVideoPlayer.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/NuppelVideoPlayer.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -147,6 +147,7 @@
+ hascommbreaktable(false),
+ deleteIter(deleteMap.end()), blankIter(blankMap.end()),
+ commBreakIter(commBreakMap.end()),
++ forcePositionMapSync(false),
+ // Playback (output) speed control
+ decoder_lock(true),
+ next_play_speed(1.0f), next_normal_speed(true),
+@@ -747,6 +748,8 @@
+ SetDecoder(new IvtvDecoder(this, m_playbackinfo));
+ no_audio_out = true; // no audio with ivtv.
+ audio_bits = 16;
++ audio_samplerate = 44100;
++ audio_channels = 2;
+ }
+ else if (forceVideoOutput == kVideoOutput_IVTV)
+ {
+@@ -1113,7 +1116,7 @@
+ const unsigned char *NuppelVideoPlayer::GetScaledFrame(QSize &size)
+ {
+ QMutexLocker locker(&yuv_lock);
+- yuv_desired_size = size = QSize(size.width() & ~0x3, size.height() & ~0x3);
++ yuv_desired_size = size = QSize(size.width() & ~0x7, size.height() & ~0x7);
+
+ if ((size.width() > 0) && (size.height() > 0))
+ {
+@@ -1920,7 +1923,7 @@
+ ShowText();
+ DisplaySubtitles();
+ }
+- else if (osdHasSubtitles || nonDisplayedSubtitles.size() > 20)
++ else if (osdHasSubtitles)
+ {
+ ClearSubtitles();
+ }
+@@ -2176,7 +2179,10 @@
+ }
+
+ if (eof)
++ {
+ discontinuity = true;
++ ClearSubtitles();
++ }
+
+ livetvchain->SetProgram(pginfo);
+
+@@ -2199,6 +2205,7 @@
+ }
+ if (IsErrored())
+ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram failed.");
+ eof = true;
+ return;
+ }
+@@ -2265,6 +2272,8 @@
+ ringBuffer->Pause();
+ ringBuffer->WaitForPause();
+
++ ClearSubtitles();
++
+ livetvchain->SetProgram(pginfo);
+
+ ringBuffer->Reset(true);
+@@ -2284,6 +2293,7 @@
+
+ if (errored || !GetDecoder())
+ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram failed.");
+ errored = true;
+ return;
+ }
+@@ -2471,6 +2481,12 @@
+ JumpToProgram();
+ }
+
++ if (forcePositionMapSync)
++ {
++ forcePositionMapSync = false;
++ GetDecoder()->SyncPositionMap();
++ }
++
+ if (IsErrored() || (nvr_enc && nvr_enc->GetErrorStatus()))
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown error, exiting decoder");
+@@ -4398,6 +4414,8 @@
+ hascommbreaktable = !commBreakMap.isEmpty();
+ SetCommBreakIter();
+ commBreakMapLock.unlock();
++
++ forcePositionMapSync = true;
+ }
+
+ bool NuppelVideoPlayer::RebuildSeekTable(bool showPercentage, StatusCallback cb, void* cbData)
+@@ -4541,7 +4559,8 @@
+ return (int)((float)(written - played) / video_frame_rate);
+ }
+
+-void NuppelVideoPlayer::calcSliderPos(struct StatusPosInfo &posInfo)
++void NuppelVideoPlayer::calcSliderPos(struct StatusPosInfo &posInfo,
++ bool paddedFields)
+ {
+ posInfo.desc = "";
+ posInfo.position = 0;
+@@ -4588,15 +4607,23 @@
+ int ssecs = (playbackLen - shours * 3600 - smins * 60);
+
+ QString text1, text2;
+- if (shours > 0)
++ if (paddedFields)
+ {
+- text1.sprintf("%d:%02d:%02d", phours, pmins, psecs);
+- text2.sprintf("%d:%02d:%02d", shours, smins, ssecs);
++ text1.sprintf("%02d:%02d:%02d", phours, pmins, psecs);
++ text2.sprintf("%02d:%02d:%02d", shours, smins, ssecs);
+ }
+ else
+ {
+- text1.sprintf("%d:%02d", pmins, psecs);
+- text2.sprintf("%d:%02d", smins, ssecs);
++ if (shours > 0)
++ {
++ text1.sprintf("%d:%02d:%02d", phours, pmins, psecs);
++ text2.sprintf("%d:%02d:%02d", shours, smins, ssecs);
++ }
++ else
++ {
++ text1.sprintf("%d:%02d", pmins, psecs);
++ text2.sprintf("%d:%02d", smins, ssecs);
++ }
+ }
+
+ posInfo.desc = QObject::tr("%1 of %2").arg(text1).arg(text2);
+@@ -4654,6 +4681,7 @@
+
+ if (commBreakIter.key() == totalFrames)
+ {
++ VERBOSE(VB_IMPORTANT, LOC + "Skipping commercial to end of file");
+ eof = true;
+ }
+ else
+@@ -4721,7 +4749,7 @@
+
+ QString message = "COMMFLAG_REQUEST ";
+ message += m_playbackinfo->chanid + " " +
+- m_playbackinfo->startts.toString(Qt::ISODate);
++ m_playbackinfo->recstartts.toString(Qt::ISODate);
+ RemoteSendMessage(message);
+
+ return false;
+@@ -5018,7 +5046,7 @@
+ QImage scaledImage = qImage.smoothScale(rect->w, rect->h);
+
+ OSDTypeImage* image = new OSDTypeImage();
+- image->SetPosition(QPoint(rect->x, rect->y));
++ image->SetPosition(QPoint(rect->x, rect->y), hmult, vmult);
+ image->LoadFromQImage(scaledImage);
+
+ subtitleOSD->AddType(image);
+Index: mythtv/libs/libmythtv/NuppelVideoRecorder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/NuppelVideoRecorder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/NuppelVideoRecorder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -216,7 +216,10 @@
+ }
+
+ if (mpa_codec)
++ {
++ QMutexLocker locker(&avcodeclock);
+ avcodec_close(mpa_ctx);
++ }
+
+ if (mpa_ctx)
+ av_free(mpa_ctx);
+@@ -453,8 +456,11 @@
+ useavcodec = true;
+
+ if (mpa_codec)
++ {
++ QMutexLocker locker(&avcodeclock);
+ avcodec_close(mpa_ctx);
+-
++ }
++
+ if (mpa_ctx)
+ av_free(mpa_ctx);
+ mpa_ctx = NULL;
+@@ -626,13 +632,14 @@
+ int frag, blocksize = 4096;
+ int tmp;
+
++ if (!skipdevice)
++ {
+ #if !defined (HAVE_SYS_SOUNDCARD_H) && !defined(HAVE_SOUNDCARD_H)
+- VERBOSE(VB_IMPORTANT, QString("NVR::AudioInit() This Unix doesn't support"
+- " device files for audio access. Skipping"));
+- return 1;
++ VERBOSE(VB_IMPORTANT,
++ QString("NVR::AudioInit() This Unix doesn't support"
++ " device files for audio access. Skipping"));
++ return 1;
+ #else
+- if (!skipdevice)
+- {
+ if (-1 == (afd = open(audiodevice.ascii(), O_RDONLY | O_NONBLOCK)))
+ {
+ VERBOSE(VB_IMPORTANT, QString("NVR: Error, cannot open DSP '%1'").
+@@ -678,8 +685,8 @@
+ }
+
+ close(afd);
++#endif
+ }
+-#endif
+
+ audio_bytes_per_sample = audio_channels * audio_bits / 8;
+ blocksize *= 4;
+Index: mythtv/libs/libmythtv/osdlistbtntype.cpp
+===================================================================
+--- mythtv/libs/libmythtv/osdlistbtntype.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/osdlistbtntype.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -19,206 +19,148 @@
+ *
+ * ============================================================ */
+
+-#include <iostream>
++// ANSI C headers
++#include <cmath>
+
++// C++ headers
++#include <algorithm>
++using namespace std;
++
++// Qt headers
+ #include <qapplication.h>
+ #include <qpixmap.h>
+ #include <qpainter.h>
+ #include <qimage.h>
+ #include <qcolor.h>
+
++// MythTV headers
+ #include "mythcontext.h"
+ #include "mythdialogs.h"
+-
+ #include "osdlistbtntype.h"
+
++#define LOC QString("OSDListTreeType: ")
++#define LOC_ERR QString("OSDListTreeType, Error: ")
+
+-OSDGenericTree::OSDGenericTree(OSDGenericTree *parent, const QString &name,
+- const QString &action, int check,
+- OSDTypeImage *image, QString group)
+- : GenericTree(name)
++static QRect unbias(QRect rect, float wmult, float hmult)
+ {
+- m_checkable = check;
+- m_action = action;
+- m_image = image;
+- m_parentButton = NULL;
+-
+- if (group != "")
+- m_group = group;
+- else
+- m_group = action;
+-
+- if (!action.isEmpty() && !action.isNull())
+- setSelectable(true);
+-
+- if (parent)
+- parent->addNode(this);
++ return QRect((int)round(rect.x() / wmult),
++ (int)round(rect.y() / hmult),
++ (int)ceil( rect.width() / wmult),
++ (int)ceil( rect.height() / hmult));
+ }
+
+-////////////////////////////////////////////////////////////////////////////
+-
+-OSDListTreeType::OSDListTreeType(const QString &name, const QRect &area,
+- const QRect &levelsize, int levelspacing,
+- float wmult, float hmult)
+- : OSDType(name)
++static QRect bias(QRect rect, float wmult, float hmult)
+ {
+- m_wmult = wmult;
+- m_hmult = hmult;
+-
+- m_totalarea = area;
+- m_levelsize = levelsize;
+- m_levelspacing = levelspacing;
+-
+- if (gContext->GetNumSetting("UseArrowAccels", 1))
+- m_arrowAccel = true;
+- else
+- m_arrowAccel = false;
+-
+- levels = 0;
+- curlevel = -1;
+-
+- treetop = NULL;
+- currentpos = NULL;
+-
+- currentlevel = NULL;
+-
+- listLevels.setAutoDelete(true);
+-
+- m_active = NULL;
+- m_inactive = NULL;
+-
+- SetItemRegColor(Qt::black,QColor(80,80,80),100);
+- SetItemSelColor(QColor(82,202,56),QColor(52,152,56),255);
+-
+- m_spacing = 0;
+- m_margin = 0;
++ return QRect((int)round(rect.x() * wmult),
++ (int)round(rect.y() * hmult),
++ (int)ceil( rect.width() * wmult),
++ (int)ceil( rect.height() * hmult));
+ }
+
+-void OSDListTreeType::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
++OSDListTreeType::OSDListTreeType(
++ const QString &name, const QRect &area,
++ const QRect &levelsize, int levelspacing,
++ float wmult, float hmult)
++ : OSDType(name),
++ treetop(NULL), currentpos(NULL),
++ m_active(NULL), m_inactive(NULL),
++ m_itemRegBeg(Qt::black), m_itemRegEnd(QColor(80,80,80)),
++ m_itemSelBeg(QColor(82,202,56)), m_itemSelEnd(QColor(52,152,56)),
++ m_itemRegAlpha(100), m_itemSelAlpha(255),
++ m_spacing(0), m_margin(0),
++ m_levelspacing(levelspacing),
++ m_totalarea(area), m_levelsize(levelsize),
++ m_unbiasedspacing(1.0f), m_unbiasedmargin(1.0f),
++ m_unbiasedarea(0,0,0,0), m_unbiasedsize(0,0,0,0),
++ m_wmult(wmult), m_hmult(hmult),
++ m_depth(0), m_levelnum(-1),
++ m_visible(true),
++ m_arrowAccel(gContext->GetNumSetting("UseArrowAccels", 1))
+ {
+- m_wmult = wmult;
+- m_hmult = hmult;
+-
+- m_spacing = (int)(m_spacing * wchange);
+- m_margin = (int)(m_margin * wchange);
+-
+- int width = (int)(m_totalarea.width() * wchange);
+- int height = (int)(m_totalarea.height() * hchange);
+- int x = (int)(m_totalarea.x() * wchange);
+- int y = (int)(m_totalarea.y() * hchange);
+-
+- m_totalarea = QRect(x, y, width, height);
+-
+- width = (int)(m_levelsize.width() * wchange);
+- height = (int)(m_levelsize.height() * hchange);
+- x = (int)(m_levelsize.x() * wchange);
+- y = (int)(m_levelsize.y() * hchange);
+-
+- m_levelsize = QRect(x, y, width, height);
+-
+- QPtrListIterator<OSDListBtnType> it(listLevels);
+- OSDListBtnType *child;
+-
+- while ((child = it.current()) != 0)
+- {
+- child->Reinit(wchange, hchange, wmult, hmult);
+- ++it;
+- }
++ m_wmult = (wmult == 0.0f) ? 1.0f : wmult;
++ m_hmult = (hmult == 0.0f) ? 1.0f : hmult;
++ m_unbiasedarea = unbias(area, wmult, hmult);
++ m_unbiasedsize = unbias(levelsize, wmult, hmult);
+ }
+
+-void OSDListTreeType::SetGroupCheckState(QString group, int newState)
++OSDListTreeType::~OSDListTreeType()
+ {
+- QPtrListIterator<OSDListBtnType> it(listLevels);
+- OSDListBtnType *child;
+- while ((child = it.current()) != 0)
+- {
+- child->SetGroupCheckState(group, newState);
+- ++it;
+- }
++ OSDListBtnList::iterator it = listLevels.begin();
++ for (; it != listLevels.end(); ++it)
++ delete *it;
+ }
+
+-void OSDListTreeType::SetItemRegColor(const QColor& beg, const QColor& end,
+- uint alpha)
++void OSDListTreeType::Reinit(float wmult, float hmult)
+ {
+- m_itemRegBeg = beg;
+- m_itemRegEnd = end;
+- m_itemRegAlpha = alpha;
+-}
++ m_wmult = (wmult == 0.0f) ? 1.0f : wmult;
++ m_hmult = (hmult == 0.0f) ? 1.0f : hmult;
++ m_spacing = (uint) round(m_unbiasedspacing * wmult);
++ m_margin = (uint) round(m_unbiasedmargin * wmult);
++ m_totalarea = bias(m_unbiasedarea, wmult, hmult);
++ m_levelsize = bias(m_unbiasedsize, wmult, hmult);
+
+-void OSDListTreeType::SetItemSelColor(const QColor& beg, const QColor& end,
+- uint alpha)
+-{
+- m_itemSelBeg = beg;
+- m_itemSelEnd = end;
+- m_itemSelAlpha = alpha;
+-}
++ if (!treetop || m_levelnum < 0)
++ return;
+
+-void OSDListTreeType::SetFontActive(TTFFont *font)
+-{
+- m_active = font;
+-}
++ // Save item indices
++ vector<uint> list;
++ for (uint i = 0; i <= (uint)m_levelnum; i++)
++ list.push_back(listLevels[i]->GetItemCurrentPos());
+
+-void OSDListTreeType::SetFontInactive(TTFFont *font)
+-{
+- m_inactive = font;
+-}
++ // Delete old OSD items
++ OSDListBtnList clone = listLevels;
++ listLevels.clear();
++ OSDListBtnList::iterator it = clone.begin();
++ for (; it != clone.end(); ++it)
++ delete *it;
+
+-void OSDListTreeType::SetSpacing(int spacing)
+-{
+- m_spacing = spacing;
++ // Create new OSD items
++ SetAsTree(treetop, &list);
+ }
+
+-void OSDListTreeType::SetMargin(int margin)
++void OSDListTreeType::SetGroupCheckState(QString group, int newState)
+ {
+- m_margin = margin;
++ OSDListBtnList::iterator it = listLevels.begin();
++ for (; it != listLevels.end(); ++it)
++ (*it)->SetGroupCheckState(group, newState);
+ }
+
+-void OSDListTreeType::SetAsTree(OSDGenericTree *toplevel)
++void OSDListTreeType::SetAsTree(OSDGenericTree *toplevel,
++ vector<uint> *select_list)
+ {
+ if (treetop)
+ {
+ listLevels.clear();
+- currentlevel = NULL;
+- treetop = NULL;
+- currentpos = NULL;
+- levels = 0;
+- curlevel = -1;
++ treetop = NULL;
++ currentpos = NULL;
++ m_depth = 0;
++ m_levelnum = -1;
+ }
+
+- levels = toplevel->calculateDepth(0) - 1;
+-
+- if (levels <= 0)
++ m_depth = toplevel->calculateDepth(0) - 1;
++ if (m_depth <= 0)
+ {
+- cerr << "Need at least one level\n";
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "SetAsTree: Need at least one level");
+ return;
+ }
+
+- currentpos = (OSDGenericTree *)toplevel->getChildAt(0);
+-
++ currentpos = (OSDGenericTree*) toplevel->getChildAt(0);
+ if (!currentpos)
+ {
+- cerr << "No top-level children?\n";
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "SetAsTree: Need top-level children");
+ return;
+ }
+
+- treetop = toplevel;
+-
+- // just for now, remove later
+- if (levels > 2)
+- levels = 3;
+-
+- for (int i = 0; i < levels; i++)
++ // Create OSD buttons for all levels
++ for (uint i = 0; i < (uint)m_depth; i++)
+ {
+ QString levelname = QString("level%1").arg(i + 1);
+-
+ QRect curlevelarea = m_levelsize;
+ curlevelarea.moveBy(m_totalarea.x(), m_totalarea.y());
+-
+ curlevelarea.moveBy((m_levelsize.width() + m_levelspacing) * i, 0);
+
+- OSDListBtnType *newlevel = new OSDListBtnType(levelname, curlevelarea,
+- m_wmult, m_hmult, true);
++ OSDListBtnType *newlevel = new OSDListBtnType(
++ levelname, curlevelarea, m_wmult, m_hmult, true);
+
+ newlevel->SetFontActive(m_active);
+ newlevel->SetFontInactive(m_inactive);
+@@ -227,229 +169,200 @@
+ newlevel->SetSpacing(m_spacing);
+ newlevel->SetMargin(m_margin);
+
+- listLevels.append(newlevel);
++ listLevels.push_back(newlevel);
+ }
+
+- currentlevel = GetLevel(0);
++ // Set up needed levels and selects
++ vector<uint> slist;
++ slist.push_back(0);
++ if (select_list)
++ slist = *select_list;
+
+- if (!currentlevel)
++ currentpos = treetop = toplevel;
++ for (m_levelnum = 0; m_levelnum < (int)slist.size(); m_levelnum++)
+ {
+- cerr << "Something is seriously wrong (currentlevel = NULL)\n";
+- return;
++ FillLevelFromTree(currentpos, m_levelnum);
++ GetLevel(m_levelnum)->SetActive(true);
++ GetLevel(m_levelnum)->SetVisible(true);
++ if (slist[m_levelnum])
++ GetLevel(m_levelnum)->SetItemCurrent(slist[m_levelnum]);
++ EnterItem(); // updates currentpos
+ }
+-
+- FillLevelFromTree(toplevel, currentlevel);
+-
+- currentlevel->SetVisible(true);
+- currentlevel->SetActive(true);
+-
+- currentpos = (OSDGenericTree *)(currentlevel->GetItemFirst()->getData());
+- curlevel = 0;
+-
+- emit itemEntered(this, currentpos);
++ m_levelnum--;
+ }
+
+-OSDGenericTree *OSDListTreeType::GetCurrentPosition(void)
++static bool has_action(QString action, const QStringList &actions)
+ {
+- return currentpos;
++ QStringList::const_iterator it;
++ for (it = actions.begin(); it != actions.end(); ++it)
++ {
++ if (action == *it)
++ return true;
++ }
++ return false;
+ }
+
+ bool OSDListTreeType::HandleKeypress(QKeyEvent *e)
+ {
+- if (!currentlevel)
++ QStringList actions;
++ bool ok = gContext->GetMainWindow()->TranslateKeyPress(
++ "TV Playback", e, actions);
++
++ if (!ok || ((uint)m_levelnum >= listLevels.size()))
+ return false;
++ else if (has_action("UP", actions))
++ {
++ GetLevel(m_levelnum)->MoveUp();
++ EnterItem();
++ }
++ else if (has_action("DOWN", actions))
++ {
++ GetLevel(m_levelnum)->MoveDown();
++ EnterItem();
++ }
++ else if (has_action("LEFT", actions) && (m_levelnum > 0))
++ {
++ GetLevel(m_levelnum)->Reset();
++ GetLevel(m_levelnum)->SetVisible(false);
+
+- bool handled = false;
+- QStringList actions;
+- if (gContext->GetMainWindow()->TranslateKeyPress("TV Playback", e,
+- actions))
++ m_levelnum--;
++ EnterItem();
++ }
++ else if ((has_action("LEFT", actions) && m_arrowAccel) ||
++ has_action("ESCAPE", actions) ||
++ has_action("CLEAROSD", actions) ||
++ has_action("MENU", actions))
+ {
+- for (unsigned int i = 0; i < actions.size() && !handled; i++)
+- {
+- QString action = actions[i];
+- handled = true;
++ m_visible = false;
++ }
++ else if (has_action("RIGHT", actions) &&
++ (m_levelnum + 1 < m_depth) &&
++ (currentpos->childCount() > 0))
++ {
++ GetLevel(m_levelnum)->SetActive(false);
++ m_levelnum++;
+
+- if (action == "UP")
+- {
+- currentlevel->MoveUp();
+- SetCurrentPosition();
+- }
+- else if (action == "DOWN")
+- {
+- currentlevel->MoveDown();
+- SetCurrentPosition();
+- }
+- else if (action == "LEFT")
+- {
+- if (curlevel > 0)
+- {
+- currentlevel->Reset();
+- currentlevel->SetVisible(false);
+-
+- curlevel--;
+-
+- currentlevel = GetLevel(curlevel);
+- currentlevel->SetActive(true);
+- SetCurrentPosition();
+- }
+- else if (m_arrowAccel)
+- {
+- m_visible = false;
+- }
+- }
+- else if (action == "RIGHT")
+- {
+- // FIXME: create new levels if needed..
+- if (curlevel + 1 < levels && currentpos->childCount() > 0)
+- {
+- currentlevel->SetActive(false);
+-
+- curlevel++;
+-
+- currentlevel = GetLevel(curlevel);
+-
+- FillLevelFromTree(currentpos, currentlevel);
+-
+- currentlevel->SetVisible(true);
+- currentlevel->SetActive(true);
+- SetCurrentPosition();
+- }
+- else if (m_arrowAccel)
+- {
+- SetGroupCheckState(currentpos->getGroup(),
+- OSDListBtnTypeItem::NotChecked);
+- currentpos->getParentButton()->setChecked(
+- OSDListBtnTypeItem::FullChecked);
+- emit itemSelected(this, currentpos);
+- }
+- }
+- else if (action == "ESCAPE" || action == "MENU" ||
+- action == "CLEAROSD")
+- m_visible = false;
+- else if (action == "SELECT")
+- {
+- SetGroupCheckState(currentpos->getGroup(),
+- OSDListBtnTypeItem::NotChecked);
+- currentpos->getParentButton()->setChecked(
+- OSDListBtnTypeItem::FullChecked);
+- emit itemSelected(this, currentpos);
+- }
+- else
+- handled = false;
+- }
++ FillLevelFromTree(currentpos, m_levelnum);
++ GetLevel(m_levelnum)->SetVisible(true);
++ EnterItem();
+ }
++ else if ((has_action("RIGHT", actions) && m_arrowAccel) ||
++ has_action("SELECT", actions))
++ {
++ SelectItem();
++ }
++ else
++ {
++ return false;
++ }
+
+- return handled;
++ return true;
+ }
+
+ void OSDListTreeType::Draw(OSDSurface *surface, int fade, int maxfade,
+ int xoff, int yoff)
+ {
+- QPtrListIterator<OSDListBtnType> it(listLevels);
+- OSDListBtnType *child;
+-
+- while ((child = it.current()) != 0)
+- {
+- child->Draw(surface, fade, maxfade, xoff, yoff);
+- ++it;
+- }
++ OSDListBtnList::iterator it = listLevels.begin();
++ for (; it != listLevels.end(); ++it)
++ (*it)->Draw(surface, fade, maxfade, xoff, yoff);
+ }
+
+ void OSDListTreeType::FillLevelFromTree(OSDGenericTree *item,
+- OSDListBtnType *list)
++ uint level_num)
+ {
++ OSDListBtnType *list = GetLevel(level_num);
+ if (!list)
+ {
+- VERBOSE(VB_IMPORTANT, "OSDListTreeType::FillLevelFromTree() "
+- "called with no list. Ignoring call.");
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "FillLevelFromTree() "
++ "called with no list, ignoring.");
+ return;
+ }
+ list->Reset();
+
+ QPtrList<GenericTree> *itemlist = item->getAllChildren();
+-
+ QPtrListIterator<GenericTree> it(*itemlist);
+- GenericTree *child;
+
+- while ((child = it.current()) != 0)
++ OSDGenericTree *child = (OSDGenericTree*) it.current();
++ OSDListBtnTypeItem *newitem = NULL;
++ for (;(child = (OSDGenericTree*) it.current()); ++it)
+ {
+- OSDGenericTree *osdchild = (OSDGenericTree *)child;
++ OSDTypeImage *im = child->getImage();
++ QString label = child->getString();
++ QString group = child->getGroup();
++ bool canCheck = child->getCheckable() >= 0;
++ bool hasCheck = child->getCheckable() == 1;
++ bool hasChild = child->childCount() > 0;
+
+- OSDListBtnTypeItem *newitem;
+- newitem = new OSDListBtnTypeItem(list, child->getString(),
+- osdchild->getImage(),
+- (osdchild->getCheckable() >= 0),
+- (child->childCount() > 0));
+- if (osdchild->getCheckable() == 1)
++ newitem = new OSDListBtnTypeItem(list, label, im, canCheck, hasChild);
++
++ if (hasCheck)
+ newitem->setChecked(OSDListBtnTypeItem::FullChecked);
+- newitem->setGroup(osdchild->getGroup());
+- newitem->setData(osdchild);
+- osdchild->setParentButton(newitem);
++ newitem->setGroup(group);
++ newitem->setData(child);
+
+- ++it;
++ child->setParentButton(newitem);
+ }
+ }
+
+-OSDListBtnType *OSDListTreeType::GetLevel(int levelnum)
++OSDListBtnType *OSDListTreeType::GetLevel(uint levelnum)
+ {
+- if ((uint)levelnum > listLevels.count())
+- {
+- cerr << "OOB GetLevel call\n";
+- return NULL;
+- }
++ if (levelnum < listLevels.size())
++ return listLevels[levelnum];
+
+- return listLevels.at(levelnum);
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "GetLevel("<<levelnum<<") "
++ "listLevels.size() is only "<<listLevels.size());
++ return NULL;
+ }
+
+-void OSDListTreeType::SetCurrentPosition(void)
++void OSDListTreeType::EnterItem(void)
+ {
+- if (!currentlevel)
++ if ((uint)m_levelnum >= listLevels.size())
+ return;
+
+- OSDListBtnTypeItem *lbt = currentlevel->GetItemCurrent();
++ listLevels[m_levelnum]->SetActive(true);
++ OSDListBtnTypeItem *lbt = listLevels[m_levelnum]->GetItemCurrent();
++ if (lbt)
++ {
++ currentpos = (OSDGenericTree*) (lbt->getData());
++ emit itemEntered(this, currentpos);
++ }
++}
+
+- if (!lbt)
++void OSDListTreeType::SelectItem(void)
++{
++ if (!currentpos)
+ return;
+
+- currentpos = (OSDGenericTree *)(lbt->getData());
+- emit itemEntered(this, currentpos);
++ SetGroupCheckState(currentpos->getGroup(), OSDListBtnTypeItem::NotChecked);
++ currentpos->getParentButton()->setChecked(OSDListBtnTypeItem::FullChecked);
++ emit itemSelected(this, currentpos);
+ }
+-
++
++#undef LOC_ERR
++#undef LOC
++
+ //////////////////////////////////////////////////////////////////////////
+
+ OSDListBtnType::OSDListBtnType(const QString &name, const QRect &area,
+ float wmult, float hmult,
+ bool showScrollArrows)
+- : OSDType(name)
++ : OSDType(name),
++ m_order(0), m_rect(area),
++ m_contentsRect(0,0,0,0), m_arrowsRect(0,0,0,0),
++ m_wmult(wmult), m_hmult(hmult),
++ m_itemHeight(0), m_itemSpacing(0),
++ m_itemMargin(0), m_itemsVisible(0),
++ m_active(false), m_showScrollArrows(showScrollArrows),
++ m_showUpArrow(false), m_showDnArrow(false),
++ m_initialized(false), m_clearing(false),
++ m_visible(false),
++ m_itemRegBeg(Qt::black), m_itemRegEnd(QColor(80,80,80)),
++ m_itemSelBeg(QColor(82,202,56)), m_itemSelEnd(QColor(52,152,56)),
++ m_itemRegAlpha(100), m_itemSelAlpha(255),
++ m_fontActive(NULL), m_fontInactive(NULL),
++ m_topIndx(0), m_selIndx(0),
++ m_update(true)
+ {
+- m_rect = area;
+-
+- m_wmult = wmult;
+- m_hmult = hmult;
+-
+- m_showScrollArrows = showScrollArrows;
+-
+- m_active = false;
+- m_showUpArrow = false;
+- m_showDnArrow = false;
+-
+- m_itemList.setAutoDelete(false);
+- m_topItem = 0;
+- m_selItem = 0;
+-
+- m_initialized = false;
+- m_clearing = false;
+- m_itemSpacing = 0;
+- m_itemMargin = 0;
+- m_itemHeight = 0;
+- m_itemsVisible = 0;
+- m_fontActive = 0;
+- m_fontInactive = 0;
+-
+- SetItemRegColor(Qt::black,QColor(80,80,80),100);
+- SetItemSelColor(QColor(82,202,56),QColor(52,152,56),255);
+-
+- m_visible = false;
+ }
+
+ OSDListBtnType::~OSDListBtnType()
+@@ -457,316 +370,198 @@
+ Reset();
+ }
+
+-void OSDListBtnType::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
+-{
+- m_wmult = wmult;
+- m_hmult = hmult;
+-
+- m_itemHeight = (int)(m_itemHeight * hchange);
+- m_itemSpacing = (int)(m_itemSpacing * wchange);
+- m_itemMargin = (int)(m_itemMargin * wchange);
+-
+- int width = (int)(m_rect.width() * wchange);
+- int height = (int)(m_rect.height() * hchange);
+- int x = (int)(m_rect.x() * wchange);
+- int y = (int)(m_rect.y() * hchange);
+-
+- m_rect = QRect(x, y, width, height);
+-
+- Init();
+-
+- OSDListBtnTypeItem* item = 0;
+- for (item = m_itemList.first(); item; item = m_itemList.next()) {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+-
+-}
+-
+ void OSDListBtnType::SetGroupCheckState(QString group, int newState)
+ {
+- OSDListBtnTypeItem* item = 0;
+- for (item = m_itemList.first(); item; item = m_itemList.next()) {
+- if (item->getGroup() == group)
+- item->setChecked((OSDListBtnTypeItem::CheckState)newState);
+- }
++ OSDListBtnItemList::iterator it;
++ for (it = m_itemList.begin(); it != m_itemList.end(); ++it)
++ if ((*it)->getGroup() == group)
++ (*it)->setChecked((OSDListBtnTypeItem::CheckState) newState);
+ }
+
+-void OSDListBtnType::SetItemRegColor(const QColor& beg, const QColor& end,
+- uint alpha)
++void OSDListBtnType::Reset(void)
+ {
+- m_itemRegBeg = beg;
+- m_itemRegEnd = end;
+- m_itemRegAlpha = alpha;
+-}
+-
+-void OSDListBtnType::SetItemSelColor(const QColor& beg, const QColor& end,
+- uint alpha)
+-{
+- m_itemSelBeg = beg;
+- m_itemSelEnd = end;
+- m_itemSelAlpha = alpha;
+-}
+-
+-void OSDListBtnType::SetFontActive(TTFFont *font)
+-{
+- m_fontActive = font;
+-}
+-
+-void OSDListBtnType::SetFontInactive(TTFFont *font)
+-{
+- m_fontInactive = font;
+-}
+-
+-void OSDListBtnType::SetSpacing(int spacing)
+-{
+- m_itemSpacing = spacing;
+-}
+-
+-void OSDListBtnType::SetMargin(int margin)
+-{
+- m_itemMargin = margin;
+-}
+-
+-void OSDListBtnType::SetActive(bool active)
+-{
+- m_active = active;
+-}
+-
+-void OSDListBtnType::Reset()
+-{
+ QMutexLocker lock(&m_update);
+
+ m_clearing = true;
+-
+- OSDListBtnTypeItem* item = 0;
+- for (item = m_itemList.first(); item; item = m_itemList.next()) {
+- delete item;
+- }
+-
+- m_clearing = false;
++ OSDListBtnItemList::iterator it;
++ OSDListBtnItemList clone = m_itemList;
+ m_itemList.clear();
+-
+- m_topItem = 0;
+- m_selItem = 0;
++ for (it = clone.begin(); it != clone.end(); ++it)
++ delete (*it);
++ m_clearing = false;
++
++ m_topIndx = 0;
++ m_selIndx = 0;
+ m_showUpArrow = false;
+ m_showDnArrow = false;
+ }
+
+ void OSDListBtnType::InsertItem(OSDListBtnTypeItem *item)
+ {
+- OSDListBtnTypeItem* lastItem = m_itemList.last();
+- m_itemList.append(item);
+-
+- if (m_showScrollArrows && m_itemList.count() > m_itemsVisible)
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
+-
+- if (!lastItem)
+- {
+- m_topItem = item;
+- m_selItem = item;
++ QMutexLocker lock(&m_update);
++ m_itemList.push_back(item);
++ m_showDnArrow = m_showScrollArrows && m_itemList.size() > m_itemsVisible;
++ if (m_itemList.size() == 1)
+ emit itemSelected(item);
+- }
+ }
+
++int find(const OSDListBtnItemList &list, const OSDListBtnTypeItem *item)
++{
++ for (uint i = 0; i < list.size(); i++)
++ if (list[i] == item)
++ return i;
++ return -1;
++}
++
+ void OSDListBtnType::RemoveItem(OSDListBtnTypeItem *item)
+ {
++ QMutexLocker lock(&m_update);
+ if (m_clearing)
+ return;
+-
+- if (m_itemList.find(item) == -1)
++
++ int i = find(m_itemList, item);
++ if (i < 0)
+ return;
+
+- m_topItem = m_itemList.first();
+- m_selItem = m_itemList.first();
++ m_itemList.erase(m_itemList.begin()+i);
+
+- m_itemList.remove(item);
+-
+ m_showUpArrow = false;
+-
+- if (m_showScrollArrows && m_itemList.count() > m_itemsVisible)
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
++ m_showDnArrow = m_itemList.size() > m_itemsVisible;
++ m_selIndx = 0;
++ m_topIndx = 0;
+
+- if (m_selItem) {
+- emit itemSelected(m_selItem);
+- }
++ if (m_itemList.size())
++ emit itemSelected(m_itemList[m_selIndx]);
+ }
+
+-void OSDListBtnType::SetItemCurrent(OSDListBtnTypeItem* item)
++void OSDListBtnType::SetItemCurrent(const OSDListBtnTypeItem* item)
+ {
+- bool locked = m_update.tryLock();
++ QMutexLocker lock(&m_update);
++ int i = find(m_itemList, item);
++ if (i >= 0)
++ SetItemCurrent(i);
++}
+
+- if (m_itemList.find(item) == -1)
++void OSDListBtnType::SetItemCurrent(uint current)
++{
++ QMutexLocker lock(&m_update);
++ if (current >= m_itemList.size())
+ return;
+
+- m_topItem = item;
+- m_selItem = item;
+-
+- if (m_showScrollArrows && m_itemList.count() > m_itemsVisible)
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
+-
+- emit itemSelected(m_selItem);
+-
+- if (locked)
+- m_update.unlock();
++ m_selIndx = current;
++ m_topIndx = max(m_selIndx - (int)m_itemsVisible, 0);
++ m_showUpArrow = m_topIndx;
++ m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size();
++ emit itemSelected(m_itemList[m_selIndx]);
+ }
+
+-void OSDListBtnType::SetItemCurrent(int current)
++int OSDListBtnType::GetItemCurrentPos(void) const
+ {
+ QMutexLocker lock(&m_update);
+-
+- OSDListBtnTypeItem* item = m_itemList.at(current);
+- if (!item)
+- item = m_itemList.first();
+-
+- SetItemCurrent(item);
++ return (m_itemList.size()) ? m_selIndx : -1;
+ }
+
+-OSDListBtnTypeItem* OSDListBtnType::GetItemCurrent()
++OSDListBtnTypeItem* OSDListBtnType::GetItemCurrent(void)
+ {
+- return m_selItem;
++ QMutexLocker lock(&m_update);
++ if (!m_itemList.size())
++ return NULL;
++ return m_itemList[m_selIndx];
+ }
+
+-OSDListBtnTypeItem* OSDListBtnType::GetItemFirst()
++OSDListBtnTypeItem* OSDListBtnType::GetItemFirst(void)
+ {
+- return m_itemList.first();
++ QMutexLocker lock(&m_update);
++ if (!m_itemList.size())
++ return NULL;
++ return m_itemList[0];
+ }
+
+-OSDListBtnTypeItem* OSDListBtnType::GetItemNext(OSDListBtnTypeItem *item)
++OSDListBtnTypeItem* OSDListBtnType::GetItemNext(const OSDListBtnTypeItem *item)
+ {
+ QMutexLocker lock(&m_update);
+-
+- if (m_itemList.find(item) == -1)
+- return 0;
+-
+- return m_itemList.next();
++ int i = find(m_itemList, item) + 1;
++ if (i <= 0 || i >= (int)m_itemList.size())
++ return NULL;
++ return m_itemList[i];
+ }
+
+-int OSDListBtnType::GetCount()
++int OSDListBtnType::GetCount(void) const
+ {
+- return m_itemList.count();
++ QMutexLocker lock(&m_update);
++ return m_itemList.size();
+ }
+
+ OSDListBtnTypeItem* OSDListBtnType::GetItemAt(int pos)
+ {
+- return m_itemList.at(pos);
++ QMutexLocker lock(&m_update);
++ return m_itemList[pos];
+ }
+
+-int OSDListBtnType::GetItemPos(OSDListBtnTypeItem* item)
++int OSDListBtnType::GetItemPos(const OSDListBtnTypeItem *item) const
+ {
+ QMutexLocker lock(&m_update);
+-
+- return m_itemList.find(item);
++ return find(m_itemList, item);
+ }
+
+-void OSDListBtnType::MoveUp()
++void OSDListBtnType::MoveUp(void)
+ {
+ QMutexLocker lock(&m_update);
+-
+- if (m_itemList.find(m_selItem) == -1)
++ if (!m_itemList.size())
+ return;
+
+- OSDListBtnTypeItem *item = m_itemList.prev();
+- if (!item)
++ if (--m_selIndx < 0)
+ {
+- item = m_itemList.last();
+- if (!item)
+- return;
+-
+- if (m_itemList.count() > m_itemsVisible)
+- m_topItem = m_itemList.at(m_itemList.count() - m_itemsVisible);
+- else
+- m_topItem = m_itemList.first();
++ m_selIndx = m_itemList.size() - 1;
++ m_topIndx = (m_itemList.size() > m_itemsVisible) ?
++ m_itemList.size() - m_itemsVisible : 0;
+ }
+
+- m_selItem = item;
++ m_topIndx = (m_selIndx < m_topIndx) ? m_selIndx : m_topIndx;
++ m_showUpArrow = m_topIndx;
++ m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size();
+
+- if (m_itemList.find(m_selItem) < m_itemList.find(m_topItem))
+- m_topItem = m_selItem;
+-
+- if (m_topItem != m_itemList.first())
+- m_showUpArrow = true;
+- else
+- m_showUpArrow = false;
+-
+- if (m_itemList.find(m_topItem) + m_itemsVisible < m_itemList.count())
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
+-
+- emit itemSelected(m_selItem);
++ emit itemSelected(m_itemList[m_selIndx]);
+ }
+
+-void OSDListBtnType::MoveDown()
++void OSDListBtnType::MoveDown(void)
+ {
+ QMutexLocker lock(&m_update);
+-
+- if (m_itemList.find(m_selItem) == -1)
++ if (!m_itemList.size())
+ return;
+
+- OSDListBtnTypeItem *item = m_itemList.next();
+- if (!item)
+- {
+- item = m_itemList.first();
+- if (!item)
+- return;
++ if (++m_selIndx >= (int)m_itemList.size())
++ m_selIndx = m_topIndx = 0;
+
+- m_topItem = item;
+- }
+-
+- m_selItem = item;
+-
+- if (m_itemList.find(m_topItem) + m_itemsVisible <=
+- (unsigned int)m_itemList.find(m_selItem))
+- {
+- m_topItem = m_itemList.at(m_itemList.find(m_topItem) + 1);
+- }
++ bool scroll_down = m_topIndx + (int)m_itemsVisible <= m_selIndx;
++ m_topIndx = (scroll_down) ? m_topIndx + 1 : m_topIndx;
++
++ m_showUpArrow = m_topIndx;
++ m_showDnArrow = m_topIndx + m_itemsVisible < m_itemList.size();
+
+- if (m_topItem != m_itemList.first())
+- m_showUpArrow = true;
+- else
+- m_showUpArrow = false;
+-
+- if (m_itemList.find(m_topItem) + m_itemsVisible < m_itemList.count())
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
+-
+- emit itemSelected(m_selItem);
++ emit itemSelected(m_itemList[m_selIndx]);
+ }
+
+-void OSDListBtnType::Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
+- int yoff)
++void OSDListBtnType::Draw(OSDSurface *surface,
++ int fade, int maxfade,
++ int xoff, int yoff)
+ {
+- (void)xoff;
+- (void)yoff;
+-
++ QMutexLocker lock(&m_update);
+ if (!m_visible)
+ return;
+-
+- QMutexLocker lock(&m_update);
+-
+ if (!m_initialized)
+ Init();
+
+ TTFFont *font = m_active ? m_fontActive : m_fontInactive;
+
+ int y = m_rect.y();
+- m_itemList.find(m_topItem);
+- OSDListBtnTypeItem *it = m_itemList.current();
+- while (it && (y - m_rect.y()) <= (m_contentsRect.height() - m_itemHeight))
++ for (uint i = m_topIndx; i < m_itemList.size(); i++)
+ {
+- it->paint(surface, font, fade, maxfade, m_rect.x()+ xoff, y + yoff);
+-
++ if (!((y - m_rect.y()) <= (m_contentsRect.height() - m_itemHeight)))
++ break;
++ m_itemList[i]->paint(surface, font, fade, maxfade,
++ m_rect.x() + xoff, y + yoff);
+ y += m_itemHeight + m_itemSpacing;
+-
+- it = m_itemList.next();
+ }
+
+ if (m_showScrollArrows)
+@@ -792,14 +587,13 @@
+ }
+ }
+
+-void OSDListBtnType::Init()
++void OSDListBtnType::Init(void)
+ {
+ int sz1 = m_fontActive->Size() * 3 / 2;
+ int sz2 = m_fontInactive->Size() * 3 / 2;
+- m_itemHeight = QMAX(sz1, sz2) + (int)(2 * m_itemMargin);
++ m_itemHeight = max(sz1, sz2) + (int)(2 * m_itemMargin);
++ m_itemHeight = m_itemHeight & ~0x1;
+
+- m_itemHeight = (m_itemHeight / 2) * 2;
+-
+ if (m_showScrollArrows)
+ {
+ LoadPixmap(m_upArrowRegPix, "uparrow-reg");
+@@ -838,11 +632,7 @@
+ InitItem(m_itemSelActPix, itemWidth, m_itemHeight,
+ m_itemSelBeg, m_itemSelEnd, 255);
+
+- if (m_itemList.count() > m_itemsVisible && m_showScrollArrows)
+- m_showDnArrow = true;
+- else
+- m_showDnArrow = false;
+-
++ m_showDnArrow = m_itemList.size() > m_itemsVisible && m_showScrollArrows;
+ m_initialized = true;
+ }
+
+@@ -885,68 +675,57 @@
+
+ void OSDListBtnType::LoadPixmap(OSDTypeImage& pix, const QString& fileName)
+ {
+- QString file = gContext->GetThemesParentDir() + "default/lb-" + fileName + ".png";
+- pix.LoadImage(file, m_wmult, m_hmult);
++ QString path = gContext->GetThemesParentDir() + "default/lb-";
++ pix.LoadImage(path + fileName + ".png", m_wmult, m_hmult);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+-OSDListBtnTypeItem::OSDListBtnTypeItem(OSDListBtnType* lbtype,
+- const QString& text,
+- OSDTypeImage *pixmap, bool checkable,
+- bool showArrow, CheckState state)
++OSDListBtnTypeItem::OSDListBtnTypeItem(
++ OSDListBtnType *lbtype, const QString &text,
++ OSDTypeImage *pixmap, bool checkable,
++ bool showArrow, CheckState state)
++ : m_parent(lbtype), m_pixmap(pixmap),
++ m_data(NULL), m_text(text),
++ m_group(QString::null), m_state(state),
++ m_showArrow(showArrow), m_checkable(checkable),
++ m_checkRect(0,0,0,0), m_arrowRect(0,0,0,0),
++ m_pixmapRect(0,0,0,0), m_textRect(0,0,0,0)
+ {
+- m_parent = lbtype;
+- m_text = text;
+- m_pixmap = pixmap;
+- m_checkable = checkable;
+- m_state = state;
+- m_showArrow = showArrow;
+- m_data = 0;
+-
+ if (!m_parent->m_initialized)
+ m_parent->Init();
+
+- int margin = m_parent->m_itemMargin;
+- int width = m_parent->m_rect.width();
+- int height = m_parent->m_itemHeight;
++ OSDTypeImage &checkPix = m_parent->m_checkNonePix;
++ OSDTypeImage &arrowPix = m_parent->m_arrowPix;
+
+- OSDTypeImage& checkPix = m_parent->m_checkNonePix;
+- OSDTypeImage& arrowPix = m_parent->m_arrowPix;
+-
+- int cw = checkPix.ImageSize().width();
+- int ch = checkPix.ImageSize().height();
+- int aw = arrowPix.ImageSize().width();
+- int ah = arrowPix.ImageSize().height();
+- int pw = m_pixmap ? m_pixmap->ImageSize().width() : 0;
+- int ph = m_pixmap ? m_pixmap->ImageSize().height() : 0;
+-
++ int margin = m_parent->m_itemMargin;
++ int width = m_parent->m_rect.width();
++ int height = m_parent->m_itemHeight;
++ int cw = checkPix.ImageSize().width();
++ int ch = checkPix.ImageSize().height();
++ int aw = arrowPix.ImageSize().width();
++ int ah = arrowPix.ImageSize().height();
++ int pw = m_pixmap ? m_pixmap->ImageSize().width() : 0;
++ int ph = m_pixmap ? m_pixmap->ImageSize().height() : 0;
++
+ if (m_checkable)
+- m_checkRect = QRect(margin, (height - ch)/2, cw, ch);
+- else
+- m_checkRect = QRect(0,0,0,0);
++ m_checkRect = QRect(margin, (height - ch)/2, cw, ch);
+
+ if (m_showArrow)
+- m_arrowRect = QRect(width - aw - margin, (height - ah)/2,
+- aw, ah);
+- else
+- m_arrowRect = QRect(0,0,0,0);
++ m_arrowRect = QRect(width - aw - margin, (height - ah)/2, aw, ah);
+
+- if (m_pixmap)
+- m_pixmapRect = QRect(m_checkable ? (2*margin + m_checkRect.width()) :
+- margin, (height - ph)/2,
+- pw, ph);
+- else
+- m_pixmapRect = QRect(0,0,0,0);
++ if (m_pixmap)
++ {
++ int tmp = (m_checkable) ? (2 * margin + m_checkRect.width()) : margin;
++ m_pixmapRect = QRect(tmp, (height - ph)/2, pw, ph);
++ }
+
+- m_textRect = QRect(margin +
+- (m_checkable ? m_checkRect.width() + margin : 0) +
+- (m_pixmap ? m_pixmapRect.width() + margin : 0),
+- 0,
+- width - 2*margin -
+- (m_checkable ? m_checkRect.width() + margin : 0) -
+- (m_showArrow ? m_arrowRect.width() + margin : 0) -
+- (m_pixmap ? m_pixmapRect.width() + margin : 0),
+- height);
++ int tx = margin, tw = width - (2 * margin);
++ tx += (m_checkable) ? m_checkRect.width() + margin : 0;
++ tx += (m_pixmap) ? m_pixmapRect.width() + margin : 0;
++ tw -= (m_checkable) ? m_checkRect.width() + margin : 0;
++ tw -= (m_showArrow) ? m_arrowRect.width() + margin : 0;
++ tw -= (m_pixmap) ? m_pixmapRect.width() + margin : 0;
++ m_textRect = QRect(tx, 0, tw, height);
+
+ m_parent->InsertItem(this);
+ }
+@@ -957,52 +736,10 @@
+ m_parent->RemoveItem(this);
+ }
+
+-QString OSDListBtnTypeItem::text() const
+-{
+- return m_text;
+-}
+-
+-const OSDTypeImage* OSDListBtnTypeItem::pixmap() const
+-{
+- return m_pixmap;
+-}
+-
+-bool OSDListBtnTypeItem::checkable() const
+-{
+- return m_checkable;
+-}
+-
+-OSDListBtnTypeItem::CheckState OSDListBtnTypeItem::state() const
+-{
+- return m_state;
+-}
+-
+-OSDListBtnType* OSDListBtnTypeItem::parent() const
+-{
+- return m_parent;
+-}
+-
+-void OSDListBtnTypeItem::setChecked(CheckState state)
+-{
+- if (!m_checkable)
+- return;
+- m_state = state;
+-}
+-
+-void OSDListBtnTypeItem::setData(void *data)
+-{
+- m_data = data;
+-}
+-
+-void* OSDListBtnTypeItem::getData()
+-{
+- return m_data;
+-}
+-
+ void OSDListBtnTypeItem::paint(OSDSurface *surface, TTFFont *font,
+ int fade, int maxfade, int x, int y)
+ {
+- if (this == m_parent->m_selItem)
++ if (this == m_parent->GetItemCurrent())
+ {
+ if (m_parent->m_active)
+ m_parent->m_itemSelActPix.Draw(surface, fade, maxfade, x, y);
+@@ -1030,11 +767,14 @@
+ cr.moveBy(x, y);
+
+ if (m_state == HalfChecked)
+- m_parent->m_checkHalfPix.Draw(surface, fade, maxfade, cr.x(), cr.y());
++ m_parent->m_checkHalfPix.Draw(surface, fade, maxfade,
++ cr.x(), cr.y());
+ else if (m_state == FullChecked)
+- m_parent->m_checkFullPix.Draw(surface, fade, maxfade, cr.x(), cr.y());
++ m_parent->m_checkFullPix.Draw(surface, fade, maxfade,
++ cr.x(), cr.y());
+ else
+- m_parent->m_checkNonePix.Draw(surface, fade, maxfade, cr.x(), cr.y());
++ m_parent->m_checkNonePix.Draw(surface, fade, maxfade,
++ cr.x(), cr.y());
+ }
+
+ if (m_pixmap)
+@@ -1049,39 +789,3 @@
+ tr.moveBy(0, font->Size() / 4);
+ font->DrawString(surface, tr.x(), tr.y(), m_text, tr.right(), tr.bottom());
+ }
+-
+-void OSDListBtnTypeItem::Reinit(float wchange, float hchange,
+- float wmult, float hmult)
+-{
+- (void)wmult;
+- (void)hmult;
+-
+- int width = (int)(m_checkRect.width() * wchange);
+- int height = (int)(m_checkRect.height() * hchange);
+- int x = (int)(m_checkRect.x() * wchange);
+- int y = (int)(m_checkRect.y() * hchange);
+-
+- m_checkRect = QRect(x, y, width, height);
+-
+- width = (int)(m_pixmapRect.width() * wchange);
+- height = (int)(m_pixmapRect.height() * hchange);
+- x = (int)(m_pixmapRect.x() * wchange);
+- y = (int)(m_pixmapRect.y() * hchange);
+-
+- m_pixmapRect = QRect(x, y, width, height);
+-
+- width = (int)(m_textRect.width() * wchange);
+- height = (int)(m_textRect.height() * hchange);
+- x = (int)(m_textRect.x() * wchange);
+- y = (int)(m_textRect.y() * hchange);
+-
+- m_textRect = QRect(x, y, width, height);
+-
+- width = (int)(m_arrowRect.width() * wchange);
+- height = (int)(m_arrowRect.height() * hchange);
+- x = (int)(m_arrowRect.x() * wchange);
+- y = (int)(m_arrowRect.y() * hchange);
+-
+- m_arrowRect = QRect(x, y, width, height);
+-}
+-
+Index: mythtv/libs/libmythtv/RingBuffer.cpp
+===================================================================
+--- mythtv/libs/libmythtv/RingBuffer.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/RingBuffer.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -145,6 +145,12 @@
+ VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %1)")
+ .arg(lfilename).arg(retryCount));
+
++ if ((filename.right(4).lower() == ".png") ||
++ (filename.right(4).lower() == ".gif"))
++ {
++ retryCount = 0;
++ }
++
+ uint openAttempts = retryCount + 1;
+
+ filename = lfilename;
+@@ -162,6 +168,7 @@
+
+ bool is_local = false;
+ bool is_dvd = false;
++
+ if ((filename.left(7) == "myth://") &&
+ (filename.length() > 7 ))
+ {
+@@ -271,6 +278,11 @@
+ remotefile = NULL;
+ }
+ }
++
++ setswitchtonext = false;
++ ateof = false;
++ commserror = false;
++ numfailures = 0;
+ }
+
+ /** \fn RingBuffer::IsOpen(void) const
+@@ -727,7 +739,7 @@
+ loops = 0;
+
+ pthread_rwlock_rdlock(&rwlock);
+- if (totfree > readblocksize && !commserror)
++ if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
+ {
+ // limit the read size
+ totfree = readblocksize;
+@@ -737,6 +749,9 @@
+
+ if (remotefile)
+ {
++ if (livetvchain && livetvchain->HasNext())
++ remotefile->SetTimeout(true);
++
+ ret = safe_read(remotefile, readAheadBuffer + rbwpos,
+ totfree);
+ internalreadpos += ret;
+@@ -785,8 +800,16 @@
+ totfree = 0;
+ }
+
+- if (!readsallowed && used >= fill_min)
++ if (!readsallowed && (used >= fill_min || setswitchtonext))
++ {
+ readsallowed = true;
++ VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used)
++ .arg(fill_min));
++ }
++ else if (!readsallowed)
++ VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used)
++ .arg(fill_min)
++ .arg(ret));
+
+ if (readsallowed && used < fill_min && !ateof && !setswitchtonext)
+ {
+@@ -808,8 +831,11 @@
+
+ pthread_rwlock_unlock(&rwlock);
+
+- if ((used >= fill_threshold || wantseek) && !pausereadthread)
++ if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
++ !pausereadthread)
++ {
+ usleep(500);
++ }
+ }
+
+ delete [] readAheadBuffer;
+@@ -853,15 +879,15 @@
+ VERBOSE(VB_IMPORTANT,
+ LOC + "Taking too long to be allowed to read..");
+ readErr++;
+-
++
+ // HACK Sometimes the readhead thread gets borked on startup.
+- /* if ((readErr % 2) && (rbrpos ==0))
++ if ((readErr > 2 && readErr % 2) && (rbrpos ==0))
+ {
+ VERBOSE(VB_IMPORTANT, "restarting readhead thread..");
+ KillReadAheadThread();
+ StartupReadAheadThread();
+ }
+- */
++
+ if (readErr > 10)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
+@@ -895,6 +921,12 @@
+ VERBOSE(VB_IMPORTANT, LOC + "Waited " +
+ QString("%1").arg(elapsed/1000) +
+ " seconds for data to become available...");
++ if (livetvchain)
++ {
++ VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
++ "new livetv program to switch to..");
++ livetvchain->ReloadAll();
++ }
+ }
+
+ bool quit = livetvchain && (livetvchain->NeedsToSwitch() ||
+@@ -923,7 +955,7 @@
+ availWaitMutex.unlock();
+
+ avail = ReadBufAvail();
+- if (ateof && avail < count)
++ if ((ateof || setswitchtonext) && avail < count)
+ count = avail;
+
+ if (commserror)
+Index: mythtv/libs/libmythtv/hdtvrecorder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/hdtvrecorder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/hdtvrecorder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -627,9 +627,8 @@
+
+ len += remainder;
+ remainder = ProcessData(_buffer, len);
+- if (remainder > 0) // leftover bytes
+- memmove(_buffer, &(_buffer[_buffer_size - remainder]),
+- remainder);
++ if (remainder > 0 && (len > remainder)) // leftover bytes
++ memmove(_buffer, &(_buffer[len - remainder]), remainder);
+ }
+
+ FinishRecording();
+Index: mythtv/libs/libmythtv/dummydtvrecorder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/dummydtvrecorder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/dummydtvrecorder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -125,7 +125,8 @@
+ // TRANSFER DATA
+ while (_request_recording || _frames_seen_count <= 5)
+ {
+- len = read(_stream_fd, &(_buffer[remainder]), _buffer_size - remainder);
++ len = read(_stream_fd, &(_buffer[remainder]),
++ _buffer_size - remainder);
+
+ if (len == 0)
+ {
+@@ -137,9 +138,8 @@
+
+ len += remainder;
+ remainder = ProcessData(_buffer, len);
+- if (remainder > 0) // leftover bytes
+- memmove(_buffer, &(_buffer[_buffer_size - remainder]),
+- remainder);
++ if (remainder > 0 && (len > remainder)) // leftover bytes
++ memmove(_buffer, &(_buffer[len - remainder]), remainder);
+ }
+
+ FinishRecording();
+Index: mythtv/libs/libmythtv/avformatdecoder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/avformatdecoder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/avformatdecoder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -725,7 +725,12 @@
+ return -1;
+ }
+
++ /* av_find_stream_info() eventually makes calls to avcodec_open() and avcodec_close()
++ so we have to use the avcodeclock */
++ avcodeclock.lock();
+ int ret = av_find_stream_info(ic);
++ avcodeclock.unlock();
++
+ if (ret < 0)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not find codec parameters. " +
+Index: mythtv/libs/libmythtv/osdtypes.cpp
+===================================================================
+--- mythtv/libs/libmythtv/osdtypes.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/osdtypes.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -14,6 +14,9 @@
+
+ #include "mythcontext.h"
+
++/// Shared OSD image cache
++OSDImageCache OSDTypeImage::c_cache;
++
+ OSDSet::OSDSet(const QString &name, bool cache, int screenwidth,
+ int screenheight, float wmult, float hmult, int frint)
+ : QObject()
+@@ -160,9 +163,6 @@
+ int displaywidth, int displayheight,
+ float wmult, float hmult, int frint)
+ {
+- float wchange = wmult / m_wmult;
+- float hchange = hmult / m_hmult;
+-
+ m_frameint = frint;
+
+ m_screenwidth = screenwidth;
+@@ -175,57 +175,12 @@
+ vector<OSDType *>::iterator iter = allTypes->begin();
+ for (;iter != allTypes->end(); iter++)
+ {
+- OSDType *type = (*iter);
+- if (OSDTypeText *item = dynamic_cast<OSDTypeText*>(type))
+- {
+- item->Reinit(wchange, hchange);
+- }
+- else if (OSDTypePositionImage *item =
+- dynamic_cast<OSDTypePositionImage*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+- else if (OSDTypePosSlider *item = dynamic_cast<OSDTypePosSlider*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+- else if (OSDTypeFillSlider *item =
+- dynamic_cast<OSDTypeFillSlider*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+- else if (OSDTypeEditSlider *item =
+- dynamic_cast<OSDTypeEditSlider*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+- else if (OSDTypeImage *item = dynamic_cast<OSDTypeImage*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
+- else if (OSDTypeBox *item = dynamic_cast<OSDTypeBox*>(type))
+- {
+- item->Reinit(wchange, hchange);
+- }
+- else if (OSDTypePositionRectangle *item =
+- dynamic_cast<OSDTypePositionRectangle*>(type))
+- {
+- item->Reinit(wchange, hchange);
+- }
+- else if (OSDTypeCC *item = dynamic_cast<OSDTypeCC*>(type))
+- {
+- item->Reinit(xoff, yoff, displaywidth, displayheight);
+- }
+- else if (OSDListTreeType *item = dynamic_cast<OSDListTreeType*>(type))
+- {
+- item->Reinit(wchange, hchange, wmult, hmult);
+- }
++ if (OSDTypeCC *cc608 = dynamic_cast<OSDTypeCC*>(*iter))
++ cc608->Reinit(xoff, yoff, displaywidth, displayheight,
++ wmult, hmult);
+ else
+- {
+- cerr << "Unknown conversion\n";
+- }
++ (*iter)->Reinit(wmult, hmult);
+ }
+-
+ }
+
+ OSDType *OSDSet::GetType(const QString &name)
+@@ -443,7 +398,8 @@
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ OSDTypeText::OSDTypeText(const QString &name, TTFFont *font,
+- const QString &text, QRect displayrect)
++ const QString &text, QRect displayrect,
++ float wmult, float hmult)
+ : OSDType(name)
+ {
+ m_message = text;
+@@ -464,6 +420,12 @@
+ m_scrollinit = false;
+
+ m_linespacing = 1.5;
++
++ m_unbiasedsize =
++ QRect((int)round(m_screensize.x() / wmult),
++ (int)round(m_screensize.y() / hmult),
++ (int)ceil( m_screensize.width() / wmult),
++ (int)ceil( m_screensize.height() / hmult));
+ }
+
+ OSDTypeText::OSDTypeText(const OSDTypeText &other)
+@@ -507,14 +469,13 @@
+ m_scrollinit = false;
+ }
+
+-void OSDTypeText::Reinit(float wchange, float hchange)
++void OSDTypeText::Reinit(float wmult, float hmult)
+ {
+- int width = (int)(m_screensize.width() * wchange);
+- int height = (int)(m_screensize.height() * hchange);
+- int x = (int)(m_screensize.x() * wchange);
+- int y = (int)(m_screensize.y() * hchange);
+-
+- m_displaysize = m_screensize = QRect(x, y, width, height);
++ m_displaysize = m_screensize =
++ QRect((int)round(m_unbiasedsize.x() * wmult),
++ (int)round(m_unbiasedsize.y() * hmult),
++ (int)ceil( m_unbiasedsize.width() * wmult),
++ (int)ceil( m_unbiasedsize.height() * hmult));
+ }
+
+ void OSDTypeText::Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
+@@ -708,7 +669,7 @@
+ m_onlyusefirst = false;
+
+ m_filename = filename;
+- m_displaypos = displaypos;
++ SetPosition(displaypos, wmult, hmult);
+
+ m_yuv = m_alpha = NULL;
+ m_isvalid = false;
+@@ -716,6 +677,7 @@
+
+ m_scalew = scalew;
+ m_scaleh = scaleh;
++ m_cacheitem = NULL;
+
+ LoadImage(filename, wmult, hmult, scalew, scaleh);
+ }
+@@ -733,6 +695,7 @@
+ m_name = other.m_name;
+ m_scalew = other.m_scalew;
+ m_scaleh = other.m_scaleh;
++ m_cacheitem = NULL;
+
+ m_alpha = m_yuv = NULL;
+ if (m_isvalid)
+@@ -760,6 +723,8 @@
+ m_onlyusefirst = false;
+
+ m_displaypos = QPoint(0, 0);
++ m_unbiasedpos = QPoint(0, 0);
++ m_cacheitem = NULL;
+
+ m_yuv = NULL;
+ m_alpha = NULL;
+@@ -778,6 +743,8 @@
+ m_onlyusefirst = false;
+
+ m_displaypos = QPoint(0, 0);
++ m_unbiasedpos = QPoint(0, 0);
++ m_cacheitem = NULL;
+
+ m_yuv = NULL;
+ m_alpha = NULL;
+@@ -790,10 +757,14 @@
+
+ OSDTypeImage::~OSDTypeImage()
+ {
+- if (m_yuv)
+- delete [] m_yuv;
+- if (m_alpha)
+- delete [] m_alpha;
++ // In case we have a cache item in hand, it's safe to delete it,
++ // as it should not be in OSDImageCache anymore and it should have
++ // been written to the file cache for faster access in the future.
++ if (m_cacheitem)
++ {
++ delete m_cacheitem;
++ m_cacheitem = NULL;
++ }
+ }
+
+ void OSDTypeImage::SetName(const QString &name)
+@@ -801,13 +772,19 @@
+ m_name = name;
+ }
+
+-void OSDTypeImage::Reinit(float wchange, float hchange, float wmult, float hmult)
++void OSDTypeImage::SetPosition(QPoint pos, float wmult, float hmult)
+ {
+- int x = (int)(m_displaypos.x() * wchange);
+- int y = (int)(m_displaypos.y() * hchange);
++ m_displaypos = pos;
++ m_unbiasedpos =
++ QPoint((int)round(pos.x() / wmult),
++ (int)round(pos.y() / hmult));
++}
+
+- m_displaypos.setX(x);
+- m_displaypos.setY(y);
++void OSDTypeImage::Reinit(float wmult, float hmult)
++{
++ m_displaypos =
++ QPoint((int)round(m_unbiasedpos.x() * wmult),
++ (int)round(m_unbiasedpos.y() * hmult));
+
+ LoadImage(m_filename, wmult, hmult, m_scalew, m_scaleh);
+ }
+@@ -815,20 +792,44 @@
+ void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult,
+ int scalew, int scaleh)
+ {
+- if (m_isvalid)
++ QString ckey;
++
++ if (!filename.isEmpty() && filename.length() >= 2)
+ {
+- if (m_yuv)
+- delete [] m_yuv;
+- if (m_alpha)
+- delete [] m_alpha;
+-
+- m_isvalid = false;
+- m_yuv = NULL;
+- m_alpha = NULL;
++ ckey = OSDImageCache::CreateKey(
++ filename, wmult, hmult, scalew, scaleh);
+ }
++ else
++ {
++ // this method requires a backing file
++ return;
++ }
++
++ // Get the item from the cache so it's not freed while in use
++ OSDImageCacheValue* value = c_cache.Get(ckey, true);
++
++ if (value != NULL)
++ {
++ m_yuv = value->m_yuv;
++ m_ybuffer = value->m_ybuffer;
++ m_ubuffer = value->m_ubuffer;
++ m_vbuffer = value->m_vbuffer;
++ m_alpha = value->m_alpha;
++ m_imagesize = value->m_imagesize;
++ m_isvalid = true;
+
+- if (filename.length() < 2)
++ // Put the old image back to the cache so it can be reused in the
++ // future, and possibly freed by the cache system if the size limit
++ // is reached
++ if (!m_cacheitem)
++ c_cache.Insert(m_cacheitem);
++ m_cacheitem = value;
++
+ return;
++ }
++
++ // scaled image was not found in cache, have to create it
++
+
+ QImage tmpimage(filename);
+
+@@ -867,17 +868,32 @@
+ imwidth, imheight, tmp2.width());
+
+ m_imagesize = QRect(0, 0, imwidth, imheight);
++
++ // put the old image back to the cache so it can be reused in the
++ // future, and possibly freed by the cache system if the size limit
++ // is reached
++ if (m_cacheitem)
++ c_cache.Insert(m_cacheitem);
++
++ m_cacheitem = new OSDImageCacheValue(
++ ckey,
++ m_yuv, m_ybuffer, m_ubuffer,
++ m_vbuffer, m_alpha, m_imagesize);
++
++ // save the new cache item to the file cache
++ if (!filename.isEmpty())
++ c_cache.SaveToDisk(m_cacheitem);
+ }
+
+ void OSDTypeImage::LoadFromQImage(const QImage &img)
+ {
++ // this method is not cached as it's used mostly for
++ // subtitles which are displayed only once anyways, caching
++ // would probably only slow things down overall
+ if (m_isvalid)
+ {
+- if (m_yuv)
+- delete [] m_yuv;
+- if (m_alpha)
+- delete [] m_alpha;
+-
++ delete m_cacheitem;
++ m_cacheitem = NULL;
+ m_isvalid = false;
+ m_yuv = NULL;
+ m_alpha = NULL;
+@@ -1043,23 +1059,25 @@
+ m_maxval = 1000;
+ m_curval = 0;
+ m_displayrect = displayrect;
++ m_unbiasedrect =
++ QRect((int)round(m_displayrect.x() / wmult),
++ (int)round(m_displayrect.y() / hmult),
++ (int)ceil( m_displayrect.width() / wmult),
++ (int)ceil( m_displayrect.height() / hmult));
+ }
+
+ OSDTypePosSlider::~OSDTypePosSlider()
+ {
+ }
+
+-void OSDTypePosSlider::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
++void OSDTypePosSlider::Reinit(float wmult, float hmult)
+ {
+- int width = (int)(m_displayrect.width() * wchange);
+- int height = (int)(m_displayrect.height() * hchange);
+- int x = (int)(m_displayrect.x() * wchange);
+- int y = (int)(m_displayrect.y() * hchange);
+-
+- m_displayrect = QRect(x, y, width, height);
+-
+- OSDTypeImage::Reinit(wchange, hchange, wmult, hmult);
++ m_displayrect =
++ QRect((int)round(m_unbiasedrect.x() * wmult),
++ (int)round(m_unbiasedrect.y() * hmult),
++ (int)ceil( m_unbiasedrect.width() * wmult),
++ (int)ceil( m_unbiasedrect.height() * hmult));
++ OSDTypeImage::Reinit(wmult, hmult);
+ }
+
+ void OSDTypePosSlider::SetPosition(int pos)
+@@ -1092,23 +1110,25 @@
+ m_drawwidth = 0;
+ m_onlyusefirst = true;
+ m_displayrect = displayrect;
++ m_unbiasedrect =
++ QRect((int)round(m_displayrect.x() / wmult),
++ (int)round(m_displayrect.y() / hmult),
++ (int)ceil( m_displayrect.width() / wmult),
++ (int)ceil( m_displayrect.height() / hmult));
+ }
+
+ OSDTypeFillSlider::~OSDTypeFillSlider()
+ {
+ }
+
+-void OSDTypeFillSlider::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
++void OSDTypeFillSlider::Reinit(float wmult, float hmult)
+ {
+- int width = (int)(m_displayrect.width() * wchange);
+- int height = (int)(m_displayrect.height() * hchange);
+- int x = (int)(m_displayrect.x() * wchange);
+- int y = (int)(m_displayrect.y() * hchange);
+-
+- m_displayrect = QRect(x, y, width, height);
+-
+- OSDTypeImage::Reinit(wchange, hchange, wmult, hmult);
++ m_displayrect =
++ QRect((int)round(m_unbiasedrect.x() * wmult),
++ (int)round(m_unbiasedrect.y() * hmult),
++ (int)ceil( m_unbiasedrect.width() * wmult),
++ (int)ceil( m_unbiasedrect.height() * hmult));
++ OSDTypeImage::Reinit(wmult, hmult);
+ }
+
+ void OSDTypeFillSlider::SetPosition(int pos)
+@@ -1143,6 +1163,11 @@
+ m_maxval = 1000;
+ m_curval = 0;
+ m_displayrect = displayrect;
++ m_unbiasedrect =
++ QRect((int)round(m_displayrect.x() / wmult),
++ (int)round(m_displayrect.y() / hmult),
++ (int)ceil( m_displayrect.width() / wmult),
++ (int)ceil( m_displayrect.height() / hmult));
+ m_drawwidth = displayrect.width();
+
+ m_drawMap = new unsigned char[m_drawwidth + 1];
+@@ -1162,6 +1187,7 @@
+
+ m_scalew = scalew;
+ m_scaleh = scaleh;
++ m_cacheitem = NULL;
+
+ LoadImage(m_redname, wmult, hmult, scalew, scaleh);
+ if (m_isvalid)
+@@ -1184,22 +1210,16 @@
+ OSDTypeEditSlider::~OSDTypeEditSlider()
+ {
+ delete [] m_drawMap;
+-
+- if (m_ryuv)
+- delete [] m_ryuv;
+- if (m_ralpha)
+- delete [] m_ralpha;
+ }
+
+-void OSDTypeEditSlider::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
++void OSDTypeEditSlider::Reinit(float wmult, float hmult)
+ {
+- int width = (int)(m_displayrect.width() * wchange);
+- int height = (int)(m_displayrect.height() * hchange);
+- int x = (int)(m_displayrect.x() * wchange);
+- int y = (int)(m_displayrect.y() * hchange);
++ m_displayrect =
++ QRect((int)round(m_unbiasedrect.x() * wmult),
++ (int)round(m_unbiasedrect.y() * hmult),
++ (int)ceil( m_unbiasedrect.width() * wmult),
++ (int)ceil( m_unbiasedrect.height() * hmult));
+
+- m_displayrect = QRect(x, y, width, height);
+ m_drawwidth = m_displayrect.width();
+
+ delete [] m_drawMap;
+@@ -1210,11 +1230,6 @@
+
+ m_displaypos = m_displayrect.topLeft();
+
+- if (m_ryuv)
+- delete [] m_ryuv;
+- if (m_ralpha)
+- delete [] m_ralpha;
+-
+ LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh);
+ if (m_isvalid)
+ {
+@@ -1360,30 +1375,46 @@
+
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-OSDTypeBox::OSDTypeBox(const QString &name, QRect displayrect)
+- : OSDType(name)
++OSDTypeBox::OSDTypeBox(const QString &name, QRect displayrect,
++ float wmult, float hmult)
++ : OSDType(name)
+ {
+ size = displayrect;
++ m_unbiasedsize =
++ QRect((int)round(size.x() / wmult),
++ (int)round(size.y() / hmult),
++ (int)ceil( size.width() / wmult),
++ (int)ceil( size.height() / hmult));
+ }
+
++void OSDTypeBox::SetRect(QRect newrect, float wmult, float hmult)
++{
++ size = newrect;
++ m_unbiasedsize =
++ QRect((int)round(size.x() / wmult),
++ (int)round(size.y() / hmult),
++ (int)ceil( size.width() / wmult),
++ (int)ceil( size.height() / hmult));
++}
++
+ OSDTypeBox::OSDTypeBox(const OSDTypeBox &other)
+ : OSDType(other.m_name)
+ {
+ size = other.size;
++ m_unbiasedsize = other.m_unbiasedsize;
+ }
+
+ OSDTypeBox::~OSDTypeBox()
+ {
+ }
+
+-void OSDTypeBox::Reinit(float wchange, float hchange)
++void OSDTypeBox::Reinit(float wmult, float hmult)
+ {
+- int width = (int)(size.width() * wchange);
+- int height = (int)(size.height() * hchange);
+- int x = (int)(size.x() * wchange);
+- int y = (int)(size.y() * hchange);
+-
+- size = QRect(x, y, width, height);
++ size =
++ QRect((int)round(m_unbiasedsize.x() * wmult),
++ (int)round(m_unbiasedsize.y() * hmult),
++ (int)ceil( m_unbiasedsize.width() * wmult),
++ (int)ceil( m_unbiasedsize.height() * hmult));
+ }
+
+ void OSDTypeBox::Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
+@@ -1498,44 +1529,52 @@
+ }
+
+ OSDTypePositionRectangle::OSDTypePositionRectangle(
+- const OSDTypePositionRectangle &other)
+- : OSDType(other.m_name), OSDTypePositionIndicator(other)
++ const OSDTypePositionRectangle &other)
++ : OSDType(other.m_name), OSDTypePositionIndicator(other)
+ {
+ for (int i = 0; i < m_numpositions; i++)
+ {
+ QRect tmp = other.positions[i];
+ positions.push_back(tmp);
+ }
++ for (int i = 0; i < m_numpositions; i++)
++ {
++ QRect tmp = other.unbiasedpos[i];
++ unbiasedpos.push_back(tmp);
++ }
+ }
+
+ OSDTypePositionRectangle::~OSDTypePositionRectangle()
+ {
+ }
+
+-void OSDTypePositionRectangle::Reinit(float wchange, float hchange)
++void OSDTypePositionRectangle::Reinit(float wmult, float hmult)
+ {
+ for (int i = 0; i < m_numpositions; i++)
+ {
+- QRect tmp = positions[i];
+-
+- int width = (int)(tmp.width() * wchange);
+- int height = (int)(tmp.height() * hchange);
+- int x = (int)(tmp.x() * wchange);
+- int y = (int)(tmp.y() * hchange);
+-
+- tmp = QRect(x, y, width, height);
+- positions[i] = tmp;
++ QRect tmp = unbiasedpos[i];
++ positions[i] =
++ QRect((int)round(tmp.x() * wmult),
++ (int)round(tmp.y() * hmult),
++ (int)ceil( tmp.width() * wmult),
++ (int)ceil( tmp.height() * hmult));
+ }
+ }
+
+-void OSDTypePositionRectangle::AddPosition(QRect rect)
++void OSDTypePositionRectangle::AddPosition(
++ QRect rect, float wmult, float hmult)
+ {
+ positions.push_back(rect);
++ unbiasedpos.push_back(
++ QRect((int)round(rect.x() / wmult),
++ (int)round(rect.y() / hmult),
++ (int)ceil( rect.width() / wmult),
++ (int)ceil( rect.height() / hmult)));
+ m_numpositions++;
+ }
+
+-void OSDTypePositionRectangle::Draw(OSDSurface *surface, int fade, int maxfade,
+- int xoff, int yoff)
++void OSDTypePositionRectangle::Draw(
++ OSDSurface *surface, int fade, int maxfade, int xoff, int yoff)
+ {
+ fade = fade;
+ maxfade = maxfade;
+@@ -1618,17 +1657,21 @@
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ OSDTypePositionImage::OSDTypePositionImage(const QString &name)
+- : OSDTypeImage(name), OSDTypePositionIndicator()
++ : OSDTypeImage(name), OSDTypePositionIndicator(),
++ m_wmult(0.0f), m_hmult(0.0f)
+ {
+ }
+
+ OSDTypePositionImage::OSDTypePositionImage(const OSDTypePositionImage &other)
+ : OSDTypeImage(other), OSDTypePositionIndicator(other)
+ {
++ m_wmult = other.m_wmult;
++ m_hmult = other.m_hmult;
++
+ for (int i = 0; i < m_numpositions; i++)
+ {
+- QPoint tmp = other.positions[i];
+- positions.push_back(tmp);
++ positions.push_back(other.positions[i]);
++ unbiasedpos.push_back(other.unbiasedpos[i]);
+ }
+ }
+
+@@ -1636,45 +1679,61 @@
+ {
+ }
+
+-void OSDTypePositionImage::Reinit(float wchange, float hchange, float wmult,
+- float hmult)
++void OSDTypePositionImage::Reinit(float wmult, float hmult)
+ {
+- OSDTypeImage::Reinit(wchange, hchange, wmult, hmult);
++ m_wmult = wmult;
++ m_hmult = hmult;
++
++ OSDTypeImage::Reinit(wmult, hmult);
+
+ for (int i = 0; i < m_numpositions; i++)
+ {
+- QPoint tmp = positions[i];
+-
+- int x = (int)(tmp.x() * wchange);
+- int y = (int)(tmp.y() * hchange);
+-
+- positions[i].setX(x);
+- positions[i].setY(y);
++ positions[i] =
++ QPoint((int)round(unbiasedpos[i].x() * wmult),
++ (int)round(unbiasedpos[i].y() * hmult));
+ }
+ }
+
+-void OSDTypePositionImage::AddPosition(QPoint pos)
++void OSDTypePositionImage::AddPosition(QPoint pos, float wmult, float hmult)
+ {
++ if (m_wmult == 0.0f || m_hmult == 0.0f)
++ {
++ m_wmult = wmult;
++ m_hmult = hmult;
++ }
+ positions.push_back(pos);
++ unbiasedpos.push_back(
++ QPoint((int)round(pos.x() / wmult),
++ (int)round(pos.y() / hmult)));
++
++ VERBOSE(VB_IMPORTANT,
++ "OSDTypePositionImage::AddPosition["<<m_numpositions<<"]("
++ <<pos.x()<<"x"<<pos.y()
++ <<" "<<wmult<<", "<<hmult<<")");
++
+ m_numpositions++;
+ }
+
+ void OSDTypePositionImage::Draw(OSDSurface *surface, int fade, int maxfade,
+ int xoff, int yoff)
+ {
++ VERBOSE(VB_IMPORTANT,
++ "OSDTypePositionImage::Draw["<<m_curposition<<"]("
++ <<m_wmult<<", "<<m_hmult<<")");
++
+ if (m_curposition < 0 || m_curposition >= m_numpositions)
+ return;
+
+ QPoint pos = positions[m_curposition];
+
+- OSDTypeImage::SetPosition(pos);
++ OSDTypeImage::SetPosition(pos, m_wmult, m_hmult);
+ OSDTypeImage::Draw(surface, fade, maxfade, xoff, yoff);
+ }
+
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ OSDTypeCC::OSDTypeCC(const QString &name, TTFFont *font, int xoff, int yoff,
+- int dispw, int disph)
++ int dispw, int disph, float wmult, float hmult)
+ : OSDType(name)
+ {
+ m_font = font;
+@@ -1683,9 +1742,11 @@
+ yoffset = yoff;
+ displaywidth = dispw;
+ displayheight = disph;
++ m_wmult = wmult;
++ m_hmult = hmult;
+
+ QRect rect = QRect(0, 0, 0, 0);
+- m_box = new OSDTypeBox("cc_background", rect);
++ m_box = new OSDTypeBox("cc_background", rect, wmult, hmult);
+ m_ccbackground = gContext->GetNumSetting("CCBackground", 0);
+ }
+
+@@ -1695,12 +1756,23 @@
+ delete m_box;
+ }
+
+-void OSDTypeCC::Reinit(int x, int y, int dispw, int disph)
++void OSDTypeCC::Reinit(float wmult, float hmult)
+ {
++ (void) wmult;
++ (void) hmult;
++ VERBOSE(VB_IMPORTANT, "Programmer error: "
++ "Call to OSDTypeCC::Reinit(float,float)");
++}
++
++void OSDTypeCC::Reinit(int x, int y, int dispw, int disph,
++ float wmult, float hmult)
++{
+ xoffset = x;
+ yoffset = y;
+ displaywidth = dispw;
+ displayheight = disph;
++ m_wmult = wmult;
++ m_hmult = hmult;
+ }
+
+ void OSDTypeCC::AddCCText(const QString &text, int x, int y, int color,
+@@ -1875,7 +1947,7 @@
+ {
+ QRect rect = QRect(0, 0, textlength + 4,
+ (m_font->Size() * 3 / 2) + 3);
+- m_box->SetRect(rect);
++ m_box->SetRect(rect, m_wmult, m_hmult);
+ m_box->Draw(surface, 0, 0, x - 2, y - 2);
+ }
+
+Index: mythtv/libs/libmythtv/tv_play.cpp
+===================================================================
+--- mythtv/libs/libmythtv/tv_play.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/tv_play.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -247,7 +247,7 @@
+ browsechannum(""), browsechanid(""), browsestarttime(""),
+ // Program Info for currently playing video
+ recorderPlaybackInfo(NULL),
+- playbackinfo(NULL), inputFilename(""), playbackLen(0),
++ playbackinfo(NULL), playbackLen(0),
+ lastProgram(NULL), jumpToProgram(false),
+ // Video Players
+ nvp(NULL), pipnvp(NULL), activenvp(NULL),
+@@ -578,19 +578,7 @@
+ if (!testrec->IsValidRecorder())
+ {
+ if (showDialogs)
+- {
+- QString title = tr("MythTV is already using all available "
+- "inputs for recording. If you want to "
+- "watch an in-progress recording, select one "
+- "from the playback menu. If you want to "
+- "watch live TV, cancel one of the "
+- "in-progress recordings from the delete "
+- "menu.");
+-
+- DialogBox diag(gContext->GetMainWindow(), title);
+- diag.AddButton(tr("Cancel and go back to the TV menu"));
+- diag.exec();
+- }
++ ShowNoRecorderDialog();
+
+ delete testrec;
+
+@@ -659,8 +647,6 @@
+ if (internalState != kState_None)
+ return 0;
+
+- inputFilename = rcinfo->pathname;
+-
+ playbackLen = rcinfo->CalculateLength();
+ playbackinfo = new ProgramInfo(*rcinfo);
+
+@@ -844,9 +830,10 @@
+ }
+ else
+ {
++ QString playbackURL = playbackinfo->GetPlaybackURL();
++
+ tvchain->SetProgram(playbackinfo);
+-
+- prbuffer = new RingBuffer(playbackinfo->pathname, false);
++ prbuffer = new RingBuffer(playbackURL, false);
+ prbuffer->SetLiveMode(tvchain);
+ }
+
+@@ -895,7 +882,14 @@
+ else if (TRANSITION(kState_None, kState_WatchingPreRecorded) ||
+ TRANSITION(kState_None, kState_WatchingRecording))
+ {
+- prbuffer = new RingBuffer(inputFilename, false);
++ QString playbackURL;
++ if ((playbackinfo->pathname.left(4) == "dvd:") ||
++ (playbackinfo->isVideo))
++ playbackURL = playbackinfo->pathname;
++ else
++ playbackURL = playbackinfo->GetPlaybackURL();
++
++ prbuffer = new RingBuffer(playbackURL, false);
+ if (prbuffer->IsOpen())
+ {
+ gContext->DisableScreensaver();
+@@ -924,7 +918,7 @@
+ {
+ QString message = "COMMFLAG_REQUEST ";
+ message += playbackinfo->chanid + " " +
+- playbackinfo->startts.toString(Qt::ISODate);
++ playbackinfo->recstartts.toString(Qt::ISODate);
+ RemoteSendMessage(message);
+ }
+ }
+@@ -1222,10 +1216,10 @@
+ nvp->SetParentPlayer(this);
+ nvp->SetRingBuffer(prbuffer);
+ nvp->SetRecorder(recorder);
+- nvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate"));
++ nvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate", 44100));
+ nvp->SetAudioDevice(gContext->GetSetting("AudioOutputDevice"));
+ nvp->SetLength(playbackLen);
+- nvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking"));
++ nvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking", 0));
+ nvp->SetAutoCommercialSkip(autoCommercialSkip);
+ nvp->SetLiveTVChain(tvchain);
+
+@@ -1296,9 +1290,9 @@
+ pipnvp->SetAsPIP();
+ pipnvp->SetRingBuffer(piprbuffer);
+ pipnvp->SetRecorder(piprecorder);
+- pipnvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate"));
++ pipnvp->SetAudioSampleRate(gContext->GetNumSetting("AudioSampleRate", 44100));
+ pipnvp->SetAudioDevice(gContext->GetSetting("AudioOutputDevice"));
+- pipnvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking"));
++ pipnvp->SetExactSeeks(gContext->GetNumSetting("ExactSeeking", 0));
+ pipnvp->SetLiveTVChain(piptvchain);
+
+ pipnvp->SetLength(playbackLen);
+@@ -1454,6 +1448,30 @@
+ lastSignalMsg.clear();
+ }
+ UpdateOSDTimeoutMessage();
++
++ if (!tvchainUpdate.isEmpty())
++ {
++ tvchainUpdateLock.lock();
++ for (QStringList::Iterator it = tvchainUpdate.begin();
++ it != tvchainUpdate.end(); ++it)
++ {
++ if (tvchain && nvp && *it == tvchain->GetID())
++ {
++ tvchain->ReloadAll();
++ if (nvp->GetTVChain())
++ nvp->CheckTVChain();
++ }
++ if (piptvchain && pipnvp && *it == piptvchain->GetID())
++ {
++ piptvchain->ReloadAll();
++ if (pipnvp->GetTVChain())
++ pipnvp->CheckTVChain();
++ }
++ }
++ tvchainUpdate.clear();
++ tvchainUpdateLock.unlock();
++ }
++
+ osdlock.unlock();
+ }
+
+@@ -2743,7 +2761,7 @@
+ speedStr = QString("%1X").arg(normal_speed);
+
+ struct StatusPosInfo posInfo;
+- nvp->calcSliderPos(posInfo);
++ nvp->calcSliderPos(posInfo, true);
+
+ QDateTime respDate = mythCurrentDateTime();
+ QString infoStr = "";
+@@ -2806,8 +2824,10 @@
+ }
+ else
+ {
++ QString playbackURL = playbackinfo->GetPlaybackURL();
++
+ piptvchain->SetProgram(playbackinfo);
+- piprbuffer = new RingBuffer(playbackinfo->pathname, false);
++ piprbuffer = new RingBuffer(playbackURL, false);
+ piprbuffer->SetLiveMode(piptvchain);
+ }
+
+@@ -3472,8 +3492,10 @@
+ }
+ else
+ {
++ QString playbackURL = playbackinfo->GetPlaybackURL();
++
+ tvchain->SetProgram(playbackinfo);
+- prbuffer = new RingBuffer(playbackinfo->pathname, false);
++ prbuffer = new RingBuffer(playbackURL, false);
+ prbuffer->SetLiveMode(tvchain);
+ }
+
+@@ -4627,7 +4649,8 @@
+
+ normal_speed = new_normal_speed;
+
+- activenvp->Play(normal_speed, true);
++ if (!paused)
++ activenvp->Play(normal_speed, true);
+
+ QString text = QString(tr("Time Stretch %1X")).arg(normal_speed);
+
+@@ -4911,29 +4934,14 @@
+ }
+ else if (tvchain && message.left(12) == "LIVETV_CHAIN")
+ {
+- // Get osdlock, while intended for the OSD this ensures that
+- // the nvp & pipnvp are not deleted while we are using it..
+- while (!osdlock.tryLock() && nvp)
+- usleep(2500);
+-
+ message = message.simplifyWhiteSpace();
+ QStringList tokens = QStringList::split(" ", message);
+ if (tokens[1] == "UPDATE")
+ {
+- if (tvchain && nvp && tokens[2] == tvchain->GetID())
+- {
+- tvchain->ReloadAll();
+- if (nvp->GetTVChain())
+- nvp->CheckTVChain();
+- }
+- if (piptvchain && pipnvp && tokens[2] == piptvchain->GetID())
+- {
+- piptvchain->ReloadAll();
+- if (pipnvp->GetTVChain())
+- pipnvp->CheckTVChain();
+- }
++ tvchainUpdateLock.lock();
++ tvchainUpdate += QDeepCopy<QString>(tokens[2]);
++ tvchainUpdateLock.unlock();
+ }
+- osdlock.unlock();
+ }
+ else if (nvp && message.left(12) == "EXIT_TO_MENU")
+ {
+@@ -4983,7 +4991,7 @@
+ QDateTime evstartts = QDateTime::fromString(tokens[2], Qt::ISODate);
+
+ if ((playbackinfo->chanid == evchanid) &&
+- (playbackinfo->startts == evstartts))
++ (playbackinfo->recstartts == evstartts))
+ {
+ QString msg = "COMMFLAG_REQUEST ";
+ msg += tokens[1] + " " + tokens[2];
+@@ -5000,7 +5008,7 @@
+ QDateTime evstartts = QDateTime::fromString(tokens[2], Qt::ISODate);
+
+ if ((playbackinfo->chanid == evchanid) &&
+- (playbackinfo->startts == evstartts))
++ (playbackinfo->recstartts == evstartts))
+ {
+ QMap<long long, int> newMap;
+ QStringList mark;
+@@ -6067,9 +6075,22 @@
+ "in-progress recordings from the delete "
+ "menu.");
+
+- MythPopupBox::showOkPopup(
++ if (embedWinID)
++ {
++ VERBOSE(VB_IMPORTANT, errorText);
++ }
++ else if (GetOSD())
++ {
++ dialogname = "infobox";
++ QStringList options("OK");
++ GetOSD()->NewDialogBox(dialogname, errorText, options, 0);
++ }
++ else
++ {
++ MythPopupBox::showOkPopup(
+ gContext->GetMainWindow(), QObject::tr("Channel Change Error"),
+ errorText);
++ }
+ }
+
+ /** \fn TV::PauseLiveTV(void)
+Index: mythtv/libs/libmythtv/jobqueue.cpp
+===================================================================
+--- mythtv/libs/libmythtv/jobqueue.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/jobqueue.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -275,6 +275,11 @@
+ (hostname != "") &&
+ (hostname != m_hostname))
+ {
++ // Setting the status here will prevent us from processing
++ // any other jobs for this recording until this one is
++ // completed on the remote host.
++ jobStatus[key] = status;
++
+ message = QString("JobQueue: Skipping '%1' job for chanid "
+ "%2 @ %3, should run on '%4' instead")
+ .arg(JobText(type))
+Index: mythtv/libs/libmythtv/dvbdev/dvbdev.c
+===================================================================
+--- mythtv/libs/libmythtv/dvbdev/dvbdev.c (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/dvbdev/dvbdev.c (.../branches/release-0-19-fixes) (revision 10051)
+@@ -29,55 +29,79 @@
+
+ const char* dvbdevice(int type, int cardnum)
+ {
+- char* frontenddev[4] =
++ char* frontenddev[8] =
+ {
+ "/dev/dvb/adapter0/frontend0",
+ "/dev/dvb/adapter1/frontend0",
+ "/dev/dvb/adapter2/frontend0",
+- "/dev/dvb/adapter3/frontend0"
++ "/dev/dvb/adapter3/frontend0",
++ "/dev/dvb/adapter4/frontend0",
++ "/dev/dvb/adapter5/frontend0",
++ "/dev/dvb/adapter6/frontend0",
++ "/dev/dvb/adapter7/frontend0",
+ };
+
+- char* dvrdev[4] =
++ char* dvrdev[8] =
+ {
+ "/dev/dvb/adapter0/dvr0",
+ "/dev/dvb/adapter1/dvr0",
+ "/dev/dvb/adapter2/dvr0",
+- "/dev/dvb/adapter3/dvr0"
++ "/dev/dvb/adapter3/dvr0",
++ "/dev/dvb/adapter4/dvr0",
++ "/dev/dvb/adapter5/dvr0",
++ "/dev/dvb/adapter6/dvr0",
++ "/dev/dvb/adapter7/dvr0",
+ };
+
+- char* demuxdev[4] =
++ char* demuxdev[8] =
+ {
+ "/dev/dvb/adapter0/demux0",
+ "/dev/dvb/adapter1/demux0",
+ "/dev/dvb/adapter2/demux0",
+- "/dev/dvb/adapter3/demux0"
++ "/dev/dvb/adapter3/demux0",
++ "/dev/dvb/adapter4/demux0",
++ "/dev/dvb/adapter5/demux0",
++ "/dev/dvb/adapter6/demux0",
++ "/dev/dvb/adapter7/demux0",
+ };
+
+- char* cadev[4] =
++ char* cadev[8] =
+ {
+ "/dev/dvb/adapter0/ca0",
+ "/dev/dvb/adapter1/ca0",
+ "/dev/dvb/adapter2/ca0",
+- "/dev/dvb/adapter3/ca0"
++ "/dev/dvb/adapter3/ca0",
++ "/dev/dvb/adapter4/ca0",
++ "/dev/dvb/adapter5/ca0",
++ "/dev/dvb/adapter6/ca0",
++ "/dev/dvb/adapter7/ca0",
+ };
+
+- char* audiodev[4] =
++ char* audiodev[8] =
+ {
+ "/dev/dvb/adapter0/audio0",
+ "/dev/dvb/adapter1/audio0",
+ "/dev/dvb/adapter2/audio0",
+- "/dev/dvb/adapter3/audio0"
++ "/dev/dvb/adapter3/audio0",
++ "/dev/dvb/adapter4/audio0",
++ "/dev/dvb/adapter5/audio0",
++ "/dev/dvb/adapter6/audio0",
++ "/dev/dvb/adapter7/audio0",
+ };
+
+- char* videodev[4] =
++ char* videodev[8] =
+ {
+ "/dev/dvb/adapter0/video0",
+ "/dev/dvb/adapter1/video0",
+ "/dev/dvb/adapter2/video0",
+- "/dev/dvb/adapter3/video0"
++ "/dev/dvb/adapter3/video0",
++ "/dev/dvb/adapter4/video0",
++ "/dev/dvb/adapter5/video0",
++ "/dev/dvb/adapter6/video0",
++ "/dev/dvb/adapter7/video0",
+ };
+
+- if (cardnum > 3)
++ if (cardnum > 7)
+ return 0;
+
+ switch(type)
+Index: mythtv/libs/libmythtv/libmythtv.pro
+===================================================================
+--- mythtv/libs/libmythtv/libmythtv.pro (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/libmythtv.pro (.../branches/release-0-19-fixes) (revision 10051)
+@@ -144,10 +144,10 @@
+ # On screen display (video output overlay)
+ HEADERS += osd.h osdtypes.h
+ HEADERS += osdsurface.h osdlistbtntype.h
+- HEADERS += udpnotify.h
++ HEADERS += osdimagecache.h udpnotify.h
+ SOURCES += osd.cpp osdtypes.cpp
+ SOURCES += osdsurface.cpp osdlistbtntype.cpp
+- SOURCES += udpnotify.cpp
++ SOURCES += osdimagecache.cpp udpnotify.cpp
+
+ # Video output
+ HEADERS += videooutbase.h videoout_null.h
+Index: mythtv/libs/libmythtv/osdtypes.h
+===================================================================
+--- mythtv/libs/libmythtv/osdtypes.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/osdtypes.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -8,6 +8,7 @@
+ #include <vector>
+ #include <qobject.h>
+ #include <qregexp.h>
++#include "osdimagecache.h"
+
+ using namespace std;
+
+@@ -137,6 +138,8 @@
+
+ QString Name() { return m_name; }
+
++ virtual void Reinit(float wmult, float hmult) = 0;
++
+ virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
+ int yoff) = 0;
+
+@@ -150,11 +153,11 @@
+ {
+ public:
+ OSDTypeText(const QString &name, TTFFont *font, const QString &text,
+- QRect displayrect);
++ QRect displayrect, float wmult, float hmult);
+ OSDTypeText(const OSDTypeText &text);
+ ~OSDTypeText();
+
+- void Reinit(float wchange, float hchange);
++ void Reinit(float wmult, float hmult);
+
+ void SetAltFont(TTFFont *font);
+ void SetUseAlt(bool usealt) { m_usingalt = usealt; }
+@@ -190,6 +193,7 @@
+
+ QRect m_displaysize;
+ QRect m_screensize;
++ QRect m_unbiasedsize;
+ QString m_message;
+ QString m_default_msg;
+
+@@ -231,7 +235,7 @@
+ virtual ~OSDTypeImage();
+
+ void SetName(const QString &name);
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ void Reinit(float wmult, float hmult);
+
+ void LoadImage(const QString &filename, float wmult, float hmult,
+ int scalew = -1, int scaleh = -1);
+@@ -239,21 +243,20 @@
+
+ void SetStaticSize(int scalew, int scaleh) { m_scalew = scalew;
+ m_scaleh = scaleh; }
++ void SetPosition(QPoint pos, float wmult, float hmult);
+
+- QPoint DisplayPos() { return m_displaypos; }
+- void SetPosition(QPoint pos) { m_displaypos = pos; }
++ QPoint DisplayPos() const { return m_displaypos; }
++ QRect ImageSize() const { return m_imagesize; }
++ int width() const { return m_imagesize.width(); }
++ int height() const { return m_imagesize.height(); }
+
+- QRect ImageSize() { return m_imagesize; }
+-
+- int width() { return m_imagesize.width(); }
+- int height() { return m_imagesize.height(); }
+-
+ virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
+ int yoff);
+
+ protected:
+ QRect m_imagesize;
+ QPoint m_displaypos;
++ QPoint m_unbiasedpos;
+
+ QString m_filename;
+
+@@ -270,6 +273,9 @@
+
+ int m_drawwidth;
+ bool m_onlyusefirst;
++
++ static OSDImageCache c_cache;
++ OSDImageCacheValue *m_cacheitem;
+ };
+
+ class OSDTypePosSlider : public OSDTypeImage
+@@ -280,7 +286,7 @@
+ int scalew = -1, int scaleh = -1);
+ ~OSDTypePosSlider();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ void Reinit(float wmult, float hmult);
+
+ void SetRectangle(QRect rect) { m_displayrect = rect; }
+ QRect ImageSize() { return m_imagesize; }
+@@ -290,6 +296,7 @@
+
+ private:
+ QRect m_displayrect;
++ QRect m_unbiasedrect;
+ int m_maxval;
+ int m_curval;
+ };
+@@ -302,7 +309,7 @@
+ int scalew = -1, int scaleh = -1);
+ ~OSDTypeFillSlider();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ void Reinit(float wmult, float hmult);
+
+ void SetRectangle(QRect rect) { m_displayrect = rect; }
+ QRect ImageSize() { return m_imagesize; }
+@@ -314,6 +321,7 @@
+
+ private:
+ QRect m_displayrect;
++ QRect m_unbiasedrect;
+ int m_maxval;
+ int m_curval;
+ };
+@@ -327,7 +335,7 @@
+ int scalew = -1, int scaleh = -1);
+ ~OSDTypeEditSlider();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ void Reinit(float wmult, float hmult);
+
+ void SetRectangle(QRect rect) { m_displayrect = rect; }
+ QRect ImageSize() { return m_imagesize; }
+@@ -339,6 +347,7 @@
+
+ private:
+ QRect m_displayrect;
++ QRect m_unbiasedrect;
+ int m_maxval;
+ int m_curval;
+
+@@ -360,17 +369,19 @@
+ class OSDTypeBox : public OSDType
+ {
+ public:
+- OSDTypeBox(const QString &name, QRect displayrect);
++ OSDTypeBox(const QString &name, QRect displayrect,
++ float wmult, float hmult);
+ OSDTypeBox(const OSDTypeBox &other);
+ ~OSDTypeBox();
+
+- void Reinit(float wchange, float hchange);
+- void SetRect(QRect newrect) { size = newrect; }
++ void Reinit(float wmult, float hmult);
++ void SetRect(QRect newrect, float wmult, float hmult);
+
+ void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+
+ private:
+ QRect size;
++ QRect m_unbiasedsize;
+ };
+
+ class OSDTypePositionIndicator
+@@ -403,14 +414,15 @@
+ OSDTypePositionRectangle(const OSDTypePositionRectangle &other);
+ ~OSDTypePositionRectangle();
+
+- void AddPosition(QRect rect);
++ void AddPosition(QRect rect, float wmult, float hmult);
+
+- void Reinit(float wchange, float hchange);
++ void Reinit(float wmult, float hmult);
+
+ void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+
+ private:
+- vector<QRect> positions;
++ vector<QRect> positions;
++ vector<QRect> unbiasedpos;
+ };
+
+ class OSDTypePositionImage : public virtual OSDTypeImage,
+@@ -421,14 +433,17 @@
+ OSDTypePositionImage(const OSDTypePositionImage &other);
+ ~OSDTypePositionImage();
+
+- void Reinit(float wchange, float hchange, float wmult, float hmult);
++ void Reinit(float wmult, float hmult);
+
+- void AddPosition(QPoint pos);
++ void AddPosition(QPoint pos, float wmult, float hmult);
+
+ void Draw(OSDSurface *surface, int fade, int maxfade, int xoff, int yoff);
+
+ private:
+ vector<QPoint> positions;
++ vector<QPoint> unbiasedpos;
++ float m_wmult;
++ float m_hmult;
+ };
+
+ class ccText
+@@ -445,11 +460,15 @@
+ {
+ public:
+ OSDTypeCC(const QString &name, TTFFont *font, int xoff, int yoff,
+- int dispw, int disph);
++ int dispw, int disph, float wmult, float hmult);
+ ~OSDTypeCC();
+
+- void Reinit(int xoff, int yoff, int dispw, int disph);
++ void Reinit(float wmult, float hmult);
+
++ void Reinit(int xoff, int yoff,
++ int dispw, int disph,
++ float wmult, float hmult);
++
+ void AddCCText(const QString &text, int x, int y, int color,
+ bool teletextmode = false);
+ void ClearAllCCText();
+@@ -464,7 +483,7 @@
+ vector<ccText *> *m_textlist;
+ OSDTypeBox *m_box;
+ int m_ccbackground;
+-
++ float m_wmult, m_hmult;
+ int xoffset, yoffset, displaywidth, displayheight;
+ };
+
+Index: mythtv/libs/libmythtv/osdimagecache.h
+===================================================================
+--- mythtv/libs/libmythtv/osdimagecache.h (.../tags/release-0-19) (revision 0)
++++ mythtv/libs/libmythtv/osdimagecache.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -0,0 +1,74 @@
++// -*- Mode: c++ -*-
++
++// POSIX headers
++#include <stdint.h>
++
++// Qt headers
++#include <qmap.h>
++#include <qrect.h>
++#include <qmutex.h>
++#include <qstring.h>
++#include <qasciicache.h>
++
++class OSDImageCacheValue
++{
++ public:
++ OSDImageCacheValue(QString cacheKey,
++ unsigned char *yuv, unsigned char *ybuffer,
++ unsigned char *ubuffer, unsigned char *vbuffer,
++ unsigned char *alpha, QRect imagesize);
++
++ virtual ~OSDImageCacheValue();
++
++ uint GetSize(void) const { return m_size_in_bytes; }
++ QString GetKey(void) const { return m_cacheKey; }
++
++ public:
++ unsigned char *m_yuv;
++ unsigned char *m_ybuffer;
++ unsigned char *m_ubuffer;
++ unsigned char *m_vbuffer;
++ unsigned char *m_alpha;
++ QRect m_imagesize;
++
++ private:
++ uint m_size_in_bytes;
++ QString m_cacheKey;
++};
++
++typedef QAsciiCache<OSDImageCacheValue> img_cache_t;
++
++class OSDImageCache
++{
++ public:
++ OSDImageCache();
++ virtual ~OSDImageCache();
++
++ bool InFileCache(const QString &key) const;
++
++ bool Contains(const QString &key, bool useFile) const;
++
++ OSDImageCacheValue *Get(const QString &key, bool useFile);
++
++ void Insert(OSDImageCacheValue* value);
++
++ void SaveToDisk(const OSDImageCacheValue *value);
++
++ void Reset(void);
++
++ static QString CreateKey(const QString &filename,
++ float wmult, float hmult,
++ int scalew, int scaleh);
++
++ static QString ExtractOriginal(const QString &key);
++
++ private:
++ mutable QMutex m_cacheLock;
++ img_cache_t m_imageCache;
++ int m_memHits;
++ int m_diskHits;
++ int m_misses;
++
++ /// Limit on the maximum total size of OSD images cached in *memory*.
++ static uint kMaximumMemoryCacheSize;
++};
+Index: mythtv/libs/libmythtv/tv_play.h
+===================================================================
+--- mythtv/libs/libmythtv/tv_play.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/tv_play.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -456,7 +456,6 @@
+ ProgramInfo *recorderPlaybackInfo; ///< info requested from recorder
+ ProgramInfo *playbackinfo; ///< info sent in via Playback()
+ QMutex pbinfoLock;
+- QString inputFilename; ///< playbackinfo->pathname
+ int playbackLen; ///< initial playbackinfo->CalculateLength()
+ ProgramInfo *lastProgram; ///< last program played with this player
+ bool jumpToProgram;
+@@ -485,6 +484,8 @@
+ // LiveTVChain
+ LiveTVChain *tvchain;
+ LiveTVChain *piptvchain;
++ QStringList tvchainUpdate;
++ QMutex tvchainUpdateLock;
+
+ // RingBuffers
+ RingBuffer *prbuffer;
+Index: mythtv/libs/libmythtv/videosource.cpp
+===================================================================
+--- mythtv/libs/libmythtv/videosource.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/videosource.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -32,6 +32,7 @@
+ #include "videosource.h"
+ #include "datadirect.h"
+ #include "scanwizard.h"
++#include "frequencies.h"
+
+ #ifdef USING_DVB
+ #include <linux/dvb/frontend.h>
+@@ -574,22 +575,10 @@
+ {
+ setLabel(QObject::tr("Channel frequency table"));
+ addSelection("default");
+- addSelection("us-cable");
+- addSelection("us-bcast");
+- addSelection("us-cable-hrc");
+- addSelection("japan-bcast");
+- addSelection("japan-cable");
+- addSelection("europe-west");
+- addSelection("europe-east");
+- addSelection("italy");
+- addSelection("newzealand");
+- addSelection("australia");
+- addSelection("ireland");
+- addSelection("france");
+- addSelection("china-bcast");
+- addSelection("southafrica");
+- addSelection("argentina");
+- addSelection("australia-optus");
++
++ for (uint i = 0; chanlists[i].name; i++)
++ addSelection(chanlists[i].name);
++
+ setHelpText(QObject::tr("Use default unless this source uses a "
+ "different frequency table than the system wide table "
+ "defined in the General settings."));
+Index: mythtv/libs/libmythtv/frequencytables.cpp
+===================================================================
+--- mythtv/libs/libmythtv/frequencytables.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/frequencytables.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -283,104 +283,52 @@
+ "ATSC Channel %1", 70, 809000000, 887000000, 6000000, VSB_8);
+ #endif // USING_DVB
+
+- // USA Cable, QAM 256
+- fmap["atsc_qam256_uscable0"] = new FrequencyTable(
+- "QAM-256 Channel %1", 1, 75000000,1005000000, 6000000, QAM_256);
+- fmap["atsc_qam256_uscable1"] = new FrequencyTable(
+- "QAM-256 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_256);
++ QString modStr[] = { "vsb8", "qam256", "qam128", "qam64", };
++ uint mod[] = { VSB_8, QAM_256, QAM_128, QAM_64, };
++ QString desc[] = { "ATSC ", "QAM-256 ", "QAM-128 ", "QAM-64 ", };
+
+- // USA Cable, QAM 256 ch 78+
+- fmap["atsc_qam256_uscablehigh0"] = new FrequencyTable(
+- "QAM-256 Channel %1", 78,472000000,1005000000, 6000000, QAM_256);
++#define FREQ(A,B, C,D, E,F,G, H) \
++ fmap[QString("atsc_%1_us%2").arg(A).arg(B)] = \
++ new FrequencyTable(C+D, E, F, G, 6000000, H);
+
+- // USA Cable HRC, QAM 256
+- fmap["atsc_qam256_ushrc0"] = new FrequencyTable(
+- "QAM-256 HRC %1", 1, 73750000, 73750001, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc1"] = new FrequencyTable(
+- "QAM-256 HRC %1", 2, 55750000, 67750000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc2"] = new FrequencyTable(
+- "QAM-256 HRC %1", 5, 79750000, 85750000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc3"] = new FrequencyTable(
+- "QAM-256 HRC %1", 7, 175750000, 643750000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc4"] = new FrequencyTable(
+- "QAM-256 HRC %1", 95, 91750000, 114000000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc5"] = new FrequencyTable(
+- "QAM-256 HRC %1", 100, 649750000, 799750000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrc6"] = new FrequencyTable(
+- "QAM-256 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_256);
++ for (uint i = 0; i < 3; i++)
++ {
++ // USA Cable, ch 1 to 155 and T.7 to T.14
++ FREQ(modStr[i], "cable0", desc[i], "Channel %1",
++ 1, 75000000, 1005000000, mod[i]);
++ FREQ(modStr[i], "cable1", desc[i], "Channel T-%1",
++ 7, 10000000, 52000000, mod[i]);
++ // USA Cable, QAM 256 ch 78 to 155
++ FREQ(modStr[i], "cablehigh0", desc[i], "Channel %1",
++ 78, 537000000,1005000000, mod[i]);
+
+- // USA Cable HRC, QAM 256 ch 78+
+- fmap["atsc_qam256_ushrchigh0"] = new FrequencyTable(
+- "QAM-256 HRC %1", 78, 601750000, 643750000, 6000000, QAM_256);
+- fmap["atsc_qam256_ushrchigh1"] = new FrequencyTable(
+- "QAM-256 HRC %1", 100, 649750000, 799750000, 6000000, QAM_256);
++ QString std[] = { "hrc", "irc" };
++ QString sdesc[] = { "HRC ", "IRC " };
++ int off[] = { 0, 1250000 };
+
++ for (uint j = 0; j < 2; j++)
++ {
++ // USA Cable HRC/IRC, ch 1 to 125
++ FREQ(modStr[i], std[j] + "0", desc[i], sdesc[j] + "%1",
++ 1, 73750000 + off[j], 73750001 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "1", desc[i], sdesc[j] + "%1",
++ 2, 55750000 + off[j], 67750000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "2", desc[i], sdesc[j] + "%1",
++ 5, 79750000 + off[j], 85750000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "3", desc[i], sdesc[j] + "%1",
++ 7, 175750000 + off[j], 643750000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "4", desc[i], sdesc[j] + "%1",
++ 95, 91750000 + off[j], 114000000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "5", desc[i], sdesc[j] + "%1",
++ 100, 649750000 + off[j], 799750000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "6", desc[i], sdesc[j] + "T-%1",
++ 7, 8175000 + off[j], 50750000 + off[j], mod[i]);
+
+-
+- // USA Cable, QAM 128
+- fmap["atsc_qam128_uscable0"] = new FrequencyTable(
+- "QAM-128 Channel %1", 1, 75000000,1005000000, 6000000, QAM_128);
+- fmap["atsc_qam128_uscable1"] = new FrequencyTable(
+- "QAM-128 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_128);
+-
+- // USA Cable, QAM 128 ch 78+
+- fmap["atsc_qam128_uscablehigh0"] = new FrequencyTable(
+- "QAM-128 Channel %1", 78,472000000,1005000000, 6000000, QAM_128);
+-
+- // USA Cable HRC, QAM 128
+- fmap["atsc_qam128_ushrc0"] = new FrequencyTable(
+- "QAM-128 HRC %1", 1, 73750000, 73750001, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc1"] = new FrequencyTable(
+- "QAM-128 HRC %1", 2, 55750000, 67750000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc2"] = new FrequencyTable(
+- "QAM-128 HRC %1", 5, 79750000, 85750000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc3"] = new FrequencyTable(
+- "QAM-128 HRC %1", 7, 175750000, 643750000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc4"] = new FrequencyTable(
+- "QAM-128 HRC %1", 95, 91750000, 114000000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc5"] = new FrequencyTable(
+- "QAM-128 HRC %1", 100, 649750000, 799750000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrc6"] = new FrequencyTable(
+- "QAM-128 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_128);
+-
+- // USA Cable HRC, QAM 128 ch 78+
+- fmap["atsc_qam128_ushrchigh0"] = new FrequencyTable(
+- "QAM-128 HRC %1", 78, 601750000, 643750000, 6000000, QAM_128);
+- fmap["atsc_qam128_ushrchigh1"] = new FrequencyTable(
+- "QAM-128 HRC %1", 100, 649750000, 799750000, 6000000, QAM_128);
+-
+-
+-
+-
+- // USA Cable, QAM 64
+- fmap["atsc_qam64_uscable0"] = new FrequencyTable(
+- "QAM-64 Channel %1", 1, 75000000,1005000000, 6000000, QAM_64);
+- fmap["atsc_qam64_uscable1"] = new FrequencyTable(
+- "QAM-64 Channel T-%1", 7, 10000000, 52000000, 6000000, QAM_64);
+-
+- // USA Cable, QAM 64 ch 78+
+- fmap["atsc_qam64_uscablehigh0"] = new FrequencyTable(
+- "QAM-64 Channel %1", 78,472000000,1005000000, 6000000, QAM_64);
+-
+- // USA Cable HRC, QAM 64
+- fmap["atsc_qam64_ushrc0"] = new FrequencyTable(
+- "QAM-64 HRC %1", 1, 73750000, 73750001, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc1"] = new FrequencyTable(
+- "QAM-64 HRC %1", 2, 55750000, 67750000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc2"] = new FrequencyTable(
+- "QAM-64 HRC %1", 5, 79750000, 85750000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc3"] = new FrequencyTable(
+- "QAM-64 HRC %1", 7, 175750000, 643750000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc4"] = new FrequencyTable(
+- "QAM-64 HRC %1", 95, 91750000, 114000000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc5"] = new FrequencyTable(
+- "QAM-64 HRC %1", 100, 649750000, 799750000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrc6"] = new FrequencyTable(
+- "QAM-64 HRC T-%1", 7, 8175000, 50750000, 6000000, QAM_64);
+-
+- // USA Cable HRC, QAM 64 ch 78+
+- fmap["atsc_qam64_ushrchigh0"] = new FrequencyTable(
+- "QAM-64 HRC %1", 78, 601750000, 643750000, 6000000, QAM_64);
+- fmap["atsc_qam64_ushrchigh1"] = new FrequencyTable(
+- "QAM-64 HRC %1", 100, 649750000, 799750000, 6000000, QAM_64);
++ // USA Cable HRC/IRC, ch 67-125
++ FREQ(modStr[i], std[j] + "high0", desc[i], sdesc[j] + "%1",
++ 67, 535750000 + off[j], 643750000 + off[j], mod[i]);
++ FREQ(modStr[i], std[j] + "high1", desc[i], sdesc[j] + "%1",
++ 100, 649750000 + off[j], 799750000 + off[j], mod[i]);
++ }
++ }
+ }
+Index: mythtv/libs/libmythtv/scanwizardhelpers.h
+===================================================================
+--- mythtv/libs/libmythtv/scanwizardhelpers.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/scanwizardhelpers.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -272,11 +272,13 @@
+ public:
+ ScanFrequencyTable()
+ {
+- addSelection(QObject::tr("Broadcast"), "us", true);
+- addSelection(QObject::tr("Cable") +" 78+", "uscablehigh", false);
+- addSelection(QObject::tr("Cable HRC")+" 78+", "uscablehrchigh",false);
+- addSelection(QObject::tr("Cable"), "uscable", false);
+- addSelection(QObject::tr("Cable HRC"), "ushrc", false);
++ addSelection(QObject::tr("Broadcast"), "us", true);
++ addSelection(QObject::tr("Cable") +" 78+", "uscablehigh", false);
++ addSelection(QObject::tr("Cable HRC")+" 67+", "ushrchigh", false);
++ addSelection(QObject::tr("Cable IRC")+" 67+", "usirchigh", false);
++ addSelection(QObject::tr("Cable"), "uscable", false);
++ addSelection(QObject::tr("Cable HRC"), "ushrc", false);
++ addSelection(QObject::tr("Cable IRC"), "usirc", false);
+
+ setLabel(QObject::tr("Frequency Table"));
+ setHelpText(QObject::tr("Frequency table to use.") + " " +
+Index: mythtv/libs/libmythtv/scanwizard.cpp
+===================================================================
+--- mythtv/libs/libmythtv/scanwizard.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/scanwizard.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -518,7 +518,9 @@
+ "SELECT dvb_diseqc_type, diseqc_port, diseqc_pos, "
+ " lnb_lof_switch, lnb_lof_hi, lnb_lof_lo "
+ "FROM cardinput, capturecard "
+- "WHERE capturecard.cardid=%1 and cardinput.sourceid=%2")
++ "WHERE capturecard.cardid = %1 AND "
++ " cardinput.sourceid = %2 AND "
++ " capturecard.cardid = cardinput.cardid")
+ .arg(parent->captureCard()).arg(nVideoSource));
+
+ if (query.exec() && query.isActive() && query.size() > 0)
+Index: mythtv/libs/libmythtv/RingBuffer.h
+===================================================================
+--- mythtv/libs/libmythtv/RingBuffer.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/RingBuffer.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -91,6 +91,7 @@
+ long long GetTotalReadPosition(void);
+
+ long long SetAdjustFilesize(void);
++ void SetTimeout(bool fast) { oldfile = fast; }
+
+ protected:
+ static void *StartReader(void *type);
+Index: mythtv/libs/libmythtv/dvbtypes.cpp
+===================================================================
+--- mythtv/libs/libmythtv/dvbtypes.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/dvbtypes.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -202,7 +202,7 @@
+ {
+ {"TRANSMISSION_MODE_AUTO",TRANSMISSION_MODE_AUTO},
+ {"TRANSMISSION_MODE_2K",TRANSMISSION_MODE_2K},
+- {"TRANSMISSION_MODE_8K",TRANSMISSION_MODE_2K},
++ {"TRANSMISSION_MODE_8K",TRANSMISSION_MODE_8K},
+ {NULL,TRANSMISSION_MODE_AUTO},
+ };
+
+@@ -210,7 +210,7 @@
+ {
+ {"999",TRANSMISSION_MODE_AUTO},
+ {"2",TRANSMISSION_MODE_2K},
+- {"8",TRANSMISSION_MODE_2K},
++ {"8",TRANSMISSION_MODE_8K},
+ {NULL,TRANSMISSION_MODE_AUTO},
+ };
+
+@@ -218,7 +218,7 @@
+ {
+ {"auto",TRANSMISSION_MODE_AUTO},
+ {"2",TRANSMISSION_MODE_2K},
+- {"8",TRANSMISSION_MODE_2K},
++ {"8",TRANSMISSION_MODE_8K},
+ {NULL,TRANSMISSION_MODE_AUTO},
+ };
+
+Index: mythtv/libs/libmythtv/mpegrecorder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/mpegrecorder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/mpegrecorder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -363,9 +363,9 @@
+
+ if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
+ {
+- cerr << "Error setting codec params\n";
++ cerr << "Warning, unable to set recording volume\n";
++ cerr << "This is normal if you have an AVerMedia M179 card.\n";
+ perror("VIDIOC_S_CTRL:");
+- return false;
+ }
+
+ if (vbimode) {
+@@ -481,6 +481,9 @@
+ continue;
+ case 0:
+ printf("select timeout - ivtv driver has stopped responding\n");
++ if(close(readfd) != 0)
++ perror("close");
++ readfd = -1; // Force PVR card to be reopened on next iteration
+ continue;
+ default: break;
+ }
+Index: mythtv/libs/libmythtv/ivtvdecoder.cpp
+===================================================================
+--- mythtv/libs/libmythtv/ivtvdecoder.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/ivtvdecoder.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -270,7 +270,9 @@
+
+ GetNVP()->SetVideoParams(720 /*width*/, (ntsc) ? 480 : 576 /*height*/,
+ (ntsc) ? 29.97f : 25.0f, keyframedist, 1.33);
+-
++
++ fps = (ntsc) ? 29.97f : 25.0f; // save for later length calculations
++
+ ringBuffer->UpdateRawBitrate(8000);
+
+ if (m_playbackinfo || livetv || watchingrecording)
+Index: mythtv/libs/libmythtv/dvbsignalmonitor.cpp
+===================================================================
+--- mythtv/libs/libmythtv/dvbsignalmonitor.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/dvbsignalmonitor.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -348,8 +348,8 @@
+
+ len += remainder;
+ remainder = GetStreamData()->ProcessData(buffer, len);
+- if (remainder > 0) // leftover bytes
+- memmove(buffer, &(buffer[buffer_size - remainder]), remainder);
++ if (remainder > 0 && (len > remainder)) // leftover bytes
++ memmove(buffer, &(buffer[len - remainder]), remainder);
+ }
+ VERBOSE(VB_CHANNEL, LOC + "RunTableMonitorTS(): " + "shutdown");
+
+Index: mythtv/libs/libmythtv/osdimagecache.cpp
+===================================================================
+--- mythtv/libs/libmythtv/osdimagecache.cpp (.../tags/release-0-19) (revision 0)
++++ mythtv/libs/libmythtv/osdimagecache.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -0,0 +1,296 @@
++// -*- Mode: c++ -*-
++/** OSDImageCache
++ * Copyright (c) 2006 by Pekka Jääskeläinen, Daniel Thor Kristjansson
++ * Distributed as part of MythTV under GPL v2 and later.
++ */
++
++// POSIX headers
++#include <stdint.h>
++
++// Qt headers
++#include <qdir.h>
++#include <qfile.h>
++#include <qfileinfo.h>
++#include <qdatastream.h>
++#include <qdeepcopy.h>
++
++// MythTV headers
++#include "mythcontext.h"
++#include "osdimagecache.h"
++
++// Print statistics of OSD image access in the destructor of OSDImageCache
++//#define PRINT_OSD_IMAGE_CACHE_STATS
++
++#define LOC QString("OSDImgCache: ")
++#define LOC_ERR QString("OSDImgCache, Error: ")
++
++uint OSDImageCache::kMaximumMemoryCacheSize = 5 * 1024 * 1024;
++
++/** \fn OSDImageCacheValue::OSDImageCacheValue(unsigned char*,unsigned char*,unsighed char*,unsigned char*,unsighed char*, QRect)
++ * \brief The main constructor that takes the image data as arguments.
++ *
++ * The image data becomes property of the OSDImageCacheValue
++ * and will be deleted by it.
++ */
++OSDImageCacheValue::OSDImageCacheValue(
++ QString cacheKey,
++ unsigned char *yuv, unsigned char *ybuffer,
++ unsigned char *ubuffer, unsigned char *vbuffer,
++ unsigned char *alpha, QRect imagesize) :
++ m_yuv(yuv), m_ybuffer(ybuffer),
++ m_ubuffer(ubuffer), m_vbuffer(vbuffer),
++ m_alpha(alpha), m_imagesize(imagesize),
++ m_cacheKey(QDeepCopy<QString>(cacheKey))
++{
++ uint yuv_size = m_imagesize.width() * m_imagesize.height() * 3 / 2;
++ m_size_in_bytes =
++ (sizeof(OSDImageCacheValue)) + yuv_size +
++ (m_imagesize.width() * m_imagesize.height());
++}
++
++/** \fn OSDImageCacheValue::~OSDImageCacheValue()
++ * \brief Destructor, frees the cached bitmaps.
++ */
++OSDImageCacheValue::~OSDImageCacheValue()
++{
++ delete [] m_yuv;
++ m_yuv = NULL;
++ delete [] m_alpha;
++ m_alpha = NULL;
++}
++
++/** \fn OSDImageCache::OSDImageCache()
++ * \brief Constructor, initializes the internal cache structures.
++ */
++OSDImageCache::OSDImageCache() :
++ m_cacheLock(true), m_imageCache(kMaximumMemoryCacheSize, 50),
++ m_memHits(0), m_diskHits(0), m_misses(0)
++{
++ // When the cache gets too large, items are
++ // automatically deleted from it in LRU order.
++ m_imageCache.setAutoDelete(true);
++}
++
++/** \fn OSDImageCache::~OSDImageCache()
++ * \brief Destructor, frees all cached OSD images.
++ */
++OSDImageCache::~OSDImageCache()
++{
++#ifdef PRINT_OSD_IMAGE_CACHE_STATS
++ int totalAccess = m_memHits + m_diskHits + m_misses;
++ if (totalAccess == 0)
++ return;
++
++#define LOG_PREFIX "OSDImageCache: "
++ VERBOSE(VB_IMPORTANT, LOC << " Statistics: " << endl
++ << LOG_PREFIX << m_imageCache.totalCost() << " bytes in cache\n"
++ << LOG_PREFIX << " memory hits: "
++ << m_memHits << ", " << m_memHits*100.0/totalAccess << "%\n"
++ << LOG_PREFIX << " disk hits: "
++ << m_diskHits << ", " << m_diskHits*100.0/totalAccess << "%\n"
++ << LOG_PREFIX << " misses: "
++ << m_misses << ", " << m_misses*100.0/totalAccess << "%");
++#undef LOC_PREFIX
++#endif
++ Reset();
++}
++
++/** \fn OSDImageCache::Contains(const QString&,bool)
++ * \brief Returns true if cached OSD image was found in the cache.
++ *
++ * \param key The key for this image.
++ * \param useFile If true, also look from the disk cache.
++ */
++bool OSDImageCache::Contains(const QString &key, bool useFile) const
++{
++ QMutexLocker locker(&m_cacheLock);
++
++ if (m_imageCache.find(key) != NULL)
++ return true;
++
++ if (!useFile)
++ return false;
++
++ return InFileCache(key);
++}
++
++bool OSDImageCache::InFileCache(const QString &key) const
++{
++ // check if cache file exists
++ QDir dir(MythContext::GetConfDir() + "/osdcache/");
++ QFileInfo cFile(dir.path() + "/" + key);
++ if (!cFile.exists() || !cFile.isReadable())
++ return false;
++
++ // check if backing file exists
++ QString orig = ExtractOriginal(key);
++ if (orig.isEmpty())
++ return false;
++
++ QFileInfo oFile(orig);
++ if (!oFile.exists())
++ {
++ VERBOSE(VB_IMPORTANT, LOC + QString("Can't find '%1'").arg(orig));
++ return false;
++ }
++
++ // if cache file is older than backing file, delete cache file
++ if (cFile.lastModified() < oFile.lastModified())
++ {
++ cFile.dir().remove(cFile.baseName(true));
++ return false;
++ }
++
++ return true;
++}
++
++/** \fn OSDImageCache::Get(const QString&,bool)
++ * \brief Returns OSD image data from cache.
++ *
++ * This also removes the image from the cache so it won't be deleted
++ * while in use. The deletion of the taken item becomes responsibility
++ * of the client. Returns NULL if item with the given key is not found.
++ *
++ * \param key The key for this image.
++ * \param useFile If true, also check the disk cache.
++ */
++OSDImageCacheValue *OSDImageCache::Get(const QString &key, bool useFile)
++{
++ QMutexLocker locker(&m_cacheLock);
++ OSDImageCacheValue* item = m_imageCache.find(key);
++ if (item)
++ {
++ m_memHits++;
++ return m_imageCache.take(key);
++ }
++
++ if (!useFile || !InFileCache(key))
++ {
++ m_misses++;
++ return NULL;
++ }
++
++ QDir dir(MythContext::GetConfDir() + "/osdcache/");
++ QFile cacheFile(dir.path() + "/" + key);
++ cacheFile.open(IO_ReadOnly);
++ uint32_t imwidth = 0;
++ uint32_t imheight = 0;
++
++ QDataStream stream(&cacheFile);
++ stream >> imwidth >> imheight;
++
++ uint yuv_size = imwidth * imheight * 3 / 2;
++ uint tot_size = (sizeof(imwidth) * 2) + yuv_size + (imwidth * imheight);
++
++ if (cacheFile.size() != tot_size)
++ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + key + " wrong cache file size!"
++ << cacheFile.size() << " != " << tot_size);
++ return NULL;
++ }
++
++ unsigned char *yuv = new unsigned char[yuv_size];
++ unsigned char *alpha = new unsigned char[imwidth * imheight];
++ stream.readRawBytes((char*)yuv, yuv_size);
++ stream.readRawBytes((char*)alpha, imwidth * imheight);
++ cacheFile.close();
++
++ OSDImageCacheValue* value =
++ new OSDImageCacheValue(
++ key,
++ yuv, yuv,
++ yuv + (imwidth * imheight),
++ yuv + (imwidth * imheight * 5 / 4),
++ alpha, QRect(0, 0, imwidth, imheight));
++
++ m_diskHits++;
++ return value;
++}
++
++/** \fn OSDImageCache::Insert(OSDImageCacheValue*)
++ * \brief Inserts OSD image data to memory cache.
++ *
++ * The item becomes property of the OSDImageCache and may be
++ * deleted any time by it.
++ *
++ * \param value The cache item.
++ */
++void OSDImageCache::Insert(OSDImageCacheValue *value)
++{
++ if (!value)
++ return;
++
++ QMutexLocker locker(&m_cacheLock);
++ if (!m_imageCache.insert(value->GetKey(), value, value->GetSize()))
++ {
++ VERBOSE(VB_IMPORTANT,
++ LOC_ERR + QString("inserting image to memory cache failed"));
++ }
++}
++
++
++/** \fn OSDImageCache::SaveToDisk(const OSDImageCacheValue*)
++ * \brief Saves OSD image data to disk cache.
++ *
++ * Item is not written to the memory cache, i.e., it stays as
++ * property of the client.
++ *
++ * \param value The cached OSD image to save.
++ */
++void OSDImageCache::SaveToDisk(const OSDImageCacheValue *value)
++{
++ if (InFileCache(value->GetKey()))
++ return;
++
++ QDir dir(MythContext::GetConfDir() + "/osdcache/");
++ if (!dir.exists() && !dir.mkdir(dir.path()))
++ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache directory failed.");
++ return;
++ }
++
++ QFile cacheFile(dir.path() + "/" + value->GetKey());
++ if (!cacheFile.open(IO_WriteOnly | IO_Truncate))
++ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache file failed.");
++ return;
++ }
++
++ uint32_t imwidth = value->m_imagesize.width();
++ uint32_t imheight = value->m_imagesize.height();
++ uint yuv_size = imwidth * imheight * 3 / 2;
++
++ QDataStream stream(&cacheFile);
++ stream << imwidth << imheight;
++ stream.writeRawBytes((const char*)value->m_yuv, yuv_size);
++ stream.writeRawBytes((const char*)value->m_alpha, imwidth * imheight);
++ cacheFile.close();
++}
++
++/** \fn OSDImageCache::CreateKey(const QString&,float,float,int,int)
++ * \brief Generates a cache key from the given OSD image parameters.
++ *
++ * The returned key is a string that can be safely used as a file name.
++ */
++QString OSDImageCache::CreateKey(const QString &filename, float wmult,
++ float hmult, int scalew, int scaleh)
++{
++ QString tmp = filename;
++ return QString("cache_%1@%2_%3_%4_%5").arg(tmp.replace(QChar('/'), "+"))
++ .arg(wmult).arg(hmult).arg(scalew).arg(scaleh);
++}
++
++QString OSDImageCache::ExtractOriginal(const QString &key)
++{
++ QString tmp0 = key.mid(6);
++ QString tmp1 = tmp0.left(tmp0.find("@"));
++ QString tmp2 = tmp1.replace(QChar('+'), "/");
++ return tmp2;
++}
++
++void OSDImageCache::Reset(void)
++{
++ QMutexLocker locker(&m_cacheLock);
++ // this also deletes the images due to setAutoDelete(true)
++ m_imageCache.clear();
++}
+Index: mythtv/libs/libmythtv/osd.cpp
+===================================================================
+--- mythtv/libs/libmythtv/osd.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/osd.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -154,7 +154,8 @@
+ }
+
+ OSDTypeCC *ccpage = new OSDTypeCC(name, ccfont, sub_xoff, sub_yoff,
+- sub_dispw, sub_disph);
++ sub_dispw, sub_disph,
++ wmult, hmult);
+ container->AddType(ccpage);
+ }
+
+@@ -517,7 +518,7 @@
+ }
+ }
+
+- OSDTypeBox *box = new OSDTypeBox(name, area);
++ OSDTypeBox *box = new OSDTypeBox(name, area, wmult, hmult);
+ container->AddType(box);
+ }
+
+@@ -658,7 +659,7 @@
+ return;
+ }
+
+- OSDTypeText *text = new OSDTypeText(name, ttffont, "", area);
++ OSDTypeText *text = new OSDTypeText(name, ttffont, "", area, wmult, hmult);
+ container->AddType(text);
+
+ text->SetMultiLine(multiline);
+@@ -875,7 +876,7 @@
+ QRect area = parseRect(getFirstText(info));
+ normalizeRect(area);
+
+- rects->AddPosition(area);
++ rects->AddPosition(area, wmult, hmult);
+ }
+ else
+ {
+@@ -919,7 +920,7 @@
+ pos.setX((int)(pos.x() * wmult + xoffset));
+ pos.setY((int)(pos.y() * hmult + yoffset));
+
+- image->AddPosition(pos);
++ image->AddPosition(pos, wmult, hmult);
+ }
+ else if (info.tagName() == "staticsize")
+ {
+@@ -1925,7 +1926,7 @@
+ image = new OSDTypeImage(*editarrowright);
+ }
+
+- image->SetPosition(QPoint(xpos, ypos));
++ image->SetPosition(QPoint(xpos, ypos), wmult, hmult);
+
+ set->AddType(image);
+ set->Display();
+Index: mythtv/libs/libmythtv/dvbconfparser.cpp
+===================================================================
+--- mythtv/libs/libmythtv/dvbconfparser.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/dvbconfparser.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -193,10 +193,10 @@
+ QStringList::Iterator end = tokens.end();
+
+ if (i != end) c.name = *i++; else return false;
+- if (i != end) c.frequency = (*i++).toInt(); else return false;
++ if (i != end) c.frequency = (*i++).toUInt()*1000; else return false;
+ if (i == end || !c.polarity.parseConf(*i++)) return false;
+ if (i == end ) return false; else i++; //Sat num
+- if (i != end) c.symbolrate = (*i++).toInt(); else return false;
++ if (i != end) c.symbolrate = (*i++).toUInt()*1000; else return false;
+ if (i == end ) return false; else i++;
+ if (i == end ) return false; else i++;
+ if (i != end) c.serviceid = (*i++).toInt(); else return false;
+Index: mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp
+===================================================================
+--- mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmythtv/pchdtvsignalmonitor.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -108,8 +108,8 @@
+
+ len += remainder;
+ remainder = GetStreamData()->ProcessData(buffer, len);
+- if (remainder > 0) // leftover bytes
+- memmove(buffer, &(buffer[buffer_size - remainder]), remainder);
++ if (remainder > 0 && (len > remainder)) // leftover bytes
++ memmove(buffer, &(buffer[len - remainder]), remainder);
+ }
+ DBG_SM("RunTableMonitor()", "end");
+ }
+Index: mythtv/libs/libavformat/aviobuf.c
+===================================================================
+--- mythtv/libs/libavformat/aviobuf.c (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libavformat/aviobuf.c (.../branches/release-0-19-fixes) (revision 10051)
+@@ -164,7 +164,13 @@
+
+ void url_fskip(ByteIOContext *s, offset_t offset)
+ {
+- url_fseek(s, offset, SEEK_CUR);
++ if (offset < 16384)
++ {
++ static unsigned char fskipbuf[16384];
++ get_buffer(s, fskipbuf, offset);
++ }
++ else
++ url_fseek(s, offset, SEEK_CUR);
+ }
+
+ offset_t url_ftell(ByteIOContext *s)
+Index: mythtv/libs/libmyth/lcddevice.cpp
+===================================================================
+--- mythtv/libs/libmyth/lcddevice.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/lcddevice.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -150,7 +150,7 @@
+
+ if (!connected)
+ {
+- QTextStream os(socket);
++ QTextStream os(socket->socketDevice());
+
+ int count = 0;
+ do
+@@ -213,7 +213,7 @@
+ return;
+ }
+
+- QTextStream os(socket);
++ QTextStream os(socket->socketDevice());
+
+ last_command = someText;
+
+@@ -224,7 +224,7 @@
+ #endif
+ // Just stream the text out the socket
+
+- os << someText << "\n" << flush;
++ os << someText << "\n";
+ }
+ else
+ {
+Index: mythtv/libs/libmyth/audiooutputca.cpp
+===================================================================
+--- mythtv/libs/libmyth/audiooutputca.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/audiooutputca.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -107,8 +107,10 @@
+ bzero(&conv_in_desc, sizeof(AudioStreamBasicDescription));
+ conv_in_desc.mSampleRate = audio_samplerate;
+ conv_in_desc.mFormatID = kAudioFormatLinearPCM;
+- conv_in_desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
+- | kLinearPCMFormatFlagIsBigEndian;
++ conv_in_desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
++#ifdef WORDS_BIGENDIAN
++ conv_in_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
++#endif
+ conv_in_desc.mBytesPerPacket = audio_bytes_per_sample;
+ conv_in_desc.mFramesPerPacket = 1;
+ conv_in_desc.mBytesPerFrame = audio_bytes_per_sample;
+Index: mythtv/libs/libmyth/util.cpp
+===================================================================
+--- mythtv/libs/libmyth/util.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/util.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1006,16 +1006,20 @@
+ long long freespace = -1;
+ QCString cstr = file_on_disk.local8Bit();
+
+- if (statfs(cstr, &statbuf) == 0)
++ total = used = -1;
++
++ // there are cases where statfs will return 0 (good), but f_blocks and
++ // others are invalid and set to 0 (such as when an automounted directory
++ // is not mounted but still visible because --ghost was used),
++ // so check to make sure we can have a total size > 0
++ if ((statfs(cstr, &statbuf) == 0) &&
++ (statbuf.f_blocks > 0) &&
++ (statbuf.f_bsize > 0))
+ {
+ freespace = statbuf.f_bsize * (statbuf.f_bavail >> 10);
+ total = statbuf.f_bsize * (statbuf.f_blocks >> 10);
+ used = total - freespace;
+ }
+- else
+- {
+- freespace = total = used = -1;
+- }
+
+ return freespace;
+ }
+Index: mythtv/libs/libmyth/mythdialogs.cpp
+===================================================================
+--- mythtv/libs/libmyth/mythdialogs.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/mythdialogs.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -2617,6 +2617,7 @@
+ password_editor->setEchoMode(QLineEdit::Password);
+ password_editor->setGeometry(textWidth + 20,10,135,30);
+ password_editor->setBackgroundOrigin(ParentOrigin);
++ password_editor->setAllowVirtualKeyboard(false);
+ connect(password_editor, SIGNAL(textChanged(const QString &)),
+ this, SLOT(checkPassword(const QString &)));
+
+Index: mythtv/libs/libmyth/mythwidgets.cpp
+===================================================================
+--- mythtv/libs/libmyth/mythwidgets.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/mythwidgets.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -353,7 +353,8 @@
+ (e->key() == Qt::Key_Enter) ||
+ (e->key() == Qt::Key_Return)))
+ {
+- if (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1)
++ if ((allowVirtualKeyboard) &&
++ (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1))
+ {
+ popup = new VirtualKeyboard(gContext->GetMainWindow(), this);
+ gContext->GetMainWindow()->detach(popup);
+@@ -726,10 +727,11 @@
+ QWidget::focusNextPrevChild(true);
+ emit tryingToLooseFocus(true);
+ }
+- else if (action == "SELECT" &&
+- (e->text().isNull() ||
+- (e->key() == Qt::Key_Enter) ||
+- (e->key() == Qt::Key_Return)))
++ else if ((action == "SELECT") &&
++ (!active_cycle) &&
++ ((e->text().isNull()) ||
++ (e->key() == Qt::Key_Enter) ||
++ (e->key() == Qt::Key_Return)))
+ {
+ if (gContext->GetNumSetting("UseVirtualKeyboard", 1) == 1)
+ {
+@@ -749,7 +751,7 @@
+ if (handled)
+ return;
+
+- if (!handled && popup && popup->isShown())
++ if (popup && popup->isShown())
+ {
+ endCycle();
+ QTextEdit::keyPressEvent(e);
+Index: mythtv/libs/libmyth/remotefile.h
+===================================================================
+--- mythtv/libs/libmyth/remotefile.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/remotefile.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -27,6 +27,8 @@
+
+ long long GetFileSize(void);
+
++ void SetTimeout(bool fast);
++
+ private:
+ QSocketDevice *openSocket(bool control);
+
+@@ -43,6 +45,7 @@
+ QMutex lock;
+
+ long long filesize;
++ bool timeoutisfast;
+ };
+
+ #endif
+Index: mythtv/libs/libmyth/mythwidgets.h
+===================================================================
+--- mythtv/libs/libmyth/mythwidgets.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/mythwidgets.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -122,17 +122,21 @@
+ Q_OBJECT
+ public:
+ MythLineEdit(QWidget *parent=NULL, const char* widgetName=0) :
+- QLineEdit(parent, widgetName) { rw = true; Init(); };
++ QLineEdit(parent, widgetName)
++ { rw = true; allowVirtualKeyboard = true; Init(); };
+
+ MythLineEdit(const QString& contents, QWidget *parent=NULL,
+ const char* widgetName=0) :
+- QLineEdit(contents, parent, widgetName) { rw = true; Init(); };
++ QLineEdit(contents, parent, widgetName)
++ { rw = true; allowVirtualKeyboard = true; Init(); };
+
+ virtual ~MythLineEdit();
+
+ void setHelpText(QString help) { helptext = help; };
+ void setRW(bool readwrite = true) { rw = readwrite; };
+ void setRO() { rw = false; };
++ void setAllowVirtualKeyboard(bool allowKbd = true)
++ { allowVirtualKeyboard = allowKbd; }
+ void setPopupPosition(PopupPosition pos) { popupPosition = pos; }
+ PopupPosition getPopupPosition(void) { return popupPosition; }
+
+@@ -154,6 +158,7 @@
+ VirtualKeyboard *popup;
+ QString helptext;
+ bool rw;
++ bool allowVirtualKeyboard;
+ PopupPosition popupPosition;
+ };
+
+Index: mythtv/libs/libmyth/mythcontext.cpp
+===================================================================
+--- mythtv/libs/libmyth/mythcontext.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/mythcontext.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -2621,9 +2621,13 @@
+ d->LoadLogSettings();
+ if (d->m_logenable == 1)
+ {
++ QString fullMsg = message;
++ if (!details.isEmpty())
++ fullMsg += ": " + details;
++
+ if (message.left(21) != "Last message repeated")
+ {
+- if (message == d->lastLogStrings[module])
++ if (fullMsg == d->lastLogStrings[module])
+ {
+ d->lastLogCounts[module] += 1;
+ return;
+@@ -2639,7 +2643,7 @@
+ }
+
+ d->lastLogCounts[module] = 0;
+- d->lastLogStrings[module] = message;
++ d->lastLogStrings[module] = fullMsg;
+ }
+ }
+
+@@ -2693,7 +2697,7 @@
+ }
+
+ if (priority <= d->m_logprintlevel)
+- VERBOSE(VB_IMPORTANT, module + ": " + message);
++ VERBOSE(VB_IMPORTANT, module + ": " + fullMsg);
+ }
+ }
+
+Index: mythtv/libs/libmyth/remotefile.cpp
+===================================================================
+--- mythtv/libs/libmyth/remotefile.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libmyth/remotefile.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -15,6 +15,7 @@
+ path = url;
+ readposition = 0;
+ filesize = -1;
++ timeoutisfast = false;
+
+ query = "QUERY_FILETRANSFER %1";
+
+@@ -295,4 +296,34 @@
+ Read(data.data(), filesize);
+
+ return true;
+-}
++}
++
++void RemoteFile::SetTimeout(bool fast)
++{
++ if (timeoutisfast == fast)
++ return;
++
++ if (!sock)
++ {
++ VERBOSE(VB_NETWORK, "RemoteFile::Seek(): Called with no socket");
++ return;
++ }
++
++ if (!sock->isOpen() || sock->error())
++ return;
++
++ if (!controlSock->isOpen() || controlSock->error())
++ return;
++
++ QStringList strlist = QString(query).arg(recordernum);
++ strlist << "SET_TIMEOUT";
++ strlist << QString::number((int)fast);
++
++ lock.lock();
++ WriteStringList(controlSock, strlist);
++ ReadStringList(controlSock, strlist);
++ lock.unlock();
++
++ timeoutisfast = fast;
++}
++
+Index: mythtv/libs/libavcodec/libavcodec.pro
+===================================================================
+--- mythtv/libs/libavcodec/libavcodec.pro (.../tags/release-0-19) (revision 10051)
++++ mythtv/libs/libavcodec/libavcodec.pro (.../branches/release-0-19-fixes) (revision 10051)
+@@ -430,4 +430,5 @@
+ LIBS += -lz
+ QMAKE_LFLAGS_SHLIB += -single_module
+ QMAKE_LFLAGS_SHLIB += -seg1addr 0xC3000000
++ QMAKE_LFLAGS_SHLIB += -read_only_relocs warning
+ }
+Index: mythtv/programs/mythfrontend/playbackbox.cpp
+===================================================================
+--- mythtv/programs/mythfrontend/playbackbox.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfrontend/playbackbox.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -17,6 +17,7 @@
+ #include <qsqldatabase.h>
+ #include <qmap.h>
+
++#include <cmath>
+ #include <unistd.h>
+
+ #include <iostream>
+@@ -140,6 +141,7 @@
+ // Main Recording List support
+ fillListTimer(new QTimer(this)), connected(false),
+ titleIndex(0), progIndex(0),
++ progsInDB(0),
+ // Other state
+ curitem(NULL), delitem(NULL),
+ lastProgram(NULL),
+@@ -261,7 +263,9 @@
+ setNoErase();
+ gContext->addListener(this);
+
+- if (!recGroupPassword.isEmpty() || (titleList.count() <= 1) || initialFilt)
++ if ((!recGroupPassword.isEmpty()) ||
++ ((titleList.count() <= 1) && (progsInDB > 0)) ||
++ (initialFilt))
+ showRecGroupChooser();
+
+ gContext->addCurrentLocation((type == Delete)? "DeleteBox":"PlaybackBox");
+@@ -890,9 +894,13 @@
+ !playingSomething)
+ {
+ QSize size = drawVideoBounds.size();
++ float saspect = ((float)size.width()) / ((float)size.height());
++ float vaspect = previewVideoNVP->GetVideoAspect();
++ size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
++ size.setHeight(((size.height() + 7) / 8) * 8);
++ size.setWidth( ((size.width() + 7) / 8) * 8);
+ const QImage &img = previewVideoNVP->GetARGBFrame(size);
+- uint xoff = max((size.width() - drawVideoBounds.width()) / 2, 0);
+- p->drawImage(drawVideoBounds.x() + xoff, drawVideoBounds.y(), img);
++ p->drawImage(drawVideoBounds.x(), drawVideoBounds.y(), img);
+ }
+
+ /* have we timed out waiting for nvp to start? */
+@@ -1380,6 +1388,7 @@
+ asCache[asKey] = p->availableStatus;
+ }
+
++ progsInDB = 0;
+ titleList.clear();
+ progLists.clear();
+ // Clear autoDelete for the "all" list since it will share the
+@@ -1402,6 +1411,7 @@
+ vector<ProgramInfo *>::iterator i = infoList->begin();
+ for ( ; i != infoList->end(); i++)
+ {
++ progsInDB++;
+ p = *i;
+ if ((((p->recgroup == recGroup) ||
+ ((recGroup == "All Programs") &&
+@@ -4129,8 +4139,7 @@
+ if (!recGroupListBox)
+ return;
+
+- QString item =
+- recGroupListBox->currentText().section('[', 0, 0).simplifyWhiteSpace();
++ QString item = recGroupListBox->currentText().section(" [", 0, 0);
+
+ if (item.left(5) == "-----")
+ {
+@@ -4147,8 +4156,7 @@
+
+ void PlaybackBox::setGroupFilter(void)
+ {
+- recGroup =
+- recGroupListBox->currentText().section('[', 0, 0).simplifyWhiteSpace();
++ recGroup = recGroupListBox->currentText().section(" [", 0, 0);
+
+ if (groupnameAsAllProg)
+ groupDisplayName = recGroup;
+Index: mythtv/programs/mythfrontend/customrecord.cpp
+===================================================================
+--- mythtv/programs/mythfrontend/customrecord.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfrontend/customrecord.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -149,7 +149,7 @@
+ m_cfrom << "";
+ m_csql << "program.stars >= 0.75 ";
+
+- m_clause->insertItem(tr("Person named in the credits"));
++ m_clause->insertItem(tr("Person named in the credits (Data Direct)"));
+ m_cfrom << ", people, credits";
+ m_csql << QString("people.name = 'Tom Hanks' \n"
+ "AND credits.person = people.person \n"
+@@ -447,8 +447,8 @@
+ else
+ {
+ MSqlQuery query(MSqlQuery::InitCon());
+- query.prepare(QString("SELECT NULL FROM program,channel %1 WHERE\n%2")
+- .arg(from).arg(desc));
++ query.prepare(QString("SELECT NULL FROM (program,channel) "
++ "%1 WHERE\n%2").arg(from).arg(desc));
+
+ if (query.exec() && query.isActive())
+ {
+Index: mythtv/programs/mythfrontend/tv_schedule.xml
+===================================================================
+--- mythtv/programs/mythfrontend/tv_schedule.xml (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfrontend/tv_schedule.xml (.../branches/release-0-19-fixes) (revision 10051)
+@@ -26,7 +26,7 @@
+ <alttext lang="CA">Guia</alttext>
+ <alttext lang="DE">EPG</alttext>
+ <alttext lang="DK">Guide</alttext>
+- <alttext lang="DK">Dagskrá</alttext>
++ <alttext lang="IS">Dagskrá</alttext>
+ <alttext lang="NL">Gids</alttext>
+ <alttext lang="SV">Guide</alttext>
+ <alttext lang="JA">ガイド</alttext>
+Index: mythtv/programs/mythfrontend/playbackbox.h
+===================================================================
+--- mythtv/programs/mythfrontend/playbackbox.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfrontend/playbackbox.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -337,6 +337,7 @@
+ int progIndex; ///< Index of selected item index on page
+ QStringList titleList; ///< list of pages
+ ProgramMap progLists; ///< lists of programs by page
++ int progsInDB; ///< total number of recordings in DB
+
+ // Play List support
+ QStringList playList; ///< list of selected items "play list"
+Index: mythtv/programs/mythfrontend/networkcontrol.cpp
+===================================================================
+--- mythtv/programs/mythfrontend/networkcontrol.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfrontend/networkcontrol.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -469,7 +469,7 @@
+ message = "NETWORK_CONTROL SEEK BACKWARD";
+ else if (tokens[2].contains(QRegExp("^\\d\\d:\\d\\d:\\d\\d$")))
+ {
+- int hours = tokens[2].left(0).toInt();
++ int hours = tokens[2].mid(0, 2).toInt();
+ int minutes = tokens[2].mid(3, 2).toInt();
+ int seconds = tokens[2].mid(6, 2).toInt();
+ message = QString("NETWORK_CONTROL SEEK POSITION %1")
+Index: mythtv/programs/mythtranscode/mpeg2fix.cpp
+===================================================================
+--- mythtv/programs/mythtranscode/mpeg2fix.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythtranscode/mpeg2fix.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1776,6 +1776,7 @@
+
+ if (vFrame.count() && (file_end || vFrame.getLast()->isSequence))
+ {
++ MPEG2frame *seqFrame;
+ if (ptsIncrement != vFrame.first()->mpeg2_seq.frame_period / 300)
+ {
+ VERBOSE(MPF_IMPORTANT,
+@@ -1786,6 +1787,11 @@
+ }
+ displayFrame->toFirst();
+
++ // since we might reorder the frames when coming out of a cutpoint
++ // me need to save the first frame here, as it is gauranteed to
++ // have a sequence header.
++ seqFrame = vFrame.current();
++
+ while (vFrame.current() != vFrame.getLast())
+ {
+ bool ptsorder_eq_dtsorder = false;
+@@ -1941,7 +1947,7 @@
+
+ if (! new_discard_state)
+ {
+- AddSequence(markedFrame, vFrame.first());
++ AddSequence(markedFrame, seqFrame);
+ RenumberFrames(frame_pos + Lreorder.at(),
+ - GetFrameNum(markedFrame));
+ }
+Index: mythtv/programs/mythcommflag/main.cpp
+===================================================================
+--- mythtv/programs/mythcommflag/main.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythcommflag/main.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -895,9 +895,6 @@
+ return COMMFLAG_EXIT_INVALID_CMDLINE;
+ }
+
+- if (queueJobInstead)
+- return QueueCommFlagJob(chanid, starttime);
+-
+ if (copyToCutlist)
+ return CopySkipListToCutList(chanid, starttime);
+
+@@ -1009,7 +1006,10 @@
+
+ if ( allRecorded )
+ {
+- FlagCommercials(chanid, starttime);
++ if (queueJobInstead)
++ QueueCommFlagJob(chanid, starttime);
++ else
++ FlagCommercials(chanid, starttime);
+ }
+ else
+ {
+@@ -1063,7 +1063,12 @@
+
+ if ((flagStatus == COMM_FLAG_NOT_FLAGGED) &&
+ (marksFound == 0))
+- FlagCommercials(chanid, starttime);
++ {
++ if (queueJobInstead)
++ QueueCommFlagJob(chanid, starttime);
++ else
++ FlagCommercials(chanid, starttime);
++ }
+ }
+ }
+ }
+Index: mythtv/programs/mythbackend/mainserver.cpp
+===================================================================
+--- mythtv/programs/mythbackend/mainserver.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/mainserver.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1919,11 +1919,8 @@
+ if (m_sched) {
+ if (table == "") m_sched->getAllPending(strList);
+ else {
+- // We need a different connection from the scheduler proper
+- // DDCon exists, although it's designed for other purposes.
+- MSqlQueryInfo dbconn = MSqlQuery::DDCon();
+- Scheduler *sched = new Scheduler(false, encoderList,
+- table, &dbconn, m_sched);
++ Scheduler *sched = new Scheduler(false, encoderList,
++ table, m_sched);
+ sched->FillRecordListFromDB(recordid);
+ sched->getAllPending(strList);
+ delete sched;
+@@ -2940,6 +2937,12 @@
+ long long ret = ft->Seek(curpos, pos, whence);
+ encodeLongLong(retlist, ret);
+ }
++ else if (command == "SET_TIMEOUT")
++ {
++ bool fast = slist[2].toInt();
++ ft->SetTimeout(fast);
++ retlist << "ok";
++ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT, QString("Unknown command: %1").arg(command));
+Index: mythtv/programs/mythbackend/scheduler.cpp
+===================================================================
+--- mythtv/programs/mythbackend/scheduler.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/scheduler.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -35,8 +35,7 @@
+ #define LOC_ERR QString("Scheduler, Error: ")
+
+ Scheduler::Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList,
+- QString recordTbl, MSqlQueryInfo *databaseConnection,
+- Scheduler *master_sched)
++ QString recordTbl, Scheduler *master_sched)
+ {
+ hasconflicts = false;
+ m_tvList = tvList;
+@@ -48,8 +47,11 @@
+ master_sched->getAllPending(&reclist);
+ }
+
+- if (databaseConnection) dbConn = *databaseConnection;
+- else dbConn = MSqlQuery::SchedCon();
++ // Only the master scheduler should use SchedCon()
++ if (runthread)
++ dbConn = MSqlQuery::SchedCon();
++ else
++ dbConn = MSqlQuery::DDCon();
+
+ recordTable = recordTbl;
+
+@@ -1136,6 +1138,10 @@
+
+ if (reschedQueue.count())
+ {
++ // We might have been inactive for a long time, so make
++ // sure our DB connection is fresh before continuing.
++ dbConn = MSqlQuery::SchedCon();
++
+ gettimeofday(&fillstart, NULL);
+ QString msg;
+ while (reschedQueue.count())
+@@ -1827,10 +1833,10 @@
+ QString query = QString(
+ "INSERT INTO recordmatch (recordid, chanid, starttime, manualid) "
+ "SELECT RECTABLE.recordid, program.chanid, program.starttime, "
+-" IF(search = %1, recordid, 0) "
+-"FROM RECTABLE, program ").arg(kManualSearch) + fromclauses[clause] + QString(
+-" INNER JOIN channel ON (channel.chanid = program.chanid) "
+-"WHERE ") + whereclauses[clause] + QString(" AND channel.visible = 1 AND "
++" IF(search = %1, recordid, 0) ").arg(kManualSearch) + QString(
++"FROM (RECTABLE, program INNER JOIN channel "
++" ON channel.chanid = program.chanid) ") + fromclauses[clause] + QString(
++" WHERE ") + whereclauses[clause] + QString(" AND channel.visible = 1 AND "
+ "((RECTABLE.type = %1 " // allrecord
+ "OR RECTABLE.type = %2 " // findonerecord
+ "OR RECTABLE.type = %3 " // finddailyrecord
+Index: mythtv/programs/mythbackend/housekeeper.cpp
+===================================================================
+--- mythtv/programs/mythbackend/housekeeper.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/housekeeper.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -138,7 +138,6 @@
+
+ while (1)
+ {
+- VERBOSE(VB_IMPORTANT, "Running HouseKeeping");
+ gContext->LogEntry("mythbackend", LP_DEBUG,
+ "Running housekeeping thread", "");
+
+Index: mythtv/programs/mythbackend/scheduler.h
+===================================================================
+--- mythtv/programs/mythbackend/scheduler.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/scheduler.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -23,8 +23,7 @@
+ {
+ public:
+ Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList,
+- QString recordTbl = "record", MSqlQueryInfo *dbConnUse = NULL,
+- Scheduler *master_sched = NULL);
++ QString recordTbl = "record", Scheduler *master_sched = NULL);
+ ~Scheduler();
+
+ void Reschedule(int recordid);
+Index: mythtv/programs/mythbackend/filetransfer.cpp
+===================================================================
+--- mythtv/programs/mythbackend/filetransfer.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/filetransfer.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -131,3 +131,9 @@
+
+ return size;
+ }
++
++void FileTransfer::SetTimeout(bool fast)
++{
++ rbuffer->SetTimeout(fast);
++}
++
+Index: mythtv/programs/mythbackend/autoexpire.cpp
+===================================================================
+--- mythtv/programs/mythbackend/autoexpire.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/autoexpire.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -291,7 +291,8 @@
+
+ if ((availFreeKB = getDiskSpace(record_file_prefix, tKB, uKB)) < 0)
+ {
+- QString msg = QString("ERROR: Could not calculate free space.");
++ QString msg = QString("ERROR: Could not calculate free space for %1.")
++ .arg(record_file_prefix);
+ VERBOSE(VB_IMPORTANT, LOC + msg);
+ gContext->LogEntry("mythbackend", LP_WARNING,
+ "Autoexpire Recording", msg);
+Index: mythtv/programs/mythbackend/filetransfer.h
+===================================================================
+--- mythtv/programs/mythbackend/filetransfer.h (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythbackend/filetransfer.h (.../branches/release-0-19-fixes) (revision 10051)
+@@ -35,6 +35,8 @@
+
+ long long GetFileSize(void);
+
++ void SetTimeout(bool fast);
++
+ private:
+ bool readthreadlive;
+ QMutex readthreadLock;
+Index: mythtv/programs/mythtv/main.cpp
+===================================================================
+--- mythtv/programs/mythtv/main.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythtv/main.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -132,6 +132,7 @@
+ ProgramInfo *pginfo = new ProgramInfo();
+ pginfo->endts = QDateTime::currentDateTime().addSecs(-180);
+ pginfo->pathname = filename;
++ pginfo->isVideo = true;
+
+ tv->Playback(pginfo);
+ }
+Index: mythtv/programs/mythfilldatabase/filldata.cpp
+===================================================================
+--- mythtv/programs/mythfilldatabase/filldata.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/programs/mythfilldatabase/filldata.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -337,7 +337,7 @@
+
+ MSqlQuery query(MSqlQuery::InitCon());
+ query.prepare("SELECT ch.chanid, nim.url "
+- "FROM channel ch, callsignnetworkmap csm "
++ "FROM (channel ch, callsignnetworkmap csm) "
+ "RIGHT JOIN networkiconmap nim ON csm.network = nim.network "
+ "WHERE ch.callsign = csm.callsign AND "
+ "(icon = :NOICON OR icon = '') AND ch.sourceid = :SOURCEID");
+@@ -2174,7 +2174,8 @@
+ 0 /*service id*/, major, minor,
+ false /*use on air guide*/, false /*hidden*/,
+ false /*hidden in guide*/,
+- freqid, localfile, (*i).tvformat))
++ freqid, localfile, (*i).tvformat,
++ (*i).xmltvid))
+ {
+ cout << "### " << endl;
+ cout << "### Channel inserted" << endl;
+@@ -3851,7 +3852,6 @@
+ VERBOSE(VB_IMPORTANT, "Failed to fetch some program info");
+ gContext->LogEntry("mythfilldatabase", LP_WARNING,
+ "Failed to fetch some program info", "");
+- return FILLDB_EXIT_DB_ERROR;
+ }
+ else
+ VERBOSE(VB_IMPORTANT, "Data fetching complete.");
+Index: mythtv/setup/backendsettings.cpp
+===================================================================
+--- mythtv/setup/backendsettings.cpp (.../tags/release-0-19) (revision 10051)
++++ mythtv/setup/backendsettings.cpp (.../branches/release-0-19-fixes) (revision 10051)
+@@ -1,6 +1,7 @@
+ #include <cstdio>
+
+ #include "backendsettings.h"
++#include "frequencies.h"
+ #include "libmyth/mythcontext.h"
+ #include "libmyth/settings.h"
+ #include <unistd.h>
+@@ -110,23 +111,10 @@
+ {
+ GlobalComboBox *gc = new GlobalComboBox("FreqTable");
+ gc->setLabel(QObject::tr("Channel frequency table"));
+- gc->addSelection("us-cable");
+- gc->addSelection("us-bcast");
+- gc->addSelection("us-cable-hrc");
+- gc->addSelection("us-cable-irc");
+- gc->addSelection("japan-bcast");
+- gc->addSelection("japan-cable");
+- gc->addSelection("europe-west");
+- gc->addSelection("europe-east");
+- gc->addSelection("italy");
+- gc->addSelection("newzealand");
+- gc->addSelection("australia");
+- gc->addSelection("ireland");
+- gc->addSelection("france");
+- gc->addSelection("china-bcast");
+- gc->addSelection("southafrica");
+- gc->addSelection("argentina");
+- gc->addSelection("australia-optus");
++
++ for (uint i = 0; chanlists[i].name; i++)
++ gc->addSelection(chanlists[i].name);
++
+ gc->setHelpText(QObject::tr("Select the appropriate frequency table for "
+ "your system. If you have an antenna, use a \"-bcast\" "
+ "frequency."));