Index: /Users/andy/Sites/wptrunk/wp-includes/theme.php
===================================================================
--- /Users/andy/Sites/wptrunk/wp-includes/theme.php	(revision 12021)
+++ /Users/andy/Sites/wptrunk/wp-includes/theme.php	(working copy)
@@ -34,8 +34,15 @@
  */
 function get_stylesheet_directory() {
 	$stylesheet = get_stylesheet();
-	$stylesheet_dir = get_theme_root() . "/$stylesheet";
-	return apply_filters('stylesheet_directory', $stylesheet_dir, $stylesheet);
+	$theme_roots = get_option( 'theme_roots' );
+
+	if ( $theme_roots[$stylesheet] )
+		add_filter( 'theme_root', create_function( '', 'return "' . WP_CONTENT_DIR . '/' . $theme_roots[$stylesheet] . '";' ) );
+
+	$theme_root = get_theme_root();
+	$stylesheet_dir = "$theme_root/$stylesheet";
+
+	return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
 }
 
 /**
@@ -47,8 +54,15 @@
  */
 function get_stylesheet_directory_uri() {
 	$stylesheet = get_stylesheet();
-	$stylesheet_dir_uri = get_theme_root_uri() . "/$stylesheet";
-	return apply_filters('stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet);
+	$theme_roots = get_option( 'theme_roots' );
+
+	if ( $theme_roots[$stylesheet] )
+		add_filter( 'theme_root_uri', create_function( '', 'return "' . content_url( $theme_roots[$stylesheet] ) . '";' ) );
+
+	$theme_root_uri = get_theme_root_uri();
+	$stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
+
+	return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
 }
 
 /**
@@ -123,8 +137,15 @@
  */
 function get_template_directory() {
 	$template = get_template();
-	$template_dir = get_theme_root() . "/$template";
-	return apply_filters('template_directory', $template_dir, $template);
+	$theme_roots = get_option( 'theme_roots' );
+
+	if ( $theme_roots[$template] )
+		add_filter( 'theme_root', create_function( '', 'return "' . WP_CONTENT_DIR . '/' . $theme_roots[$template] . '";' ) );
+
+	$theme_root = get_theme_root();
+	$template_dir = "$theme_root/$template";
+	
+	return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
 }
 
 /**
@@ -137,8 +158,15 @@
  */
 function get_template_directory_uri() {
 	$template = get_template();
-	$template_dir_uri = get_theme_root_uri() . "/$template";
-	return apply_filters('template_directory_uri', $template_dir_uri, $template);
+	$theme_roots = get_option( 'theme_roots' );
+
+	if ( $theme_roots[$template] )
+		add_filter( 'theme_root_uri', create_function( '', 'return "' . content_url( $theme_roots[$template] ) . '";' ) );
+
+	$theme_root_uri = get_theme_root_uri();
+	$template_dir_uri = "$theme_root_uri/$template";
+	
+	return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
 }
 
 /**
@@ -253,65 +281,18 @@
 	if ( isset($wp_themes) )
 		return $wp_themes;
 
-	$themes = array();
-	$wp_broken_themes = array();
-	$theme_loc = $theme_root = get_theme_root();
-	if ( '/' != WP_CONTENT_DIR ) // don't want to replace all forward slashes, see Trac #4541
-		$theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
+	/* Register wp-content/themes as a theme directory */
+	register_theme_directory( 'themes' );
 
-	// Files in wp-content/themes directory and one subdir down
-	$themes_dir = @ opendir($theme_root);
-	if ( !$themes_dir )
+	if ( !$theme_files = search_theme_directories() )
 		return false;
+	
+	asort( $theme_files );
+	
+	foreach ( (array) $theme_files as $theme_file ) {
+		$theme_root = $theme_file['theme_root'];
+		$theme_file = $theme_file['theme_file'];
 
-	while ( ($theme_dir = readdir($themes_dir)) !== false ) {
-		if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
-			if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
-				continue;
-			$stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
-			$found_stylesheet = false;
-			while ( ($theme_file = readdir($stylish_dir)) !== false ) {
-				if ( $theme_file == 'style.css' ) {
-					$theme_files[] = $theme_dir . '/' . $theme_file;
-					$found_stylesheet = true;
-					break;
-				}
-			}
-			@closedir($stylish_dir);
-			if ( !$found_stylesheet ) { // look for themes in that dir
-				$subdir = "$theme_root/$theme_dir";
-				$subdir_name = $theme_dir;
-				$theme_subdir = @ opendir( $subdir );
-				while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
-					if ( is_dir( $subdir . '/' . $theme_dir) && is_readable($subdir . '/' . $theme_dir) ) {
-						if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
-							continue;
-						$stylish_dir = @ opendir($subdir . '/' . $theme_dir);
-						$found_stylesheet = false;
-						while ( ($theme_file = readdir($stylish_dir)) !== false ) {
-							if ( $theme_file == 'style.css' ) {
-								$theme_files[] = $subdir_name . '/' . $theme_dir . '/' . $theme_file;
-								$found_stylesheet = true;
-								break;
-							}
-						}
-						@closedir($stylish_dir);
-					}
-				}
-				@closedir($theme_subdir);
-				$wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
-			}
-		}
-	}
-	if ( is_dir( $theme_dir ) )
-		@closedir( $theme_dir );
-
-	if ( !$themes_dir || !$theme_files )
-		return $themes;
-
-	sort($theme_files);
-
-	foreach ( (array) $theme_files as $theme_file ) {
 		if ( !is_readable("$theme_root/$theme_file") ) {
 			$wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
 			continue;
@@ -346,19 +327,31 @@
 			else
 				continue;
 		}
+		
+		$template = trim( $template );
 
-		$template = trim($template);
-
 		if ( !file_exists("$theme_root/$template/index.php") ) {
 			$parent_dir = dirname(dirname($theme_file));
 			if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
-				$template = "$parent_dir/$template";
+				$template = "$theme_root/$parent_dir/$template";
 			} else {
-				$wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'));
-				continue;
+				/**  
+				 * The parent theme doesn't exist in the current theme's folder or sub folder 
+				 * so lets use the theme root for the parent template. 
+				 */
+				$parent_theme_root = $theme_files[$template]['theme_root'];
+				if ( file_exists( "$parent_theme_root/$template/index.php" ) ) {
+					$template = "$parent_theme_root/$template";
+				} else {
+					$wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'));
+					continue;
+				}
+				
 			}
+		} else {
+			$template = trim( $theme_root . '/' . $template );
 		}
-
+		
 		$stylesheet_files = array();
 		$template_files = array();
 
@@ -367,28 +360,28 @@
 			while ( ($file = $stylesheet_dir->read()) !== false ) {
 				if ( !preg_match('|^\.+$|', $file) ) {
 					if ( preg_match('|\.css$|', $file) )
-						$stylesheet_files[] = "$theme_loc/$stylesheet/$file";
+						$stylesheet_files[] = "$theme_root/$stylesheet/$file";
 					elseif ( preg_match('|\.php$|', $file) )
-						$template_files[] = "$theme_loc/$stylesheet/$file";
+						$template_files[] = "$theme_root/$stylesheet/$file";
 				}
 			}
 			@ $stylesheet_dir->close();
 		}
 
-		$template_dir = @ dir("$theme_root/$template");
+		$template_dir = @ dir("$template");
 		if ( $template_dir ) {
 			while ( ($file = $template_dir->read()) !== false ) {
 				if ( preg_match('|^\.+$|', $file) )
 					continue;
 				if ( preg_match('|\.php$|', $file) ) {
-					$template_files[] = "$theme_loc/$template/$file";
-				} elseif ( is_dir("$theme_root/$template/$file") ) {
-					$template_subdir = @ dir("$theme_root/$template/$file");
+					$template_files[] = "$template/$file";
+				} elseif ( is_dir("$template/$file") ) {
+					$template_subdir = @ dir("$template/$file");
 					while ( ($subfile = $template_subdir->read()) !== false ) {
 						if ( preg_match('|^\.+$|', $subfile) )
 							continue;
 						if ( preg_match('|\.php$|', $subfile) )
-							$template_files[] = "$theme_loc/$template/$file/$subfile";
+							$template_files[] = "$template/$file/$subfile";
 					}
 					@ $template_subdir->close();
 				}
@@ -422,12 +415,16 @@
 			}
 		}
 
-		$themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => $template, 'Stylesheet' => $stylesheet, 'Template Files' => $template_files, 'Stylesheet Files' => $stylesheet_files, 'Template Dir' => $template_dir, 'Stylesheet Dir' => $stylesheet_dir, 'Status' => $theme_data['Status'], 'Screenshot' => $screenshot, 'Tags' => $theme_data['Tags']);
+		$theme_roots[$stylesheet] = str_replace( WP_CONTENT_DIR, '', $theme_root );
+		$themes[$name] = array( 'Name' => $name, 'Title' => $title, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => basename( $template ), 'Stylesheet' => $stylesheet, 'Template Files' => $template_files, 'Stylesheet Files' => $stylesheet_files, 'Template Dir' => $template_dir, 'Stylesheet Dir' => $stylesheet_dir, 'Status' => $theme_data['Status'], 'Screenshot' => $screenshot, 'Tags' => $theme_data['Tags'], 'Theme Root' => $theme_root, 'Theme Root URI' => str_replace( WP_CONTENT_DIR, content_url(), $theme_root ) );
 	}
 
-	// Resolve theme dependencies.
-	$theme_names = array_keys($themes);
+	/* Resolve theme dependencies. */
+	$theme_names = array_keys( $themes );
 
+	/* Store theme roots in the DB */
+	update_option( 'theme_roots', $theme_roots );
+
 	foreach ( (array) $theme_names as $theme_name ) {
 		$themes[$theme_name]['Parent Theme'] = '';
 		if ( $themes[$theme_name]['Stylesheet'] != $themes[$theme_name]['Template'] ) {
@@ -441,7 +438,7 @@
 	}
 
 	$wp_themes = $themes;
-
+	
 	return $themes;
 }
 
@@ -499,6 +496,111 @@
 }
 
 /**
+ * Register a directory that contains themes relative to the content directory.
+ *
+ * @since 2.9.0
+ *
+ * @return bool
+ */
+function register_theme_directory( $directory ) {
+	global $wp_theme_directories;
+	
+	/* The theme directory should be relative to the content directory */
+	$registered_directory = WP_CONTENT_DIR . '/' . $directory;
+	
+	/* If this folder does not exist, return and do not register */
+	if ( !file_exists( $registered_directory ) )
+		return false;
+	
+	$wp_theme_directories[] = $registered_directory;
+	
+	return true;
+}
+
+/**
+ * Search all registered theme directories for complete and valid themes.
+ *
+ * @since 2.9.0
+ *
+ * @return array Valid themes found
+ */
+function search_theme_directories() {
+	global $wp_theme_directories, $wp_broken_themes;
+	
+	if ( empty( $wp_theme_directories ) )
+		return false;
+
+	$theme_files = array();
+	$wp_broken_themes = array();
+
+	/* Loop the registered theme directories and extract all themes */
+	foreach ( (array) $wp_theme_directories as $theme_root ) {
+		$theme_loc = $theme_root;
+		
+		/* We don't want to replace all forward slashes, see Trac #4541 */
+		if ( '/' != WP_CONTENT_DIR ) 
+			$theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
+
+		/* Files in the root of the current theme directory and one subdir down */
+		$themes_dir = @ opendir($theme_root);
+
+		if ( !$themes_dir )
+			return false;
+
+		while ( ($theme_dir = readdir($themes_dir)) !== false ) {
+			if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
+				if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+					continue;
+
+				$stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
+				$found_stylesheet = false;
+				
+				while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+					if ( $theme_file == 'style.css' ) {
+						$theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
+						$found_stylesheet = true;
+						break;
+					}
+				}
+				@closedir($stylish_dir);
+				
+				if ( !$found_stylesheet ) { // look for themes in that dir
+					$subdir = "$theme_root/$theme_dir";
+					$subdir_name = $theme_dir;
+					$theme_subdir = @ opendir( $subdir );
+					
+					while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
+						if ( is_dir( $subdir . '/' . $theme_dir) && is_readable($subdir . '/' . $theme_dir) ) {
+							if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
+								continue;
+								
+							$stylish_dir = @ opendir($subdir . '/' . $theme_dir);
+							$found_stylesheet = false;
+							
+							while ( ($theme_file = readdir($stylish_dir)) !== false ) {
+								if ( $theme_file == 'style.css' ) {
+									$theme_files[$theme_dir] = array( 'theme_file' => $subdir_name . '/' . $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
+									$found_stylesheet = true;
+									break;
+								}
+							}
+							@closedir($stylish_dir);
+						}
+					}
+					@closedir($theme_subdir);
+					
+					$wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
+				}
+			}
+		}
+		if ( is_dir( $theme_dir ) )
+			@closedir( $theme_dir );
+	}
+	
+	return $theme_files;
+}
+
+/**
  * Retrieve path to themes directory.
  *
  * Does not have trailing slash.
Index: /Users/andy/Sites/wptrunk/wp-admin/includes/theme.php
===================================================================
--- /Users/andy/Sites/wptrunk/wp-admin/includes/theme.php	(revision 12021)
+++ /Users/andy/Sites/wptrunk/wp-admin/includes/theme.php	(working copy)
@@ -28,6 +28,8 @@
 	$ct->description = $themes[$current_theme]['Description'];
 	$ct->author = $themes[$current_theme]['Author'];
 	$ct->tags = $themes[$current_theme]['Tags'];
+	$ct->theme_root = $themes[$current_theme]['Theme Root'];
+	$ct->theme_root_uri = $themes[$current_theme]['Theme Root URI'];
 	return $ct;
 }
 
Index: /Users/andy/Sites/wptrunk/wp-admin/themes.php
===================================================================
--- /Users/andy/Sites/wptrunk/wp-admin/themes.php	(revision 12021)
+++ /Users/andy/Sites/wptrunk/wp-admin/themes.php	(working copy)
@@ -132,16 +132,16 @@
 <h3><?php _e('Current Theme'); ?></h3>
 <div id="current-theme">
 <?php if ( $ct->screenshot ) : ?>
-<img src="<?php echo content_url($ct->stylesheet_dir . '/' . $ct->screenshot); ?>" alt="<?php _e('Current theme preview'); ?>" />
+<img src="<?php echo $ct->theme_root_uri . '/' . $ct->stylesheet . '/' . $ct->screenshot; ?>" alt="<?php _e('Current theme preview'); ?>" />
 <?php endif; ?>
 <h4><?php
 	/* translators: 1: theme title, 2: theme version, 3: theme author */
 	printf(__('%1$s %2$s by %3$s'), $ct->title, $ct->version, $ct->author) ; ?></h4>
 <p class="theme-description"><?php echo $ct->description; ?></p>
 <?php if ($ct->parent_theme) { ?>
-	<p><?php printf(__('The template files are located in <code>%2$s</code>.  The stylesheet files are located in <code>%3$s</code>.  <strong>%4$s</strong> uses templates from <strong>%5$s</strong>.  Changes made to the templates will affect both themes.'), $ct->title, $ct->template_dir, $ct->stylesheet_dir, $ct->title, $ct->parent_theme); ?></p>
+	<p><?php printf(__('The template files are located in <code>%2$s</code>.  The stylesheet files are located in <code>%3$s</code>.  <strong>%4$s</strong> uses templates from <strong>%5$s</strong>.  Changes made to the templates will affect both themes.'), $ct->title, str_replace( WP_CONTENT_DIR, '', $ct->template_dir ), str_replace( WP_CONTENT_DIR, '', $ct->stylesheet_dir ), $ct->title, $ct->parent_theme); ?></p>
 <?php } else { ?>
-	<p><?php printf(__('All of this theme&#8217;s files are located in <code>%2$s</code>.'), $ct->title, $ct->template_dir, $ct->stylesheet_dir); ?></p>
+	<p><?php printf(__('All of this theme&#8217;s files are located in <code>%2$s</code>.'), $ct->title, str_replace( WP_CONTENT_DIR, '', $ct->template_dir ), str_replace( WP_CONTENT_DIR, '', $ct->stylesheet_dir ) ); ?></p>
 <?php } ?>
 <?php if ( $ct->tags ) : ?>
 <p><?php _e('Tags:'); ?> <?php echo join(', ', $ct->tags); ?></p>
@@ -203,6 +203,8 @@
 	$stylesheet_dir = $themes[$theme_name]['Stylesheet Dir'];
 	$template_dir = $themes[$theme_name]['Template Dir'];
 	$parent_theme = $themes[$theme_name]['Parent Theme'];
+	$theme_root = $themes[$theme_name]['Theme Root'];
+	$theme_root_uri = $themes[$theme_name]['Theme Root URI'];
 	$preview_link = esc_url(get_option('home') . '/');
 	if ( is_ssl() )
 		$preview_link = str_replace( 'http://', 'https://', $preview_link );
@@ -223,7 +225,7 @@
 ?>
 		<a href="<?php echo $preview_link; ?>" class="<?php echo $thickbox_class; ?> screenshot">
 <?php if ( $screenshot ) : ?>
-			<img src="<?php echo content_url($stylesheet_dir . '/' . $screenshot); ?>" alt="" />
+			<img src="<?php echo $theme_root_uri . '/' . $stylesheet . '/' . $screenshot; ?>" alt="" />
 <?php endif; ?>
 		</a>
 <h3><?php
@@ -233,9 +235,9 @@
 <span class='action-links'><?php echo $actions ?></span>
 	<?php if ($parent_theme) {
 	/* translators: 1: theme title, 2:  template dir, 3: stylesheet_dir, 4: theme title, 5: parent_theme */ ?>
-	<p><?php printf(__('The template files are located in <code>%2$s</code>.  The stylesheet files are located in <code>%3$s</code>.  <strong>%4$s</strong> uses templates from <strong>%5$s</strong>.  Changes made to the templates will affect both themes.'), $title, $template_dir, $stylesheet_dir, $title, $parent_theme); ?></p>
+	<p><?php printf(__('The template files are located in <code>%2$s</code>.  The stylesheet files are located in <code>%3$s</code>.  <strong>%4$s</strong> uses templates from <strong>%5$s</strong>.  Changes made to the templates will affect both themes.'), $title, str_replace( WP_CONTENT_DIR, '', $template_dir ), str_replace( WP_CONTENT_DIR, '', $stylesheet_dir ), $title, $parent_theme); ?></p>
 <?php } else { ?>
-	<p><?php printf(__('All of this theme&#8217;s files are located in <code>%2$s</code>.'), $title, $template_dir, $stylesheet_dir); ?></p>
+	<p><?php printf(__('All of this theme&#8217;s files are located in <code>%2$s</code>.'), $title, str_replace( WP_CONTENT_DIR, '', $template_dir ), str_replace( WP_CONTENT_DIR, '', $stylesheet_dir ) ); ?></p>
 <?php } ?>
 <?php if ( $tags ) : ?>
 <p><?php _e('Tags:'); ?> <?php echo join(', ', $tags); ?></p>
