=== added file 'themes/bluemarine/bluemarine.info'
--- themes/bluemarine/bluemarine.info	1970-01-01 00:00:00 +0000
+++ themes/bluemarine/bluemarine.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Bluemarine
+description = Table-based multi-column theme with a marine and ash color scheme.

=== added file 'themes/chameleon/chameleon.info'
--- themes/chameleon/chameleon.info	1970-01-01 00:00:00 +0000
+++ themes/chameleon/chameleon.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,9 @@
+; $Id$
+name = Chameleon
+description = Minimalist tabled theme with light colors.
+regions[left] = Left sidebar
+regions[right] = Right sidebar
+features[] = logo
+features[] = favicon
+features[] = name
+features[] = slogan

=== added file 'themes/chameleon/marvin/marvin.info'
--- themes/chameleon/marvin/marvin.info	1970-01-01 00:00:00 +0000
+++ themes/chameleon/marvin/marvin.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Marvin
+description = Boxy tabled theme in all grays.
+regions[left] = Left sidebar
+regions[right] = Right sidebar

=== added file 'themes/garland/garland.info'
--- themes/garland/garland.info	1970-01-01 00:00:00 +0000
+++ themes/garland/garland.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Garland
+description = Tableless, recolorable, multi-column, fluid width theme (default).

=== added file 'themes/garland/minnelli/minnelli.info'
--- themes/garland/minnelli/minnelli.info	1970-01-01 00:00:00 +0000
+++ themes/garland/minnelli/minnelli.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Minnelli
+description = Tableless, recolorable, multi-column, fixed width theme.

=== added file 'themes/pushbutton/pushbutton.info'
--- themes/pushbutton/pushbutton.info	1970-01-01 00:00:00 +0000
+++ themes/pushbutton/pushbutton.info	2007-04-06 17:14:50 +0000
@@ -0,0 +1,3 @@
+; $Id$
+name = Pushbutton
+description = Tabled, multi-column theme in blue and orange tones.
\ No newline at end of file

=== modified file 'CHANGELOG.txt'
--- CHANGELOG.txt	2007-04-06 13:27:20 +0000
+++ CHANGELOG.txt	2007-04-06 17:14:47 +0000
@@ -13,6 +13,7 @@ Drupal 6.0, xxxx-xx-xx (development vers
     * Language detection based on parts of the URL.
     * Browser based language detection.
 - Language dependent path aliases.
+- Added .info files to themes and made it easier to specify regions and features.
 
 Drupal 5.0, 2007-01-15
 ----------------------

=== modified file 'includes/common.inc'
--- includes/common.inc	2007-04-06 13:27:20 +0000
+++ includes/common.inc	2007-04-06 17:14:47 +0000
@@ -2482,3 +2482,114 @@ function drupal_common_themes() {
     ),
   );
 }
+
+/**
+ * Parse Drupal info file format.
+ *
+ * Files should use an ini-like format to specify values.
+ * White-space generally doesn't matter, except inside values.
+ * e.g.
+ * key = value
+ * key = "value"
+ * key = 'value'
+ * key = "multi-line
+ *
+ * value"
+ * key = 'multi-line
+ *
+ * value'
+ *
+ * Arrays are created using a GET-like syntax:
+ *
+ * key[] = "numeric array"
+ * key[index] = "associative array"
+ * key[index][] = "nested numeric array"
+ * key[index][index] = "nested associative array"
+ *
+ * PHP constants are substituted in, but only when used as the entire value.
+ *
+ * Comments should start with a semi-colon at the beginning of a line.
+ *
+ * This function is NOT for placing arbitrary module-specific settings. Use
+ * variable_get() and variable_set() for that.
+ *
+ * Information stored in the module.info file:
+ *   name         - The real name of the module for display purposes.
+ *   description  - A brief description of the module.
+ *   dependencies - An array of short names (shortname) of other modules this
+ *                  module depends on.
+ *   package      - The name of the package of modules this module belongs to.
+ *
+ * Example of .info file:
+ *   name = Forum
+ *   description = Enables threaded discussions about general topics.
+ *   dependencies[] = taxonomy
+ *   dependencies[] = comment
+ *   package = Core - optional
+ *   version = VERSION
+ *
+ * @param $filename
+ *   The file we are parsing. Accepts file with relative or absolute path.
+ * @return
+ *   The info array.
+ */
+function drupal_parse_info_file($filename) {
+  $info = array();
+
+  if (!file_exists($filename)) {
+    return $info;
+  }
+
+  $data = file_get_contents($filename);
+  if (preg_match_all('
+    @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
+    ((?:
+      [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
+      \[[^\[\]]*\]                  # unless they are balanced and not nested
+    )+?)
+    \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
+    (?:
+      ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
+      (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
+      ([^\r\n]*?)                   # Non-quoted string
+    )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
+    @msx', $data, $matches, PREG_SET_ORDER)) {
+    foreach ($matches as $match) {
+      // Fetch the key and value string
+      $i = 0;
+      foreach (array('key', 'value1', 'value2', 'value3') as $var) {
+        $$var = isset($match[++$i]) ? $match[$i] : '';
+      }
+      $value = stripslashes(substr($value1, 1, -1)) . stripslashes(substr($value2, 1, -1)) . $value3;
+
+      // Parse array syntax
+      $keys = preg_split('/\]?\[/', rtrim($key, ']'));
+      $last = array_pop($keys);
+      $parent = &$info;
+
+      // Create nested arrays
+      foreach ($keys as $key) {
+        if ($key == '') {
+          $key = count($parent);
+        }
+        if (!isset($parent[$key]) || !is_array($parent[$key])) {
+          $parent[$key] = array();
+        }
+        $parent = &$parent[$key];
+      }
+
+      // Handle PHP constants
+      if (defined($value)) {
+        $value = constant($value);
+      }
+
+      // Insert actual value
+      if ($last == '') {
+        $last = count($parent);
+      }
+      $parent[$last] = $value;
+    }
+  }
+
+  return $info;
+}

=== modified file 'includes/install.inc'
--- includes/install.inc	2007-03-27 05:13:53 +0000
+++ includes/install.inc	2007-04-06 17:18:51 +0000
@@ -311,7 +311,7 @@ function drupal_install_profile($profile
   module_invoke('system', 'install');
   $system_versions = drupal_get_schema_versions('system');
   $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
-  db_query("INSERT INTO {system} (filename, name, type, description, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', 'module', '', 1, 0, 0, %d)", $system_path . '/system.module', 'system', $system_version);
+  db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES('%s', '%s', 'module', '', 1, 0, 0, %d)", $system_path . '/system.module', 'system', $system_version);
 
   // Now that we've installed things properly, bootstrap the full Drupal environment
   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

=== modified file 'includes/module.inc'
--- includes/module.inc	2007-02-04 21:20:50 +0000
+++ includes/module.inc	2007-04-06 17:14:47 +0000
@@ -102,16 +102,27 @@ function module_rebuild_cache() {
 
   ksort($files);
 
+  // Set defaults for module info
+  $defaults = array(
+    'dependencies' => array(),
+    'dependents' => array(),
+    'description' => '',
+    'version' => NULL
+  );
+
   foreach ($files as $filename => $file) {
-    $file->info = _module_parse_info_file(dirname($file->filename) .'/'. $file->name .'.info');
+    // Look for the info file.
+    $file->info = drupal_parse_info_file(dirname($file->filename) .'/'. $file->name .'.info');
+
     // Skip modules that don't provide info.
     if (empty($file->info)) {
       unset($files[$filename]);
       continue;
     }
-    $files[$filename]->info = $file->info;
+    // Merge in defaults and save.
+    $files[$filename]->info = $file->info + $defaults;
 
-    // log the critical hooks implemented by this module
+    // Log the critical hooks implemented by this module.
     $bootstrap = 0;
     foreach (bootstrap_hooks() as $hook) {
       if (module_hook($file->name, $hook)) {
@@ -121,15 +132,14 @@ function module_rebuild_cache() {
     }
 
     // Update the contents of the system table:
-    // TODO: We shouldn't actually need this description field anymore. Remove me next release.
     if (isset($file->status) || (isset($file->old_filename) && $file->old_filename != $file->filename)) {
-      db_query("UPDATE {system} SET description = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", $file->info['description'], $file->name, $file->filename, $bootstrap, $file->old_filename);
+      db_query("UPDATE {system} SET info = '%s', name = '%s', filename = '%s', bootstrap = %d WHERE filename = '%s'", serialize($file->info), $file->name, $file->filename, $bootstrap, $file->old_filename);
     }
     else {
       // This is a new module.
       $files[$filename]->status = 0;
       $files[$filename]->throttle = 0;
-      db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, $file->info['description'], 'module', $file->filename, 0, 0, $bootstrap);
+      db_query("INSERT INTO {system} (name, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, serialize($file->info), 'module', $file->filename, 0, 0, $bootstrap);
     }
   }
   $files = _module_build_dependents($files);
@@ -160,53 +170,6 @@ function _module_build_dependents($files
 }
 
 /**
- * Parse Drupal info file format.
- * Uses ini parser provided by php's parse_ini_file().
- *
- * Files should use the ini format to specify values.
- * e.g.
- * key = "value"
- * key2 = value2
- *
- * Some things to be aware of:
- * - This function is NOT for placing arbitrary module-specific settings. Use variable_get()
- *   and variable_set() for that.
- * - You may not use double-quotes in a value.
- *
- * Information stored in the module.info file:
- * name - The real name of the module for display purposes.
- * description - A brief description of the module.
- * dependencies - A space delimited list of the short names (shortname) of other modules this module depends on.
- * package - The name of the package of modules this module belongs to.
- *
- * Example of .info file:
- *   name = Forum
- *   description = Enables threaded discussions about general topics.
- *   dependencies = taxonomy comment
- *   package = Core - optional
- *
- * @param $filename
- *   The file we are parsing. Accepts file with relative or absolute path.
- * @return
- *   The info array.
- */
-function _module_parse_info_file($filename) {
-  $info = array();
-
-  if (file_exists($filename)) {
-    $info = parse_ini_file($filename);
-
-    if (isset($info['dependencies'])) {
-      $info['dependencies'] = explode(" ", $info['dependencies']);
-    }
-    else {
-      $info['dependencies'] = NULL;
-    }
-  }
-  return $info;
-}
-
-/**
  * Determine whether a given module exists.
  *
  * @param $module

=== modified file 'includes/theme.inc'
--- includes/theme.inc	2007-04-06 14:31:51 +0000
+++ includes/theme.inc	2007-04-06 17:23:59 +0000
@@ -59,7 +59,7 @@ function init_theme() {
     // File is a style; loads its CSS.
     // Set theme to its template/theme
     drupal_add_css($themes[$theme]->filename, 'theme');
-    $theme = basename(dirname($themes[$theme]->description));
+    $theme = basename(dirname($themes[$theme]->owner));
   }
   else {
     // File is a template/theme
@@ -74,10 +74,10 @@ function init_theme() {
    include_once './' . $themes[$theme]->filename;
    _theme_load_registry($theme);
   }
-  elseif (strpos($themes[$theme]->description, '.engine')) {
+  elseif (strpos($themes[$theme]->owner, '.engine')) {
     // file is a template; include its engine
-    include_once './' . $themes[$theme]->description;
-    $theme_engine = basename($themes[$theme]->description, '.engine');
+    include_once './' . $themes[$theme]->owner;
+    $theme_engine = basename($themes[$theme]->owner, '.engine');
     if (function_exists($theme_engine .'_init')) {
       call_user_func($theme_engine .'_init', $themes[$theme]);
     }
@@ -210,6 +210,7 @@ function list_themes($refresh = FALSE) {
     $result = db_query("SELECT * FROM {system} WHERE type = 'theme'");
     while ($theme = db_fetch_object($result)) {
       if (file_exists($theme->filename)) {
+        $theme->info = unserialize($theme->info);
         $list[$theme->name] = $theme;
       }
     }
@@ -238,6 +239,7 @@ function list_theme_engines($refresh = F
     $result = db_query("SELECT * FROM {system} WHERE type = 'theme_engine' AND status = '1' ORDER BY name");
     while ($engine = db_fetch_object($result)) {
       if (file_exists($engine->filename)) {
+        $engine->info = unserialize($engine->info);
         $list[$engine->name] = $engine;
       }
     }

=== modified file 'modules/block/block.module'
--- modules/block/block.module	2007-04-06 13:27:20 +0000
+++ modules/block/block.module	2007-04-06 17:14:50 +0000
@@ -100,9 +100,9 @@ function block_menu() {
   $default = variable_get('theme_default', 'garland');
   foreach (list_themes() as $key => $theme) {
     $items['admin/build/block/list/'. $key] = array(
-      'title' => t('!key settings', array('!key' => $key)),
+      'title' => t('!key settings', array('!key' => $theme->info['name'])),
       'page arguments' => array('block_admin_display', $key),
-      'type' => $key== $default ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
+      'type' => $key == $default ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
       'weight' => $key == $default ? -10 : 0,
     );
   }

=== modified file 'modules/forum/forum.info'
--- modules/forum/forum.info	2006-11-21 20:55:33 +0000
+++ modules/forum/forum.info	2007-04-06 17:14:50 +0000
@@ -1,6 +1,7 @@
 ; $Id: forum.info,v 1.4 2006/11/21 20:55:34 dries Exp $
 name = Forum
 description = Enables threaded discussions about general topics.
-dependencies = taxonomy comment
+dependencies[] = taxonomy
+dependencies[] = comment
 package = Core - optional
 version = VERSION

=== modified file 'modules/system/admin.css'
--- modules/system/admin.css	2006-11-23 11:05:46 +0000
+++ modules/system/admin.css	2007-04-06 17:14:50 +0000
@@ -96,4 +96,17 @@ table.system-status-report tr.ok th {
 }
 .theme-settings-bottom {
   clear: both;
+}
+
+/**
+ * Formatting for theme overview
+ */
+table.screenshot {
+  margin-right: 1em;
+}
+.theme-info h2 {
+  margin-bottom: 0;
+}
+.theme-info p {
+  margin-top: 0;
 }
\ No newline at end of file

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2007-03-30 08:47:58 +0000
+++ modules/system/system.install	2007-04-06 18:27:40 +0000
@@ -492,12 +492,13 @@ function system_install() {
         filename varchar(255) NOT NULL default '',
         name varchar(255) NOT NULL default '',
         type varchar(255) NOT NULL default '',
-        description varchar(255) NOT NULL default '',
+        owner varchar(255) NOT NULL default '',
         status int NOT NULL default '0',
         throttle tinyint DEFAULT '0' NOT NULL,
         bootstrap int NOT NULL default '0',
         schema_version smallint NOT NULL default -1,
         weight int NOT NULL default '0',
+        info text,
         PRIMARY KEY (filename),
         KEY (weight)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
@@ -978,12 +979,13 @@ function system_install() {
         filename varchar(255) NOT NULL default '',
         name varchar(255) NOT NULL default '',
         type varchar(255) NOT NULL default '',
-        description varchar(255) NOT NULL default '',
+        owner varchar(255) NOT NULL default '',
         status int NOT NULL default '0',
         throttle smallint DEFAULT '0' NOT NULL,
         bootstrap int NOT NULL default '0',
         schema_version smallint NOT NULL default -1,
         weight int NOT NULL default '0',
+        info text,
         PRIMARY KEY (filename)
       )");
       db_query("CREATE INDEX {system}_weight_idx ON {system} (weight)");
@@ -1106,8 +1108,8 @@ function system_install() {
       break;
   }
 
-  db_query("INSERT INTO {system} (filename, name, type, description, status, throttle, bootstrap, schema_version) VALUES ('themes/engines/phptemplate/phptemplate.engine', 'phptemplate', 'theme_engine', '', 1, 0, 0, 0)");
-  db_query("INSERT INTO {system} (filename, name, type, description, status, throttle, bootstrap, schema_version) VALUES ('themes/garland/page.tpl.php', 'garland', 'theme', 'themes/engines/phptemplate/phptemplate.engine', 1, 0, 0, 0)");
+  db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version) VALUES ('themes/engines/phptemplate/phptemplate.engine', 'phptemplate', 'theme_engine', '', 1, 0, 0, 0)");
+  db_query("INSERT INTO {system} (filename, name, type, owner, status, throttle, bootstrap, schema_version, info) VALUES ('themes/garland/page.tpl.php', 'garland', 'theme', 'themes/engines/phptemplate/phptemplate.engine', 1, 0, 0, 0, '%s')", serialize(drupal_parse_info_file('themes/garland/garland.info') + system_theme_default()));
 
   db_query("INSERT INTO {users} (uid,name,mail) VALUES(0,'','')");
 
@@ -3724,6 +3726,32 @@ function system_update_2006() {
 }
 
 /**
+ * Add info files to themes.
+ */
+function system_update_2007() {
+  $ret = array();
+
+  // Alter system table.
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+      db_add_column($ret, 'system', 'info', 'text');
+      db_change_column($ret, 'system', 'description', 'owner', 'varchar(255)', array('not null' => TRUE, 'default' => "''"));
+      break;
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {system} ADD info longtext");
+      $ret[] = update_sql("ALTER TABLE {system} CHANGE description owner varchar(255) NOT NULL default ''");
+      break;
+  }
+  
+  // Rebuild system table contents.
+  module_rebuild_cache();
+  system_theme_data();
+
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.0-to-x.x"
  * The next series of updates should start at 3000.
  */

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2007-04-06 14:31:51 +0000
+++ modules/system/system.module	2007-04-06 18:28:17 +0000
@@ -204,7 +204,7 @@ function system_menu() {
   foreach (list_themes() as $theme) {
     if ($theme->status) {
       $items['admin/build/themes/settings/'. $theme->name] = array(
-        'title' => $theme->name,
+        'title' => $theme->info['name'],
         'page arguments' => array('system_theme_settings', $theme->name),
         'type' => MENU_LOCAL_TASK,
       );
@@ -449,7 +449,7 @@ function system_admin_theme_settings() {
   ksort($themes);
   $options[0] = t('System default');
   foreach ($themes as $theme) {
-    $options[$theme->name] = $theme->name;
+    $options[$theme->name] = $theme->info['name'];
   }
 
   $form['admin_theme'] = array(
@@ -941,6 +941,30 @@ function system_get_files_database(&$fil
   }
 }
 
+function system_theme_default() {
+  // Prepare defaults for themes.
+  return array(
+    'regions' => array(
+      'left' => 'Left sidebar',
+      'right' => 'Right sidebar',
+      'content' => 'Content',
+      'header' => 'Header',
+      'footer' => 'Footer',
+    ),
+    'description' => '',
+    'features' => array(
+      'comment_user_picture',
+      'favicon',
+      'mission',
+      'logo',
+      'name',
+      'node_user_picture',
+      'search',
+      'slogan'
+    ),
+  );
+}
+
 /**
  * Collect data about all currently available themes
  */
@@ -1009,10 +1033,16 @@ function system_theme_data() {
   // Extract current files from database.
   system_get_files_database($themes, 'theme');
 
+  $defaults = system_theme_default();
+  // Read info files for the owner
+  foreach (array_keys($themes) as $key) {
+    $themes[$key]->info = drupal_parse_info_file(dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.info') + $defaults;
+  }
+
   db_query("DELETE FROM {system} WHERE type = 'theme'");
 
   foreach ($themes as $theme) {
-    db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
+    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
   }
 
   return $themes;
@@ -1030,32 +1060,8 @@ function system_region_list($theme_key) 
   static $list = array();
 
   if (!array_key_exists($theme_key, $list)) {
-    $theme = db_fetch_object(db_query("SELECT * FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key));
-
-    // Stylesheets can't have regions; use its theme.
-    if (strpos($theme->filename, '.css')) {
-      return system_region_list(basename(dirname($theme->description)));
-    }
-
-    // If this is a custom theme, load it in before moving on.
-    if (file_exists($file = dirname($theme->filename) .'/'. $theme_key .'.theme')) {
-      include_once "./$file";
-    }
-
-    $regions = array();
-
-    // This theme has defined its own regions.
-    if (function_exists($theme_key .'_regions')) {
-      $regions = call_user_func($theme_key .'_regions');
-    }
-    // File is an engine; include its regions.
-    else if (strpos($theme->description, '.engine')) {
-      include_once './'. $theme->description;
-      $theme_engine = basename($theme->description, '.engine');
-      $regions = function_exists($theme_engine .'_regions') ? call_user_func($theme_engine .'_regions') : array();
-    }
-
-    $list[$theme_key] = $regions;
+    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
+    $list[$theme_key] = array_map('t', $info['regions']);
   }
 
   return $list[$theme_key];
@@ -1181,22 +1187,22 @@ function system_themes_form() {
   ksort($themes);
   $status = array();
 
-  foreach ($themes as $info) {
-    $info->screenshot = dirname($info->filename) .'/screenshot.png';
-    $screenshot = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
-
-    $form[$info->name]['screenshot'] = array('#value' => $screenshot);
-    $form[$info->name]['description'] = array('#type' => 'item', '#title' => $info->name,  '#value' => dirname($info->filename));
-    $options[$info->name] = '';
-    if (!empty($info->status)) {
-      $status[] = $info->name;
+  foreach ($themes as $theme) {
+    $theme->screenshot = dirname($theme->filename) .'/screenshot.png';
+    $screenshot = file_exists($theme->screenshot) ? theme('image', $theme->screenshot, t('Screenshot for %theme theme', array('%theme' => $theme->info['name'])), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
+
+    $form[$theme->name]['screenshot'] = array('#value' => $screenshot);
+    $form[$theme->name]['info'] = array('#type' => 'value', '#value' => $theme->info);
+    $options[$theme->name] = '';
+    if (!empty($theme->status)) {
+      $status[] = $theme->name;
     }
-    if (!empty($info->status) && (function_exists($info->prefix .'_settings') || function_exists($info->prefix .'_features'))) {
-      $form[$info->name]['operations'] = array('#value' => l(t('configure'), 'admin/build/themes/settings/'. $info->name) );
+    if (!empty($theme->status)) {
+      $form[$theme->name]['operations'] = array('#value' => l(t('configure'), 'admin/build/themes/settings/'. $theme->name) );
     }
     else {
       // Dummy element for drupal_render. Cleaner than adding a check in the theme function.
-      $form[$info->name]['operations'] = array();
+      $form[$theme->name]['operations'] = array();
     }
   }
 
@@ -1210,15 +1216,25 @@ function system_themes_form() {
 
 function theme_system_themes_form($form) {
   foreach (element_children($form) as $key) {
+    // Only look for themes
+    if (!isset($form[$key]['info'])) {
+      continue;
+    }
+    
+    // Fetch info
+    $info = $form[$key]['info']['#value'];
+
+    // Style theme info
+    $theme = '<div class="theme-info"><h2>'. $info['name'] .'</h2><div class="description">'. $info['description'] .'</div></div>';
+
+    // Build rows
     $row = array();
-    if (isset($form[$key]['description']) && is_array($form[$key]['description'])) {
-      $row[] = drupal_render($form[$key]['screenshot']);
-      $row[] = drupal_render($form[$key]['description']);
-      $row[] = array('data' => drupal_render($form['status'][$key]), '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');
-      }
+    $row[] = drupal_render($form[$key]['screenshot']);
+    $row[] = $theme;
+    $row[] = array('data' => drupal_render($form['status'][$key]), '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');
     }
     $rows[] = $row;
   }
@@ -1297,10 +1313,6 @@ function system_modules($form_values = N
   $throttle = array();
   // Traverse the files retrieved and build the form.
   foreach ($files as $filename => $file) {
-    $file->info += array(
-      'dependents' => array(),
-      'version' => NULL,
-    );
     $form['name'][$filename] = array('#value' => $file->info['name']);
     $form['version'][$filename] = array('#value' => $file->info['version']);
     $form['description'][$filename] = array('#value' => t($file->info['description']));
@@ -1641,11 +1653,11 @@ function system_modules_uninstall($form_
   $form = array();
 
   // Pull all disabled modules from the system table.
-  $disabled_modules = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED);
+  $disabled_modules = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED);
   while ($module = db_fetch_object($disabled_modules)) {
 
-    // Grab the .info file and set name and description.
-    $info = _module_parse_info_file(dirname($module->filename) .'/'. $module->name .'.info');
+    // Grab the module info
+    $info = unserialize($module->info);
 
     // Load the .install file, and check for an uninstall hook.
     // If the hook exists, the module can be uninstalled.
@@ -1965,7 +1977,7 @@ function system_theme_settings($key = ''
     $settings = theme_get_settings($key);
     $var = str_replace('/', '_', 'theme_'. $key .'_settings');
     $themes = system_theme_data();
-    $features = function_exists($themes[$key]->prefix .'_features') ? call_user_func($themes[$key]->prefix .'_features') : array();
+    $features = $themes[$key]->info['features'];
   }
   else {
     $settings = theme_get_settings('');
@@ -2005,14 +2017,14 @@ function system_theme_settings($key = ''
 
   // Toggle settings
   $toggles = array(
-    'toggle_logo'                 => t('Logo'),
-    'toggle_name'                 => t('Site name'),
-    'toggle_slogan'               => t('Site slogan'),
-    'toggle_mission'              => t('Mission statement'),
-    'toggle_node_user_picture'    => t('User pictures in posts'),
-    'toggle_comment_user_picture' => t('User pictures in comments'),
-    'toggle_search'               => t('Search box'),
-    'toggle_favicon'              => t('Shortcut icon')
+    'logo'                 => t('Logo'),
+    'name'                 => t('Site name'),
+    'slogan'               => t('Site slogan'),
+    'mission'              => t('Mission statement'),
+    'node_user_picture'    => t('User pictures in posts'),
+    'comment_user_picture' => t('User pictures in comments'),
+    'search'               => t('Search box'),
+    'favicon'              => t('Shortcut icon')
   );
 
   // Some features are not always available
@@ -2033,9 +2045,9 @@ function system_theme_settings($key = ''
   foreach ($toggles as $name => $title) {
     if ((!$key) || in_array($name, $features)) {
       // disable search box if search.module is disabled
-      $form['theme_settings'][$name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $settings[$name]);
+      $form['theme_settings']['toggle_'. $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $settings['toggle_'. $name]);
       if (isset($disabled[$name])) {
-        $form['theme_settings'][$name]['#disabled'] = TRUE;
+        $form['theme_settings']['toggle_'. $name]['#disabled'] = TRUE;
       }
     }
   }
@@ -2065,7 +2077,7 @@ function system_theme_settings($key = ''
   }
 
   // Logo settings
-  if ((!$key) || in_array('toggle_logo', $features)) {
+  if ((!$key) || in_array('logo', $features)) {
     $form['logo'] = array(
       '#type' => 'fieldset',
       '#title' => t('Logo image settings'),
@@ -2094,7 +2106,7 @@ function system_theme_settings($key = ''
   }
 
   // Icon settings
-  if ((!$key) || in_array('toggle_favicon', $features)) {
+  if ((!$key) || in_array('favicon', $features)) {
     $form['favicon'] = array('#type' => 'fieldset', '#title' => t('Shortcut icon settings'));
     $form['favicon']['text'] = array('#value' => t('Your shortcut icon or \'favicon\' is displayed in the address bar and bookmarks of most browsers.'));
     $form['favicon']['default_favicon'] = array(

=== modified file 'themes/chameleon/chameleon.theme'
--- themes/chameleon/chameleon.theme	2007-04-06 13:27:20 +0000
+++ themes/chameleon/chameleon.theme	2007-04-06 17:14:50 +0000
@@ -23,21 +23,6 @@ function chameleon_theme($existing) {
   return $templates;
 }
 
-function chameleon_features() {
-  return array(
-       'toggle_logo',
-       'toggle_favicon',
-       'toggle_name',
-       'toggle_slogan');
-}
-
-function chameleon_regions() {
-  return array(
-       'left' => t('left sidebar'),
-       'right' => t('right sidebar')
-  );
-}
-
 function chameleon_page($content, $show_blocks = TRUE) {
   $language = isset($GLOBALS['language']) ? $GLOBALS['language'] : NULL;
 

=== modified file 'themes/engines/phptemplate/phptemplate.engine'
--- themes/engines/phptemplate/phptemplate.engine	2007-04-06 13:27:20 +0000
+++ themes/engines/phptemplate/phptemplate.engine	2007-04-06 17:15:09 +0000
@@ -14,23 +14,6 @@ function phptemplate_init($template) {
 }
 
 /**
- * @return
- *  Array of template features
- */
-function phptemplate_features() {
-  return array(
-    'toggle_logo',
-    'toggle_comment_user_picture',
-    'toggle_favicon',
-    'toggle_mission',
-    'toggle_name',
-    'toggle_node_user_picture',
-    'toggle_search',
-    'toggle_slogan'
-  );
-}
-
-/**
  * Implementation of hook_themes to tell Drupal what templates the engine
  * and the current theme use. The $existing argument will contain hooks
  * pre-defined by Drupal so that we can use that information if
@@ -38,7 +21,6 @@ function phptemplate_features() {
  */
 function phptemplate_theme($existing) {
   $templates = array(
-    'regions' => array('function' => 'phptemplate_regions'),
     'box' => array('file' => 'box'),
     'node' => array('file' => 'node'),
     'comment' => array('file' => 'comment'),
@@ -82,22 +64,6 @@ function phptemplate_templates($director
 }
 
 /**
- * Declare the available regions implemented by this engine.
- *
- * @return
- *  An array of regions. The first array element will be used as the default region for themes.
- */
-function phptemplate_regions() {
-  return array(
-       'left' => t('left sidebar'),
-       'right' => t('right sidebar'),
-       'content' => t('content'),
-       'header' => t('header'),
-       'footer' => t('footer')
-  );
-}
-
-/**
  * Adds additional helper variables to all templates.
  *
  * Counts how many times certain hooks have been called. Sidebar left / right are special cases.

