Index: wp-admin/widgets.php
===================================================================
--- wp-admin/widgets.php	(revision 18607)
+++ wp-admin/widgets.php	(working copy)
@@ -44,6 +44,12 @@
 $help .= '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>';
 add_contextual_help($current_screen, $help);
 
+// These are the widgets grouped by sidebar
+$sidebars_widgets = wp_get_sidebars_widgets();
+
+if ( empty( $sidebars_widgets ) )
+	$sidebars_widgets = wp_get_widget_defaults();
+
 // register the inactive_widgets area as sidebar
 register_sidebar(array(
 	'name' => __('Inactive Widgets'),
@@ -55,78 +61,21 @@
 	'after_title' => '',
 ));
 
-// These are the widgets grouped by sidebar
-$sidebars_widgets = wp_get_sidebars_widgets();
-if ( empty( $sidebars_widgets ) )
-	$sidebars_widgets = wp_get_widget_defaults();
-
-// look for "lost" widgets, this has to run at least on each theme change
-function retrieve_widgets() {
-	global $wp_registered_widget_updates, $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
-
-	$_sidebars_widgets = array();
-	$sidebars = array_keys($wp_registered_sidebars);
-
-	unset( $sidebars_widgets['array_version'] );
-
-	$old = array_keys($sidebars_widgets);
-	sort($old);
-	sort($sidebars);
-
-	if ( $old == $sidebars )
-		return;
-
-	// Move the known-good ones first
-	foreach ( $sidebars as $id ) {
-		if ( array_key_exists( $id, $sidebars_widgets ) ) {
-			$_sidebars_widgets[$id] = $sidebars_widgets[$id];
-			unset($sidebars_widgets[$id], $sidebars[$id]);
-		}
+foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
+	if ( empty( $wp_registered_sidebars[ $sidebar_id ] ) ) {
+		// register the inactive_widgets area as sidebar
+		register_sidebar(array(
+			'name' => __('Orphaned Widgets'),
+			'id' => $sidebar_id,
+			'description' => '',
+			'before_widget' => '',
+			'after_widget' => '',
+			'before_title' => '',
+			'after_title' => '',
+		));
 	}
-
-	// if new theme has less sidebars than the old theme
-	if ( !empty($sidebars_widgets) ) {
-		foreach ( $sidebars_widgets as $lost => $val ) {
-			if ( is_array($val) )
-				$_sidebars_widgets['wp_inactive_widgets'] = array_merge( (array) $_sidebars_widgets['wp_inactive_widgets'], $val );
-		}
-	}
-
-	// discard invalid, theme-specific widgets from sidebars
-	$shown_widgets = array();
-	foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
-		if ( !is_array($widgets) )
-			continue;
-
-		$_widgets = array();
-		foreach ( $widgets as $widget ) {
-			if ( isset($wp_registered_widgets[$widget]) )
-				$_widgets[] = $widget;
-		}
-		$_sidebars_widgets[$sidebar] = $_widgets;
-		$shown_widgets = array_merge($shown_widgets, $_widgets);
-	}
-
-	$sidebars_widgets = $_sidebars_widgets;
-	unset($_sidebars_widgets, $_widgets);
-
-	// find hidden/lost multi-widget instances
-	$lost_widgets = array();
-	foreach ( $wp_registered_widgets as $key => $val ) {
-		if ( in_array($key, $shown_widgets, true) )
-			continue;
-
-		$number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
-
-		if ( 2 > (int) $number )
-			continue;
-
-		$lost_widgets[] = $key;
-	}
-
-	$sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
-	wp_set_sidebars_widgets($sidebars_widgets);
 }
+
 retrieve_widgets();
 
 if ( count($wp_registered_sidebars) == 1 ) {
Index: wp-includes/default-filters.php
===================================================================
--- wp-includes/default-filters.php	(revision 18607)
+++ wp-includes/default-filters.php	(working copy)
@@ -217,6 +217,7 @@
 add_action( 'wp_footer',           'wp_print_footer_scripts'                );
 add_action( 'wp_head',             'wp_shortlink_wp_head',            10, 0 );
 add_action( 'template_redirect',   'wp_shortlink_header',             11, 0 );
+add_action( 'init',                'check_theme_switched',            99    );
 
 if ( isset( $_GET['replytocom'] ) )
     add_filter( 'pre_option_blog_public', '__return_zero' );
@@ -284,4 +285,4 @@
 
 unset($filter, $action);
 
-?>
\ No newline at end of file
+?>
Index: wp-includes/theme.php
===================================================================
--- wp-includes/theme.php	(revision 18607)
+++ wp-includes/theme.php	(working copy)
@@ -1248,6 +1248,8 @@
 function switch_theme($template, $stylesheet) {
 	global $wp_theme_directories;
 
+	$old_theme = get_current_theme();
+
 	update_option('template', $template);
 	update_option('stylesheet', $stylesheet);
 	if ( count($wp_theme_directories) > 1 ) {
@@ -1260,7 +1262,8 @@
 		$default_theme_mods = (array) get_option( "mods_$theme" );
 		add_option( "theme_mods_$stylesheet", $default_theme_mods );
 	}
-	do_action('switch_theme', $theme);
+	update_option( 'theme_switched', $old_theme );
+	do_action( 'switch_theme', $theme );
 }
 
 /**
Index: wp-includes/widgets.php
===================================================================
--- wp-includes/widgets.php	(revision 18607)
+++ wp-includes/widgets.php	(working copy)
@@ -1055,30 +1055,7 @@
 				unset($_sidebars_widgets);
 
 			case 2 :
-				$sidebars = array_keys( $wp_registered_sidebars );
-				if ( !empty( $sidebars ) ) {
-					// Move the known-good ones first
-					foreach ( (array) $sidebars as $id ) {
-						if ( array_key_exists( $id, $sidebars_widgets ) ) {
-							$_sidebars_widgets[$id] = $sidebars_widgets[$id];
-							unset($sidebars_widgets[$id], $sidebars[$id]);
-						}
-					}
-
-					// move the rest to wp_inactive_widgets
-					if ( !isset($_sidebars_widgets['wp_inactive_widgets']) )
-						$_sidebars_widgets['wp_inactive_widgets'] = array();
-
-					if ( !empty($sidebars_widgets) ) {
-						foreach ( $sidebars_widgets as $lost => $val ) {
-							if ( is_array($val) )
-								$_sidebars_widgets['wp_inactive_widgets'] = array_merge( (array) $_sidebars_widgets['wp_inactive_widgets'], $val );
-						}
-					}
-
-					$sidebars_widgets = $_sidebars_widgets;
-					unset($_sidebars_widgets);
-				}
+				$sidebars_widgets = retrieve_widgets();
 		}
 	}
 
@@ -1215,3 +1192,95 @@
 function _get_widget_id_base($id) {
 	return preg_replace( '/-[0-9]+$/', '', $id );
 }
+
+function check_theme_switched() {
+	if ( false !== ( $old_theme = get_option( 'theme_switched' ) ) && !empty( $old_theme ) ) {
+		global $sidebars_widgets;
+
+		if ( ! is_array( $sidebars_widgets ) )
+			$sidebars_widgets = wp_get_sidebars_widgets();
+
+		$key = md5( $old_theme );
+		// Store widgets for 1 week so we can restore if needed
+		set_transient( 'old_widgets_' . $key, $sidebars_widgets, 604800 );
+
+		retrieve_widgets();
+		update_option( 'theme_switched', false );
+	}
+}
+// look for "lost" widgets, this has to run at least on each theme change
+function retrieve_widgets() {
+	global $wp_registered_widget_updates, $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
+
+	$key = md5( get_current_theme() );
+	if ( false !== ( $_sidebars_widgets = get_transient( "old_widgets_{$key}" ) ) ) {
+		delete_transient( "old_widgets_{$key}" );
+	} else {
+		if ( ! is_array( $sidebars_widgets ) )
+			$sidebars_widgets = wp_get_sidebars_widgets();
+
+		$sidebars = array_keys($wp_registered_sidebars);
+
+		unset( $sidebars_widgets['array_version'] );
+
+		$old = array_keys($sidebars_widgets);
+		sort($old);
+		sort($sidebars);
+
+		if ( $old == $sidebars )
+			return;
+
+
+		$_sidebars_widgets = array(
+			'wp_inactive_widgets' => $sidebars_widgets['wp_inactive_widgets']
+		);
+		unset( $sidebars_widgets['wp_inactive_widgets'] );
+		foreach ( $wp_registered_sidebars as $id => $settings ) {
+			if ( ! empty( $sidebars_widgets ) )
+				$_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
+		}
+		if ( !empty($sidebars_widgets) ) {
+			foreach ( $sidebars_widgets as $poor_lost_puppy => $val ) {
+				if ( is_array($val) ) {
+					$_sidebars_widgets[$poor_lost_puppy] = $val;
+				}
+			}
+		}
+	}
+
+	// discard invalid, theme-specific widgets from sidebars
+	$shown_widgets = array();
+	foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
+		if ( !is_array($widgets) )
+			continue;
+
+		$_widgets = array();
+		foreach ( $widgets as $widget ) {
+			if ( isset($wp_registered_widgets[$widget]) )
+				$_widgets[] = $widget;
+		}
+		$_sidebars_widgets[$sidebar] = $_widgets;
+		$shown_widgets = array_merge($shown_widgets, $_widgets);
+	}
+
+	$sidebars_widgets = $_sidebars_widgets;
+	unset($_sidebars_widgets, $_widgets);
+
+	// find hidden/lost multi-widget instances
+	$lost_widgets = array();
+	foreach ( $wp_registered_widgets as $key => $val ) {
+		if ( in_array($key, $shown_widgets, true) )
+			continue;
+
+		$number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
+
+		if ( 2 > (int) $number )
+			continue;
+
+		$lost_widgets[] = $key;
+	}
+
+	$sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
+	wp_set_sidebars_widgets($sidebars_widgets);
+	return $sidebars_widgets;
+}
