=== modified file 'includes/theme.inc'
--- includes/theme.inc	2009-11-20 04:29:42 +0000
+++ includes/theme.inc	2009-11-22 22:29:31 +0000
@@ -1243,6 +1243,78 @@ function theme_render_template($template
 }
 
 /**
+ * Enable a given list of themes.
+ *
+ * @param $theme_list
+ *   An array of theme names.
+ */
+function theme_enable($theme_list) {
+  drupal_clear_css_cache();
+
+  foreach ($theme_list as $key) {
+    db_update('system')
+      ->fields(array('status' => 1))
+      ->condition('type', 'theme')
+      ->condition('name', $key)
+      ->execute();
+  }
+
+  list_themes(TRUE);
+  menu_rebuild();
+  drupal_theme_rebuild();
+
+  // Notify locale module about new themes being enabled, so translations can
+  // be imported. This might start a batch, and only return to the redirect
+  // path after that.
+  module_invoke('locale', 'system_update', $theme_list);
+
+  // Invoke hook_themes_enabled after the themes have been enabled.
+  module_invoke_all('themes_enabled', $theme_list);
+
+  return;
+}
+
+/**
+ * Disable a given list of themes.
+ *
+ * @param $theme_list
+ *   An array of theme names.
+ */
+function theme_disable($theme_list) {
+  // Don't disable the default theme.
+  if ($pos = array_search(variable_get('theme_default', 'garland'), $theme_list) !== FALSE) {
+    unset($theme_list[$pos]);
+    if (empty($theme_list)) {
+      return;
+    }
+  }
+
+  // If the admin theme is disabled, turn off the setting.
+  if (in_array(variable_get('admin_theme', 0), $theme_list)) {
+    variable_del('admin_theme');
+  }
+
+  drupal_clear_css_cache();
+
+  foreach ($theme_list as $key) {
+    db_update('system')
+      ->fields(array('status' => 0))
+      ->condition('type', 'theme')
+      ->condition('name', $key)
+      ->execute();
+  }
+
+  list_themes(TRUE);
+  menu_rebuild();
+  drupal_theme_rebuild();
+
+  // Invoke hook_themes_enabled after the themes have been enabled.
+  module_invoke_all('themes_disabled', $theme_list);
+
+  return;
+}
+
+/**
  * @defgroup themeable Default theme implementations
  * @{
  * Functions and templates that present output to the user, and can be

=== modified file 'modules/block/block.module'
--- modules/block/block.module	2009-11-22 21:24:37 +0000
+++ modules/block/block.module	2009-11-22 22:29:31 +0000
@@ -497,34 +497,11 @@ function block_form_user_profile_form_al
 }
 
 /**
- * Implement hook_form_FORM_ID_alter().
- */
-function block_form_system_themes_form_alter(&$form, &$form_state) {
-  // This function needs to fire before the theme changes are recorded in the
-  // database, otherwise it will populate the default list of blocks from the
-  // new theme, which is empty.
-  array_unshift($form['#submit'], 'block_system_themes_form_submit');
-}
-
-/**
  * Initialize blocks for enabled themes.
  */
-function block_system_themes_form_submit(&$form, &$form_state) {
-  if ($form_state['values']['op'] == t('Save configuration')) {
-    if (is_array($form_state['values']['status'])) {
-      foreach ($form_state['values']['status'] as $key => $choice) {
-        if ($choice || $form_state['values']['theme_default'] == $key) {
-          block_theme_initialize($key);
-        }
-      }
-    }
-    if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] !== variable_get('admin_theme', 0)) {
-      // If we're changing themes, make sure the theme has its blocks initialized.
-      $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', 0, 1, array(':theme' => $form_state['values']['admin_theme']))->fetchField();
-      if (!$has_blocks) {
-        block_theme_initialize($form_state['values']['admin_theme']);
-      }
-    }
+function block_themes_enabled($theme_list) {
+  foreach ($theme_list as $theme) {
+    block_theme_initialize($theme);
   }
 }
 

=== modified file 'modules/system/system-rtl.css'
--- modules/system/system-rtl.css	2009-08-24 03:11:34 +0000
+++ modules/system/system-rtl.css	2009-11-11 13:10:31 +0000
@@ -90,6 +90,28 @@ input.password-confirm {
   margin-left: 10px;
   margin-right: 0;
 }
+
+.system-themes-list-enabled .theme-selector .screenshot {
+  float: right;
+  margin: 0 0 0 20px;
+}
+.system-themes-list-disabled .theme-selector {
+  float: right;
+  padding: 20px 0 20px 20px;
+}
+.theme-selector .operations li {
+  float: right;
+  border-right: none;
+  border-left: 1px solid #cdcdcd;
+}
+.theme-selector .operations li.last {
+  padding: 0 0.7em 0 0;
+  border-left: none;
+}
+.theme-selector .operations li.first {
+  padding: 0 0 0 0.7em;
+}
+
 .password-strength-title {
   float: right;
 }

=== modified file 'modules/system/system.admin.inc'
--- modules/system/system.admin.inc	2009-11-22 18:42:55 +0000
+++ modules/system/system.admin.inc	2009-11-23 14:05:39 +0000
@@ -192,12 +192,9 @@ function system_settings_overview() {
 }
 
 /**
- * Menu callback; displays a listing of all themes.
- *
- * @ingroup forms
- * @see system_themes_form_submit()
+ * Retrieve the list of themes that are not hidden.
  */
-function system_themes_form() {
+function _system_theme_list() {
   // Get current list of themes.
   $themes = system_rebuild_theme_data();
 
@@ -209,13 +206,26 @@ function system_themes_form() {
   }
 
   uasort($themes, 'system_sort_modules_by_info_name');
+  return $themes;
+}
+
+/**
+ * Menu callback; displays a listing of all themes.
+ */
+function system_themes_page() {
+  // Get current list of themes.
+  $themes =& _system_theme_list();
 
-  $status = array();
-  $incompatible_core = array();
-  $incompatible_php = array();
+  $theme_default = variable_get('theme_default', 'garland');
+  $theme_groups  = array();
 
-  foreach ($themes as $theme) {
-    $screenshot = NULL;
+  foreach ($themes as &$theme) {
+
+    $admin_theme_options[$theme->name] = $theme->info['name'];
+    $theme->is_default = ($theme->name == $theme_default);
+
+    // Identify theme screenshot.
+    $theme->screenshot = NULL;
     // Create a list which includes the current theme and all its base themes.
     if (isset($themes[$theme->name]->base_themes)) {
       $theme_keys = array_keys($themes[$theme->name]->base_themes);
@@ -227,50 +237,61 @@ function system_themes_form() {
     // Look for a screenshot in the current theme or in its closest ancestor.
     foreach (array_reverse($theme_keys) as $theme_key) {
       if (isset($themes[$theme_key]) && file_exists($themes[$theme_key]->info['screenshot'])) {
-        $screenshot = $themes[$theme_key]->info['screenshot'];
+        $theme->screenshot = $themes[$theme_key]->info['screenshot'];
         break;
       }
     }
-    $screenshot = $screenshot ? theme('image', array('path' => $screenshot, 'alt' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])), 'title' => '', 'attributes' => array('class' => array('screenshot')), 'getsize' => FALSE)) : t('no screenshot');
 
-    $form[$theme->name]['screenshot'] = array('#markup' => $screenshot);
-    $form[$theme->name]['info'] = array(
-      '#type' => 'value',
-      '#value' => $theme->info,
-    );
-    $options[$theme->name] = $theme->info['name'];
-
-    $form[$theme->name]['operations'] = drupal_theme_access($theme) ? array('#type' => 'link', '#title' => t('configure'), '#href' => 'admin/appearance/settings/' . $theme->name) : array();
-
-    if (!empty($theme->status)) {
-      $status[] = $theme->name;
+    if (drupal_theme_access($theme)) {
+      $theme->operations = array(
+        l(t('Configure'), 'admin/appearance/settings/' . $theme->name),
+      );
+      if (!$theme->is_default) {
+        $theme->operations[] = l(t('Disable'), 'admin/appearance/disable', array('query' => array('theme' => $theme->name)));
+        $theme->operations[] = l(t('Set default'), 'admin/appearance/default', array('query' => array('theme' => $theme->name)));
+      }
     }
     else {
-      // Ensure this theme is compatible with this version of core.
-      // Require the 'content' region to make sure the main page
-      // content has a common place in all themes.
-      if (!isset($theme->info['core']) || ($theme->info['core'] != DRUPAL_CORE_COMPATIBILITY) || (!isset($theme->info['regions']['content']))) {
-        $incompatible_core[] = $theme->name;
-      }
-      if (version_compare(phpversion(), $theme->info['php']) < 0) {
-        $incompatible_php[$theme->name] = $theme->info['php'];
-      }
+      $theme->operations = array(
+        l(t('Enable'), 'admin/appearance/enable', array('query' => array('theme' => $theme->name))),
+        l(t('Set default'), 'admin/appearance/default', array('query' => array('theme' => $theme->name))),
+      );
+    }
+
+    if (empty($theme->status)) {
+     // Ensure this theme is compatible with this version of core.
+     // Require the 'content' region to make sure the main page
+     // content has a common place in all themes.
+      $theme->incompatible_core = !isset($theme->info['core']) || ($theme->info['core'] != DRUPAL_CORE_COMPATIBILITY) || (!isset($theme->info['regions']['content']));
+      $theme->incompatible_php = version_compare(phpversion(), $theme->info['php']) < 0;
     }
+
+    // Add notes to default and administration theme.
+    $theme->notes = array();
+    $theme->classes = array();
+    if ($theme->is_default) {
+      $theme->classes[] = 'theme-default';
+      $theme->notes[] = t('default theme');
+    }
+
+    // Sort enabled and disabled themes into their own groups.
+    $theme_groups[$theme->status ? 'enabled' : 'disabled'][] = $theme;
   }
 
-  $form['status'] = array(
-    '#type' => 'checkboxes',
-    '#options' => array_fill_keys(array_keys($options), ''),
-    '#default_value' => $status,
-    '#incompatible_themes_core' => drupal_map_assoc($incompatible_core),
-    '#incompatible_themes_php' => $incompatible_php,
-  );
-  $form['theme_default'] = array(
-    '#type' => 'radios',
-    '#options' => array_fill_keys(array_keys($options), ''),
-    '#default_value' => variable_get('theme_default', 'garland'),
-  );
+  uasort($theme_groups['enabled'], 'system_sort_themes');
+  drupal_alter('system_themes_page', $theme_groups);
+
+  $admin_form = drupal_get_form('system_themes_admin_form', $admin_theme_options);
+  return theme('system_themes_page', array('theme_groups' => $theme_groups)) . drupal_render($admin_form);
+}
 
+/**
+ * Form to select the administration theme.
+ *
+ * @ingroup forms
+ * @see system_themes_admin_form_submit()
+ */
+function system_themes_admin_form($form, &$form_state, $theme_options) {
   // Administration theme settings.
   $form['admin_theme'] = array(
     '#type' => 'fieldset',
@@ -280,7 +301,7 @@ function system_themes_form() {
   );
   $form['admin_theme']['admin_theme'] = array(
     '#type' => 'select',
-    '#options' => array(0 => t('Default theme')) + $options,
+    '#options' => array(0 => t('Default theme')) + $theme_options,
     '#title' => t('Administration theme'),
     '#description' => t('Choose "Default theme" to always use the same theme as the rest of the site.'),
     '#default_value' => variable_get('admin_theme', 0),
@@ -290,84 +311,158 @@ function system_themes_form() {
     '#title' => t('Use the administration theme when editing or creating content'),
     '#default_value' => variable_get('node_admin_theme', '0'),
   );
-
-  $form['buttons']['submit'] = array(
+  $form['admin_theme']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save configuration'),
   );
-
   return $form;
 }
 
 /**
- * Process system_themes_form form submissions.
+ * Process system_themes_admin_form form submissions.
  */
-function system_themes_form_submit($form, &$form_state) {
-  drupal_clear_css_cache();
+function system_themes_admin_form_submit($form, &$form_state) {
+  drupal_set_message(t('The configuration options have been saved.'));
+  variable_set('admin_theme', $form_state['values']['admin_theme']);
+  variable_set('node_admin_theme', $form_state['values']['node_admin_theme']);
+}
+
+/**
+ * Form to enable a theme.
+ *
+ * @ingroup forms
+ * @see system_theme_enable_form_submit()
+ */
+function system_theme_enable_form($form, &$form_state) {
+  // Get current list of themes.
+  $themes =& _system_theme_list();
 
-  // Store list of previously enabled themes and disable all themes
-  $old_theme_list = $new_theme_list = array();
-  foreach (list_themes() as $theme) {
-    if ($theme->status) {
-      $old_theme_list[] = $theme->name;
+  foreach ($themes as $theme) {
+    // Only allow disabled themes to be enabled.
+    if (empty($theme->status)) {
+      $options[$theme->name] = $theme->info['name'];
     }
   }
-  db_update('system')
-    ->fields(array('status' => 0))
-    ->condition('type', 'theme')
-    ->execute();
 
-  if ($form_state['values']['op'] == t('Save configuration')) {
-    if (is_array($form_state['values']['status'])) {
-      foreach ($form_state['values']['status'] as $key => $choice) {
-        // Always enable the default theme, despite its status checkbox being checked:
-        if ($choice || $form_state['values']['theme_default'] == $key) {
-          $new_theme_list[] = $key;
-          db_update('system')
-            ->fields(array('status' => 1))
-            ->condition('type', 'theme')
-            ->condition('name', $key)
-            ->execute();
-        }
-      }
-    }
-    if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != $form_state['values']['theme_default']) {
-      drupal_set_message(t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', array(
-        '%admin_theme' => $form_state['values']['admin_theme'],
-        '%selected_theme' => $form_state['values']['theme_default'],
-      )));
-    }
+  // We normally submit this form via a link with GET variables.
+  $form['#method'] = 'get';
+  $form['#redirect'] = 'admin/appearance';
+  $form['theme'] = array(
+    '#title' => t('Select a theme to enable'),
+    '#type' => 'select',
+    '#options' => array(0 => t('- Please choose -')) + $options,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+  return $form;
+}
 
-    // Save the variables.
-    variable_set('theme_default', $form_state['values']['theme_default']);
-    variable_set('admin_theme', $form_state['values']['admin_theme']);
-    variable_set('node_admin_theme', $form_state['values']['node_admin_theme']);
-  }
-  else {
-    // Revert to defaults: only Garland is enabled.
-    variable_del('theme_default');
-    variable_del('admin_theme');
-    variable_del('node_admin_theme');
-    db_update('system')
-      ->fields(array('status' => 1))
-      ->condition('type', 'theme')
-      ->condition('name', 'garland')
-      ->execute();
-    $new_theme_list = array('garland');
+/**
+ * Process system_theme_enable_form form submissions.
+ */
+function system_theme_enable_form_submit($form, &$form_state) {
+  drupal_set_message(t('The configuration options have been saved.'));
+}
+
+/**
+ * Form to disable a theme.
+ *
+ * @ingroup forms
+ * @see system_theme_disable_form_submit()
+ */
+function system_theme_disable_form($form, &$form_state) {
+  // Get current list of themes.
+  $themes =& _system_theme_list();
+
+  $theme_default = variable_get('theme_default', 'garland');
+  foreach ($themes as $theme) {
+    // Only allow enabled themes that aren't the default theme to be disabled.
+    if (!empty($theme->status) && $theme->name != $theme_default) {
+      $options[$theme->name] = $theme->info['name'];
+    }
   }
 
-  list_themes(TRUE);
-  menu_rebuild();
-  drupal_theme_rebuild();
+  // We normally submit this form via a link with GET variables.
+  $form['#method'] = 'get';
+  $form['#redirect'] = 'admin/appearance';
+  $form['theme'] = array(
+    '#title' => t('Select a theme to disable'),
+    '#type' => 'select',
+    '#options' => array(0 => t('- Please choose -')) + $options,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+  return $form;
+}
+
+/**
+ * Process system_theme_disable_form form submissions.
+ */
+function system_theme_disable_form_submit($form, &$form_state) {
+dsm($form_state);
+  $theme_default = variable_get('theme_default', 'garland');
   drupal_set_message(t('The configuration options have been saved.'));
-  $form_state['redirect'] = 'admin/appearance';
+}
 
-  // Notify locale module about new themes being enabled, so translations can
-  // be imported. This might start a batch, and only return to the redirect
-  // path after that.
-  module_invoke('locale', 'system_update', array_diff($new_theme_list, $old_theme_list));
+/**
+ * Form to select the default theme.
+ *
+ * @ingroup forms
+ * @see system_theme_default_form_submit()
+ */
+function system_theme_default_form($form, &$form_state) {
+  // Get current list of themes.
+  $themes =& _system_theme_list();
 
-  return;
+  foreach ($themes as $theme) {
+    $options[$theme->name] = $theme->info['name'];
+  }
+
+  // We normally submit this form via a link with GET variables.
+  $form['#method'] = 'get';
+  $form['#redirect'] = 'admin/appearance';
+  $form['theme'] = array(
+    '#title' => t('Select a theme to set as the default'),
+    '#type' => 'select',
+    '#options' => array(0 => t('- Please choose -')) + $options,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+  return $form;
+}
+
+/**
+ * Process system_theme_default_form form submissions.
+ */
+function system_theme_default_form_submit($form, &$form_state) {
+  // Get current list of themes.
+  $themes =& _system_theme_list();
+
+  $theme = $form['theme'];
+
+  // Enable the theme if it is currently disabled.
+  if (empty($themes[$theme]->status)) {
+    theme_enable(array($theme));
+  }
+
+  $admin_theme = variable_get('admin_theme', 0);
+  if ($admin_theme != $theme) {
+    drupal_set_message(t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', array(
+      '%admin_theme' => $admin_theme,
+      '%selected_theme' => $theme,
+    )));
+  }
+  else {
+    drupal_set_message(t('The configuration options have been saved.'));
+  }
+
+  variable_set('theme_default', $theme);
 }
 
 /**
@@ -803,6 +898,19 @@ function system_sort_modules_by_info_nam
 }
 
 /**
+ * Array sorting callback; sorts modules or themes by their name.
+ */
+function system_sort_themes($a, $b) {
+  if ($a->is_default) {
+    return -1;
+  }
+  if ($b->is_default) {
+    return 1;
+  }
+  return strcasecmp($a->info['name'], $b->info['name']);
+}
+
+/**
  * Build a table row for the system modules page.
  */
 function _system_modules_build_row($info, $extra) {
@@ -2418,61 +2526,58 @@ function theme_system_modules_uninstall(
  *
  * @param $variables
  *   An associative array containing:
- *   - form: An associative array containing the structure of the form.
+ *   - theme_groups: An associative array containing groups of themes.
  *
  * @ingroup themeable
  */
-function theme_system_themes_form($variables) {
-  $form = $variables['form'];
+function theme_system_themes_page($variables) {
+  $theme_groups = $variables['theme_groups'];
 
-  foreach (element_children($form) as $key) {
-    // Only look for themes
-    if (!isset($form[$key]['info'])) {
+  $output = '<div id="system-themes-page">';
+
+  // There are two possible theme groups.
+  $states = array(
+    'enabled' => format_plural(count($theme_groups['enabled']), 'Enabled theme', 'Enabled themes'),
+    'disabled' => format_plural(count($theme_groups['disabled']), 'Disabled theme', 'Disabled themes'),
+  );
+
+  foreach ($states as $state => $title) {
+    if (!count($theme_groups[$state])) {
+      // Skip this group of themes if no theme is there.
       continue;
     }
+    // Start new theme group.
+    $output .= '<div class="system-themes-list system-themes-list-'. $state .'"><h2>'. $title .'</h2>';
 
-    // Fetch info
-    $info = $form[$key]['info']['#value'];
-    // Localize theme description.
-    $description = t($info['description']);
-    // Make sure it is compatible and render the checkbox if so.
-    if (isset($form['status']['#incompatible_themes_core'][$key])) {
-      unset($form['status'][$key]);
-      $status = theme('image', array('path' => 'misc/watchdog-error.png', 'alt' => t('incompatible'), 'title' => t('Incompatible with this version of Drupal core')));
-      $description .= '<div class="incompatible">' . t('This version is incompatible with the !core_version version of Drupal core.', array('!core_version' => VERSION)) . '</div>';
-    }
-    elseif (isset($form['status']['#incompatible_themes_php'][$key])) {
-      unset($form['status'][$key]);
-      $status = theme('image', array('path' => 'misc/watchdog-error.png', 'alt' => t('incompatible'), 'title' => t('Incompatible with this version of PHP')));
-      $php_required = $form['status']['#incompatible_themes_php'][$key];
-      if (substr_count($php_required, '.') < 2) {
-        $php_required .= '.*';
-      }
-      $description .= '<div class="incompatible">' . t('This theme requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $php_required, '!php_version' => phpversion())) . '</div>';
-    }
-    else {
-      $status = drupal_render($form['status'][$key]);
-    }
+    foreach($theme_groups[$state] as $theme) {
 
-    // Style theme info
-    $theme = '<div class="theme-info"><h2>' . $info['name'] . '</h2><div class="description">' . $description . '</div></div>';
+      // Theme the screenshot.
+      $screenshot = $theme->screenshot ? theme('image', array('path' => $theme->screenshot, 'alt' => t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])), 'title' => '', 'attributes' => array('class' => array('screenshot')), 'getsize' => FALSE)) : t('no screenshot');
 
-    // Build rows
-    $row = array();
-    $row[] = drupal_render($form[$key]['screenshot']);
-    $row[] = $theme;
-    $row[] = isset($info['version']) ? $info['version'] : '';
-    $row[] = array('data' => $status, 'align' => 'center');
-    if ($form['theme_default']) {
-      $row[] = array('data' => drupal_render($form['theme_default'][$key]), 'align' => 'center');
-      $row[] = array('data' => drupal_render($form[$key]['operations']), 'align' => 'center');
+      // Localize the theme description.
+      $description = t($theme->info['description']);
+
+      // Make sure to provide feedback on compatibility.
+      if (!empty($theme->incompatible_core)) {
+        $description .= '<div class="incompatible">' . t('This version is incompatible with the !core_version version of Drupal core.', array('!core_version' => VERSION)) . '</div>';
+      }
+      elseif (!empty($theme->incompatible_php)) {
+        if (substr_count($theme->info['php'], '.') < 2) {
+          $theme->info['php'] .= '.*';
+        }
+        $description .= '<div class="incompatible">' . t('This theme requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $theme->info['php'], '!php_version' => phpversion())) . '</div>';
+      }
+
+      // Style theme info
+      $notes = count($theme->notes) ? ' (' . join(', ', $theme->notes) . ')' : '';
+      $theme->classes[] = 'theme-selector';
+      $theme->classes[] = 'clearfix';
+      $output .= '<div class="'. join(' ', $theme->classes) .'">' . $screenshot . '<div class="theme-info"><h3>' . $theme->info['name'] . ' ' . (isset($theme->info['version']) ? $theme->info['version'] : '') . $notes . '</h3><div class="description">' . $description . '</div><div class="operations clearfix">' . theme('item_list', array('items' => $theme->operations)) . '</div></div></div>';
     }
-    $rows[] = $row;
+    $output .= '</div>';
   }
+  $output .= '</div>';
 
-  $header = array(t('Screenshot'), t('Name'), t('Version'), t('Enabled'), t('Default'), t('Operations'));
-  $output = theme('table', array('header' => $header, 'rows' => $rows));
-  $output .= drupal_render_children($form);
   return $output;
 }
 

=== modified file 'modules/system/system.api.php'
--- modules/system/system.api.php	2009-11-15 08:48:39 +0000
+++ modules/system/system.api.php	2009-11-23 09:12:08 +0000
@@ -2673,6 +2673,23 @@ function hook_page_delivery_callback_alt
 }
 
 /**
+ * Alters theme operation links.
+ *
+ * @param $theme_groups
+ *   An associative array containing groups of themes.
+ *
+ * @see system_themes_page()
+ */
+function hook_system_themes_page_alter(&$theme_groups) {
+  foreach ($theme_groups as $state => &$group) {
+    foreach($theme_groups[$state] as &$theme) {
+      // Add a foo link to each list of theme operations.
+      $theme->operations[] = l(t('Foo'), 'admin/appearance/foo', array('query' => array('theme' => $theme->name)));
+    }
+  }
+}
+
+/**
  * Alters inbound URL requests.
  *
  * @param $path

=== modified file 'modules/system/system.css'
--- modules/system/system.css	2009-11-22 03:03:24 +0000
+++ modules/system/system.css	2009-11-22 22:29:31 +0000
@@ -522,9 +522,61 @@ html.js .js-hide {
 /*
 ** Styles for the system themes page (admin/appearance)
 */
-#system-themes-form div.incompatible {
+.system-themes-list {
+  margin-bottom: 1em;
+}
+.system-themes-list-disabled {
+  border-top: 1px solid #cdcdcd;
+  padding-top: 1em;
+}
+.theme-selector {
+  padding-top: 20px;
+}
+.theme-selector .screenshot {
+  border: 1px solid #e0e0d8;
+  padding: 2px;
+}
+.theme-default .screenshot {
+  border: 1px solid #aaa;
+}
+.theme-selector h3 {
+  font-weight: normal;
+}
+.theme-default h3 {
   font-weight: bold;
 }
+.system-themes-list-enabled .theme-selector .screenshot {
+  float: left; /* LTR */
+  margin: 0 20px 0 0; /* LTR */
+}
+.system-themes-list-enabled .theme-selector h3 {
+  margin-top: 0;
+}
+.system-themes-list-disabled .theme-selector {
+  width: 300px;
+  float: left; /* LTR */
+  padding: 20px 20px 20px 0; /* LTR */
+}
+.theme-selector .operations {
+  margin-top: 1em;
+}
+.theme-selector .operations li {
+  float: left; /* LTR */
+  margin: 0;
+  padding: 0 0.7em;
+  list-style-type: none;
+  border-right: 1px solid #cdcdcd;  /* LTR */
+}
+.theme-selector .operations li.last {
+  padding: 0 0 0 0.7em; /* LTR */
+  border-right: none; /* LTR */
+}
+.theme-selector .operations li.first {
+  padding: 0 0.7em 0 0; /* LTR */
+}
+#system-themes-admin-form {
+  clear: left;
+}
 
 /*
 ** Password strength indicator

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2009-11-22 01:33:45 +0000
+++ modules/system/system.module	2009-11-23 14:14:30 +0000
@@ -133,8 +133,8 @@ function system_help($path, $arg) {
  */
 function system_theme() {
   return array_merge(drupal_common_theme(), array(
-    'system_themes_form' => array(
-      'render element' => 'form',
+    'system_themes_page' => array(
+      'variables' => array('theme_groups' => NULL),
       'file' => 'system.admin.inc',
     ),
     'system_settings_form' => array(
@@ -581,23 +581,47 @@ function system_menu() {
   $items['admin/appearance'] = array(
     'title' => 'Appearance',
     'description' => 'Select and configure your site theme.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('system_themes_form'),
+    'page callback' => 'system_themes_page',
     'access arguments' => array('administer site configuration'),
     'position' => 'left',
     'weight' => -6,
     'file' => 'system.admin.inc',
   );
-  $items['admin/appearance/select'] = array(
+  $items['admin/appearance/list'] = array(
     'title' => 'List',
-    'description' => 'Select the default theme for your site.',
+    'description' => 'Select and configure your site theme.',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'weight' => -1,
     'file' => 'system.admin.inc',
   );
+  $items['admin/appearance/enable'] = array(
+    'title' => 'Enable theme',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_theme_enable_form'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/appearance/disable'] = array(
+    'title' => 'Disable theme',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_theme_disable_form'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
+  $items['admin/appearance/default'] = array(
+    'title' => 'Set default theme',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_theme_default_form'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_CALLBACK,
+    'file' => 'system.admin.inc',
+  );
   $items['admin/appearance/settings'] = array(
     'title' => 'Configure',
     'description' => 'Configure default and theme specific settings.',
+    'page callback' => 'drupal_get_form',
     'page arguments' => array('system_theme_settings'),
     'access arguments' => array('administer site configuration'),
     'type' => MENU_LOCAL_TASK,

=== modified file 'modules/update/update.module'
--- modules/update/update.module	2009-10-25 19:52:47 +0000
+++ modules/update/update.module	2009-11-09 11:54:50 +0000
@@ -396,22 +396,30 @@ function update_cron() {
 }
 
 /**
- * Implement hook_form_FORM_ID_alter().
+ * Implement hook_themes_enabled().
  *
- * Adds a submit handler to the system modules and themes forms, so that if a
- * site admin saves either form, we invalidate the cache of available updates.
+ * If themes are enabled, we invalidate the cache of available updates.
+ */
+function update_themes_enabled($themes) {
+  // Clear all update module caches.
+  _update_cache_clear();
+}
+
+/**
+ * Implement hook_themes_disabled().
  *
- * @see _update_cache_clear()
+ * If themes are disabled, we invalidate the cache of available updates.
  */
-function update_form_system_themes_form_alter(&$form, $form_state) {
-  $form['#submit'][] = 'update_cache_clear_submit';
+function update_themes_disabled($themes) {
+  // Clear all update module caches.
+  _update_cache_clear();
 }
 
 /**
  * Implement hook_form_FORM_ID_alter().
  *
- * Adds a submit handler to the system modules and themes forms, so that if a
- * site admin saves either form, we invalidate the cache of available updates.
+ * Adds a submit handler to the system modules form, so that if a site admin
+ * saves the form, we invalidate the cache of available updates.
  *
  * @see _update_cache_clear()
  */

=== modified file 'themes/garland/minnelli/screenshot.png'
Binary files themes/garland/minnelli/screenshot.png	2006-10-29 13:17:37 +0000 and themes/garland/minnelli/screenshot.png	2009-11-09 12:03:53 +0000 differ

=== modified file 'themes/garland/screenshot.png'
Binary files themes/garland/screenshot.png	2006-10-29 13:17:37 +0000 and themes/garland/screenshot.png	2009-11-09 12:04:10 +0000 differ

=== modified file 'themes/seven/screenshot.png'
Binary files themes/seven/screenshot.png	2009-08-03 23:34:57 +0000 and themes/seven/screenshot.png	2009-11-09 12:03:30 +0000 differ

=== modified file 'themes/seven/style.css'
--- themes/seven/style.css	2009-11-23 01:41:43 +0000
+++ themes/seven/style.css	2009-11-23 03:54:45 +0000
@@ -716,6 +716,21 @@ div.admin-panel {
   display: block;
 }
 
+/* admin/appearance */
+#block-system-main #system-themes-page h2 {
+  font-weight: normal;
+  text-transform: uppercase;
+}
+#block-system-main .theme-selector h3 {
+  font-weight: normal;
+}
+#block-system-main .theme-default h3 {
+  font-weight: bold;
+}
+#block-system-main .system-themes-list-enabled .theme-selector h3 {
+  margin-top: 0;
+}
+
 /* admin/content and admin/people */
 #block-system-main dl.multiselect,
 #block-system-main dl.multiselect dt,

=== modified file 'themes/stark/screenshot.png'
Binary files themes/stark/screenshot.png	2009-01-30 23:06:23 +0000 and themes/stark/screenshot.png	2009-11-09 12:03:08 +0000 differ

