Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.992
diff -u -p -r1.992 common.inc
--- includes/common.inc	18 Sep 2009 10:54:20 -0000	1.992
+++ includes/common.inc	21 Sep 2009 03:16:15 -0000
@@ -3763,7 +3763,10 @@ function _drupal_bootstrap_full() {
     ini_set('log_errors', 1);
     ini_set('error_log', file_directory_path() . '/error.log');
   }
-
+  // Set a custom theme for the current page, if there is one. We need to run
+  // this before invoking hook_init(), since any modules which initialize the
+  // theme system will prevent a custom theme from being correctly set later.
+  menu_set_custom_theme();
   // Let all modules take action before menu system handles the request
   // We do not want this while running update.php.
   if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.346
diff -u -p -r1.346 menu.inc
--- includes/menu.inc	18 Sep 2009 10:54:20 -0000	1.346
+++ includes/menu.inc	21 Sep 2009 03:16:15 -0000
@@ -359,8 +359,9 @@ function menu_set_item($path, $router_it
  *   The router item, an associate array corresponding to one row in the
  *   menu_router table. The value of key map holds the loaded objects. The
  *   value of key access is TRUE if the current user can access this page.
- *   The values for key title, page_arguments, access_arguments will be
- *   filled in based on the database values and the objects loaded.
+ *   The values for key title, page_arguments, access_arguments, and
+ *   theme_arguments will be filled in based on the database values and the
+ *   objects loaded.
  */
 function menu_get_item($path = NULL, $router_item = NULL) {
   $router_items = &drupal_static(__FUNCTION__);
@@ -391,6 +392,7 @@ function menu_get_item($path = NULL, $ro
       if ($router_item['access']) {
         $router_item['map'] = $map;
         $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts']));
+        $router_item['theme_arguments'] = array_merge(menu_unserialize($router_item['theme_arguments'], $map), array_slice($map, $router_item['number_parts']));
       }
     }
     $router_items[$path] = $router_item;
@@ -936,6 +938,8 @@ function menu_tree_all_data($menu_name, 
         'title',
         'title_callback',
         'title_arguments',
+        'theme_callback',
+        'theme_arguments',
         'type',
         'description',
       ));
@@ -1117,6 +1121,8 @@ function menu_tree_page_data($menu_name,
           'title',
           'title_callback',
           'title_arguments',
+          'theme_callback',
+          'theme_arguments',
           'type',
           'description',
         ));
@@ -1390,6 +1396,38 @@ function menu_get_active_help() {
 }
 
 /**
+ * Gets the custom theme for the current page, if there is one.
+ *
+ * @param $initialize
+ *   This parameter should only be used internally; it is set to TRUE in order
+ *   to force the custom theme to be initialized from the menu router item for
+ *   the current page.
+ * @return
+ *   The machine-readable name of the custom theme, if there is one.
+ *
+ * @see menu_set_custom_theme()
+ */
+function menu_get_custom_theme($initialize = FALSE) {
+  $custom_theme = &drupal_static(__FUNCTION__);
+  // Skip this if the site is offline or being installed or updated, since the
+  // menu system may not be correctly initialized then.
+  if ($initialize && !_menu_site_is_offline(TRUE) && (!defined('MAINTENANCE_MODE') || (MAINTENANCE_MODE != 'update' && MAINTENANCE_MODE != 'install'))) {
+    $router_item = menu_get_item();
+    if (!empty($router_item['access']) && !empty($router_item['theme_callback']) && function_exists($router_item['theme_callback'])) {
+      $custom_theme = call_user_func_array($router_item['theme_callback'], $router_item['theme_arguments']);
+    }
+  }
+  return $custom_theme;
+}
+
+/**
+ * Sets a custom theme for the current page, if there is one.
+ */
+function menu_set_custom_theme() {
+  menu_get_custom_theme(TRUE);
+}
+
+/**
  * Build a list of named menus.
  */
 function menu_get_names() {
@@ -2728,6 +2766,13 @@ function _menu_router_build($callbacks) 
             $item['file path'] = $parent['file path'];
           }
         }
+        // Same for theme callbacks.
+        if (!isset($item['theme callback']) && isset($parent['theme callback'])) {
+          $item['theme callback'] = $parent['theme callback'];
+          if (!isset($item['theme arguments']) && isset($parent['theme arguments'])) {
+            $item['theme arguments'] = $parent['theme arguments'];
+          }
+        }
       }
     }
     if (!isset($item['access callback']) && isset($item['access arguments'])) {
@@ -2749,6 +2794,8 @@ function _menu_router_build($callbacks) 
       'block callback' => '',
       'title arguments' => array(),
       'title callback' => 't',
+      'theme arguments' => array(),
+      'theme callback' => '',
       'description' => '',
       'position' => '',
       'tab_parent' => '',
@@ -2798,6 +2845,8 @@ function _menu_router_save($menu, $masks
       'title',
       'title_callback',
       'title_arguments',
+      'theme_callback',
+      'theme_arguments',
       'type',
       'block_callback',
       'description',
@@ -2823,6 +2872,8 @@ function _menu_router_save($menu, $masks
       'title' => $item['title'],
       'title_callback' => $item['title callback'],
       'title_arguments' => ($item['title arguments'] ? serialize($item['title arguments']) : ''),
+      'theme_callback' => $item['theme callback'],
+      'theme_arguments' => serialize($item['theme arguments']),
       'type' => $item['type'],
       'block_callback' => $item['block callback'],
       'description' => $item['description'],
@@ -2853,20 +2904,24 @@ function menu_path_is_external($path) {
  * This function will log the current user out and redirect to front page
  * if the current user has no 'access site in maintenance mode' permission.
  *
+ * @param $check_only
+ *   If this is set to TRUE, the function will perform the access checks and
+ *   return the site offline status, but not log the user out or display any
+ *   messages.
  * @return
  *   FALSE if the site is not in maintenance mode, the user login page is
  *   displayed, or the user has the 'access site in maintenance mode'
  *   permission. TRUE for anonymous users not being on the login page when the
  *   site is in maintenance mode.
  */
-function _menu_site_is_offline() {
+function _menu_site_is_offline($check_only = FALSE) {
   // Check if site is in maintenance mode.
   if (variable_get('maintenance_mode', 0)) {
     if (user_access('access site in maintenance mode')) {
       // Ensure that the maintenance mode message is displayed only once
       // (allowing for page redirects) and specifically suppress its display on
       // the maintenance mode settings page.
-      if ($_GET['q'] != 'admin/config/development/maintenance') {
+      if (!$check_only && $_GET['q'] != 'admin/config/development/maintenance') {
         if (user_access('administer site configuration')) {
           drupal_set_message(t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance'))), 'status', FALSE);
         }
@@ -2881,8 +2936,10 @@ function _menu_site_is_offline() {
         return ($_GET['q'] != 'user' && $_GET['q'] != 'user/login');
       }
       // Logged in users are unprivileged here, so they are logged out.
-      require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'user') . '/user.pages.inc';
-      user_logout();
+      if (!$check_only) {
+        require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'user') . '/user.pages.inc';
+        user_logout();
+      }
     }
   }
   return FALSE;
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.525
diff -u -p -r1.525 theme.inc
--- includes/theme.inc	15 Sep 2009 20:03:18 -0000	1.525
+++ includes/theme.inc	21 Sep 2009 03:16:15 -0000
@@ -38,10 +38,24 @@ define('MARK_UPDATED', 2);
  */
 
 /**
+ * Determines if a theme is available to use.
+ *
+ * @param $theme
+ *   An object representing the theme to check.
+ * @return
+ *   Boolean TRUE if the theme is enabled or is the site administration theme;
+ *   FALSE otherwise.
+ */
+function drupal_theme_access($theme) {
+  $admin_theme = variable_get('admin_theme');
+  return !empty($theme->status) || ($admin_theme && $theme->name == $admin_theme);
+}
+
+/**
  * Initialize the theme system by loading the theme.
  */
 function drupal_theme_initialize() {
-  global $theme, $user, $custom_theme, $theme_key;
+  global $theme, $user, $theme_key;
 
   // If $theme is already set, assume the others are set, too, and do nothing
   if (isset($theme)) {
@@ -52,12 +66,13 @@ function drupal_theme_initialize() {
   $themes = list_themes();
 
   // Only select the user selected theme if it is available in the
-  // list of enabled themes.
-  $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland');
+  // list of themes that can be accessed.
+  $theme = !empty($user->theme) && isset($themes[$user->theme]) && drupal_theme_access($themes[$user->theme]) ? $user->theme : variable_get('theme_default', 'garland');
 
   // Allow modules to override the present theme... only select custom theme
-  // if it is available in the list of installed themes.
-  $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme : $theme;
+  // if it is available in the list of themes that can be accessed.
+  $custom_theme = menu_get_custom_theme();
+  $theme = $custom_theme && isset($themes[$custom_theme]) && drupal_theme_access($themes[$custom_theme]) ? $custom_theme : $theme;
 
   // Store the identifier for retrieving theme settings with.
   $theme_key = $theme;
Index: modules/block/block.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.admin.inc,v
retrieving revision 1.57
diff -u -p -r1.57 block.admin.inc
--- modules/block/block.admin.inc	18 Sep 2009 00:12:45 -0000	1.57
+++ modules/block/block.admin.inc	21 Sep 2009 03:16:15 -0000
@@ -10,11 +10,6 @@
  * Menu callback for admin/structure/block.
  */
 function block_admin_display($theme = NULL) {
-  global $custom_theme;
-
-  // If non-default theme configuration has been selected, set the custom theme.
-  $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland');
-
   // Fetch and sort blocks.
   $blocks = _block_rehash();
   usort($blocks, '_block_compare');
@@ -26,14 +21,10 @@ function block_admin_display($theme = NU
  * Generate main blocks administration form.
  */
 function block_admin_display_form($form, &$form_state, $blocks, $theme = NULL) {
-  global $theme_key, $custom_theme;
+  global $theme_key;
 
   drupal_add_css(drupal_get_path('module', 'block') . '/block.css', array('preprocess' => FALSE));
 
-  // If non-default theme configuration has been selected, set the custom theme.
-  $custom_theme = isset($theme) ? $theme : variable_get('theme_default', 'garland');
-  drupal_theme_initialize();
-
   $block_regions = system_region_list($theme_key, REGIONS_VISIBLE) + array(BLOCK_REGION_NONE => '<' . t('none') . '>');
 
   // Weights range from -delta to +delta, so delta should be at least half
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.378
diff -u -p -r1.378 block.module
--- modules/block/block.module	20 Sep 2009 07:32:17 -0000	1.378
+++ modules/block/block.module	21 Sep 2009 03:16:16 -0000
@@ -76,6 +76,7 @@ function block_menu() {
     'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
     'page callback' => 'block_admin_display',
     'access arguments' => array('administer blocks'),
+    'theme callback' => '_block_custom_theme',
     'file' => 'block.admin.inc',
   );
   $items['admin/structure/block/list'] = array(
@@ -123,6 +124,8 @@ function block_menu() {
       'weight' => $key == $default ? -10 : 0,
       'access callback' => '_block_themes_access',
       'access arguments' => array($theme),
+      'theme callback' => '_block_custom_theme',
+      'theme arguments' => array($key),
       'file' => 'block.admin.inc',
     );
   }
@@ -133,8 +136,23 @@ function block_menu() {
  * Menu item access callback - only admin or enabled themes can be accessed.
  */
 function _block_themes_access($theme) {
-  $admin_theme = variable_get('admin_theme');
-  return user_access('administer blocks') && ($theme->status || ($admin_theme && ($theme->name == $admin_theme)));
+  return user_access('administer blocks') && drupal_theme_access($theme);
+}
+
+/**
+ * Theme callback for the block configuration pages.
+ *
+ * @param $theme
+ *   The theme whose blocks are being configured. If not set, the default theme
+ *   is assumed.
+ * @return
+ *   The theme that should be used for the block configuration page, or NULL
+ *   to indicate that the default theme should be used.
+ */
+function _block_custom_theme($theme = NULL) {
+  // We return exactly what was passed in, to guarantee that the page will
+  // always be displayed using the theme whose blocks are being configured.
+  return $theme;
 }
 
 /**
Index: modules/menu/menu.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.api.php,v
retrieving revision 1.10
diff -u -p -r1.10 menu.api.php
--- modules/menu/menu.api.php	17 Sep 2009 04:07:39 -0000	1.10
+++ modules/menu/menu.api.php	21 Sep 2009 03:16:16 -0000
@@ -40,6 +40,13 @@
  *     user_access() unless a value is inherited from a parent menu item.
  *   - "access arguments": An array of arguments to pass to the access callback
  *     function. Integer values pass the corresponding URL component.
+ *   - "theme callback": Optional. A function returning the machine-readable
+ *     name of the theme that will be used to render the page. If the function
+ *     returns nothing, the main site theme will be used. If no function is
+ *     provided, the main site theme will also be used, unless a value is
+ *     inherited from a parent menu item.
+ *   - "theme arguments": An array of arguments to pass to the theme callback
+ *     function. Integer values pass the corresponding URL component.
  *   - "file": A file that will be included before the callbacks are accessed;
  *     this allows callback functions to be in separate files. The file should
  *     be relative to the implementing module's directory unless otherwise
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1128
diff -u -p -r1.1128 node.module
--- modules/node/node.module	19 Sep 2009 11:07:36 -0000	1.1128
+++ modules/node/node.module	21 Sep 2009 03:16:16 -0000
@@ -1629,6 +1629,7 @@ function node_menu() {
     'access callback' => '_node_add_access',
     'weight' => 1,
     'menu_name' => 'management',
+    'theme callback' => '_node_custom_theme',
     'file' => 'node.pages.inc',
   );
   $items['rss.xml'] = array(
@@ -1690,6 +1691,7 @@ function node_menu() {
     'page arguments' => array(1),
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
+    'theme callback' => '_node_custom_theme',
     'weight' => 1,
     'type' => MENU_LOCAL_TASK,
     'file' => 'node.pages.inc',
@@ -1754,6 +1756,17 @@ function node_page_title($node) {
 }
 
 /**
+ * Theme callback for creating and editing nodes.
+ */
+function _node_custom_theme() {
+  // Use the administration theme if the site is configured to use it for
+  // nodes.
+  if (variable_get('node_admin_theme')) {
+    return variable_get('admin_theme');
+  }
+}
+
+/**
  * Implement hook_init().
  */
 function node_init() {
Index: modules/simpletest/tests/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu.test,v
retrieving revision 1.16
diff -u -p -r1.16 menu.test
--- modules/simpletest/tests/menu.test	17 Sep 2009 04:07:39 -0000	1.16
+++ modules/simpletest/tests/menu.test	21 Sep 2009 03:16:16 -0000
@@ -18,6 +18,10 @@ class MenuIncTestCase extends DrupalWebT
   function setUp() {
     // Enable dummy module that implements hook_menu.
     parent::setUp('menu_test');
+    // Make the tests below more robust by explicitly setting the default theme
+    // and administrative theme that they expect.
+    variable_set('theme_default', 'garland');
+    variable_set('admin_theme', 'seven');
   }
 
   /**
@@ -30,6 +34,80 @@ class MenuIncTestCase extends DrupalWebT
   }
 
   /**
+   * Test the theme callback when it is set to use an administrative theme.
+   */
+  function testThemeCallbackAdministrative() {
+    $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+    $this->assertText('Requested theme: seven. Actual theme: seven.', t('The administrative theme can be correctly set in a theme callback.'));
+    $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+  }
+
+  /**
+   * Test that the theme callback is properly inherited.
+   */
+  function testThemeCallbackInheritance() {
+    $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance');
+    $this->assertText('Requested theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', t('Theme callback inheritance correctly uses the administrative theme.'));
+    $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+  }
+
+  /**
+   * Test the theme callback when the site is in maintenance mode.
+   */
+  function testThemeCallbackMaintenanceMode() {
+    variable_set('maintenance_mode', TRUE);
+
+    // For a regular user, the fact that the site is in maintenance mode means
+    // we expect the theme callback system to be bypassed entirely.
+    $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+    $this->assertRaw('minnelli/minnelli.css', t("The maintenance theme's CSS appears on the page."));
+
+    // An administrator, however, should continue to see the requested theme.
+    $admin_user = $this->drupalCreateUser(array('access site in maintenance mode'));
+    $this->drupalLogin($admin_user);
+    $this->drupalGet('menu-test/theme-callback/use-admin-theme');
+    $this->assertText('Requested theme: seven. Actual theme: seven.', t('The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.'));
+    $this->assertRaw('seven/style.css', t("The administrative theme's CSS appears on the page."));
+  }
+
+  /**
+   * Test the theme callback when it is set to use an optional theme.
+   */
+  function testThemeCallbackOptionalTheme() {
+    // Request a theme that is not enabled.
+    $this->drupalGet('menu-test/theme-callback/use-stark-theme');
+    $this->assertText('Requested theme: stark. Actual theme: garland.', t('The theme callback system falls back on the default theme when a theme that is not enabled is requested.'));
+    $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+
+    // Now enable the theme and request it again.
+    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+    $this->drupalLogin($admin_user);
+    $this->drupalPost('admin/appearance', array('status[stark]' => 1), t('Save configuration'));
+    $this->drupalLogout();
+    $this->drupalGet('menu-test/theme-callback/use-stark-theme');
+    $this->assertText('Requested theme: stark. Actual theme: stark.', t('The theme callback system uses an optional theme once it has been enabled.'));
+    $this->assertRaw('stark/layout.css', t("The optional theme's CSS appears on the page."));
+  }
+
+  /**
+   * Test the theme callback when it is set to use a theme that does not exist.
+   */
+  function testThemeCallbackFakeTheme() {
+    $this->drupalGet('menu-test/theme-callback/use-fake-theme');
+    $this->assertText('Requested theme: fake_theme. Actual theme: garland.', t('The theme callback system falls back on the default theme when a theme that does not exist is requested.'));
+    $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+  }
+
+  /**
+   * Test the theme callback when no theme is requested.
+   */
+  function testThemeCallbackNoThemeRequested() {
+    $this->drupalGet('menu-test/theme-callback/no-theme-requested');
+    $this->assertText('Requested theme: NONE. Actual theme: garland.', t('The theme callback system falls back on the default theme when no theme is requested.'));
+    $this->assertRaw('garland/style.css', t("The default theme's CSS appears on the page."));
+  }
+
+  /**
    * Tests for menu_link_maintain().
    */
   function testMenuLinkMaintain() {
Index: modules/simpletest/tests/menu_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu_test.module,v
retrieving revision 1.7
diff -u -p -r1.7 menu_test.module
--- modules/simpletest/tests/menu_test.module	17 Sep 2009 04:07:40 -0000	1.7
+++ modules/simpletest/tests/menu_test.module	21 Sep 2009 03:16:16 -0000
@@ -44,6 +44,20 @@ function menu_test_menu() {
     'title' => 'Unattached subchild router',
     'page callback' => 'node_page_default',
   );
+  // Theme callback tests.
+  $items['menu-test/theme-callback/%'] = array(
+    'title' => 'Page that displays different themes',
+    'page callback' => 'menu_test_theme_page_callback',
+    'access arguments' => array('access content'),
+    'theme callback' => 'menu_test_theme_callback',
+    'theme arguments' => array(2),
+  );
+  $items['menu-test/theme-callback/%/inheritance'] = array(
+    'title' => 'Page that tests theme callback inheritance.',
+    'page callback' => 'menu_test_theme_page_callback',
+    'page arguments' => array(TRUE),
+    'access arguments' => array('access content'),
+  );
   return $items;
 }
 
@@ -58,6 +72,56 @@ function menu_test_callback() {
 }
 
 /**
+ * Page callback to use when testing the theme callback functionality.
+ *
+ * @param $inherited
+ *   An optional boolean to set to TRUE when the requested page is intended to
+ *   inherit the theme of its parent.
+ * @return
+ *   A string describing the requested custom theme and actual theme being used
+ *   for the current page request.
+ */
+function menu_test_theme_page_callback($inherited = FALSE) {
+  global $theme_key;
+  // Initialize the theme system so that $theme_key will be populated.
+  drupal_theme_initialize();
+  // Now check both the requested custom theme and the actual theme being used.
+  $custom_theme = menu_get_custom_theme();
+  $requested_theme = empty($custom_theme) ? 'NONE' : $custom_theme;
+  $output = "Requested theme: $requested_theme. Actual theme: $theme_key.";
+  if ($inherited) {
+    $output .= ' Theme callback inheritance is being tested.';
+  }
+  return $output;
+}
+
+/**
+ * Theme callback to use when testing the theme callback functionality.
+ *
+ * @param $argument
+ *   The argument passed in from the URL.
+ * @return
+ *   The name of the custom theme to request for the current page.
+ */
+function menu_test_theme_callback($argument) {
+  // Test using the variable administrative theme.
+  if ($argument == 'use-admin-theme') {
+    return variable_get('admin_theme');
+  }
+  // Test using a theme that exists, but may or may not be enabled.
+  elseif ($argument == 'use-stark-theme') {
+    return 'stark';
+  }
+  // Test using a theme that does not exist.
+  elseif ($argument == 'use-fake-theme') {
+    return 'fake_theme';
+  }
+  // For any other value of the URL argument, do not return anything. This
+  // allows us to test that returning nothing from a theme callback function
+  // causes the page to correctly fall back on using the main site theme.
+}
+
+/**
  * Helper function for the testMenuName() test. Used to change the menu_name
  * parameter of a menu.
  *
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.203
diff -u -p -r1.203 system.admin.inc
--- modules/system/system.admin.inc	19 Sep 2009 11:07:36 -0000	1.203
+++ modules/system/system.admin.inc	21 Sep 2009 03:16:16 -0000
@@ -233,7 +233,7 @@ function system_themes_form() {
     );
     $options[$theme->name] = $theme->info['name'];
 
-    if (!empty($theme->status) || $theme->name == variable_get('admin_theme', 0)) {
+    if (drupal_theme_access($theme)) {
       $form[$theme->name]['operations'] = array('#markup' => l(t('configure'), 'admin/appearance/settings/' . $theme->name) );
     }
     else {
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.389
diff -u -p -r1.389 system.install
--- modules/system/system.install	20 Sep 2009 17:56:24 -0000	1.389
+++ modules/system/system.install	21 Sep 2009 03:16:17 -0000
@@ -950,6 +950,20 @@ function system_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'theme_callback' => array(
+        'description' => 'A function which returns the name of the theme that will be used to render this page. If left empty, the default theme will be used.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'theme_arguments' => array(
+        'description' => 'A serialized array of arguments for the theme callback.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
       'type' => array(
         'description' => 'Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.',
         'type' => 'int',
@@ -2515,6 +2529,17 @@ function system_update_7038() {
 }
 
 /**
+ * Adds fields to the {menu_router} table to allow custom themes to be set per
+ * page.
+ */
+function system_update_7039() {
+  $ret = array();
+  db_add_field($ret, 'menu_router', 'theme_callback', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
+  db_add_field($ret, 'menu_router', 'theme_arguments', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''));
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.792
diff -u -p -r1.792 system.module
--- modules/system/system.module	19 Sep 2009 11:07:36 -0000	1.792
+++ modules/system/system.module	21 Sep 2009 03:16:17 -0000
@@ -509,6 +509,8 @@ function system_menu() {
     'page callback' => 'system_main_admin_page',
     'weight' => 9,
     'menu_name' => 'management',
+    'theme callback' => 'variable_get',
+    'theme arguments' => array('admin_theme'),
     'file' => 'system.admin.inc',
   );
   $items['admin/compact'] = array(
@@ -1308,7 +1310,7 @@ function blocked_ip_load($iid) {
  * Menu item access callback - only admin or enabled themes can be accessed.
  */
 function _system_themes_access($theme) {
-  return user_access('administer site configuration') && ($theme->status || $theme->name == variable_get('admin_theme', 0));
+  return user_access('administer site configuration') && drupal_theme_access($theme);
 }
 
 /**
@@ -1422,14 +1424,10 @@ function _system_filetransfer_backend_fo
  * Implement hook_init().
  */
 function system_init() {
-  // Use the administrative theme if the user is looking at a page in the admin/* path.
+  // Add the CSS for this module.
   if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
-    global $custom_theme;
-    $custom_theme = variable_get('admin_theme', 0);
     drupal_add_css(drupal_get_path('module', 'system') . '/admin.css', array('weight' => CSS_SYSTEM));
   }
-
-  // Add the CSS for this module.
   drupal_add_css(drupal_get_path('module', 'system') . '/defaults.css', array('weight' => CSS_SYSTEM));
   drupal_add_css(drupal_get_path('module', 'system') . '/system.css', array('weight' => CSS_SYSTEM));
   drupal_add_css(drupal_get_path('module', 'system') . '/system-menus.css', array('weight' => CSS_SYSTEM));
@@ -1660,7 +1658,7 @@ function system_admin_menu_block($item) 
 
   $content = array();
   $result = db_query("
-    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
+    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, m.description, ml.*
     FROM {menu_links} ml
     LEFT JOIN {menu_router} m ON ml.router_path = m.path
     WHERE ml.plid = :plid AND ml.menu_name = :name AND hidden = 0", array(':plid' => $item['mlid'], ':name' => $item['menu_name']), array('fetch' => PDO::FETCH_ASSOC));
@@ -2324,7 +2322,7 @@ function system_get_module_admin_tasks($
 
   if (empty($items)) {
     $result = db_query("
-       SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, ml.*
+       SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, ml.*
        FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path = m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module = 'system' AND m.number_parts > 2", array(), array('fetch' => PDO::FETCH_ASSOC));
     foreach ($result as $item) {
       _menu_link_translate($item);
