Index: index.php
===================================================================
RCS file: /Users/Shared/code/drupal/index.php,v
retrieving revision 1.94
diff -u -p -r1.94 index.php
--- index.php	26 Dec 2007 08:46:48 -0000	1.94
+++ index.php	12 Aug 2008 00:58:45 -0000
@@ -21,19 +21,21 @@ $return = menu_execute_active_handler();
 if (is_int($return)) {
   switch ($return) {
     case MENU_NOT_FOUND:
-      drupal_not_found();
+      $elements = drupal_not_found();
       break;
     case MENU_ACCESS_DENIED:
-      drupal_access_denied();
+      $elements = drupal_access_denied();
       break;
     case MENU_SITE_OFFLINE:
-      drupal_site_offline();
+      $elements = drupal_site_offline();
       break;
   }
 }
 elseif (isset($return)) {
   // Print any value (including an empty string) except NULL or undefined:
-  print theme('page', $return);
+  $elements = drupal_build_page($return);
 }
 
+echo drupal_render_page($elements);
+
 drupal_page_footer();
Index: includes/common.inc
===================================================================
RCS file: /Users/Shared/code/drupal/includes/common.inc,v
retrieving revision 1.781
diff -u -p -r1.781 common.inc
--- includes/common.inc	2 Aug 2008 19:01:02 -0000	1.781
+++ includes/common.inc	12 Aug 2008 00:58:45 -0000
@@ -47,20 +47,18 @@ function drupal_set_content($region = NU
  * @param $region
  *   A specified region to fetch content for. If NULL, all regions will be
  *   returned.
- * @param $delimiter
- *   Content to be inserted between exploded array elements.
  */
-function drupal_get_content($region = NULL, $delimiter = ' ') {
+function drupal_get_content($region = NULL) {
   $content = drupal_set_content();
   if (isset($region)) {
     if (isset($content[$region]) && is_array($content[$region])) {
-      return implode($delimiter, $content[$region]);
+      return $content[$region];
     }
   }
   else {
     foreach (array_keys($content) as $region) {
-      if (is_array($content[$region])) {
-        $content[$region] = implode($delimiter, $content[$region]);
+      if (!is_array($content[$region])) {
+        $content[$region] = array();
       }
     }
     return $content;
@@ -331,8 +329,15 @@ function drupal_site_offline() {
   drupal_maintenance_theme();
   drupal_set_header('HTTP/1.1 503 Service unavailable');
   drupal_set_title(t('Site offline'));
-  print theme('maintenance_page', filter_xss_admin(variable_get('site_offline_message',
-    t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))));
+
+  $elements['page'] = array(
+    '#title' => drupal_get_title(),
+    '#theme' => 'maintenance_page',
+    '#content' => array(
+      '#markup' => filter_xss_admin(variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))),
+    ),
+  );
+  return $elements;
 }
 
 /**
@@ -358,11 +363,11 @@ function drupal_not_found() {
 
   if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
     drupal_set_title(t('Page not found'));
-    $return = t('The requested page could not be found.');
+    $return = array('#markup' => t('The requested page could not be found.'));
   }
 
   // To conserve CPU and bandwidth, omit the blocks.
-  print theme('page', $return, FALSE);
+  return drupal_build_page($return, FALSE, TRUE, FALSE);
 }
 
 /**
@@ -387,9 +392,122 @@ function drupal_access_denied() {
 
   if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
     drupal_set_title(t('Access denied'));
-    $return = t('You are not authorized to access this page.');
+    $return = array('#markup' => t('You are not authorized to access this page.'));
   }
-  print theme('page', $return);
+  return drupal_build_page($return, TRUE, TRUE, FALSE);
+}
+
+/**
+ * Build a structured array with page content and theme parameters.
+ */
+function drupal_build_page($content, $show_blocks = TRUE, $show_messages = TRUE, $success = TRUE) {
+  if (!is_array($content)) {
+    $content = array('#markup' => $content);
+  }
+  $elements = array(
+    '#title' => drupal_get_title(),
+    '#theme' => 'page',
+    '#show_blocks' => $show_blocks,
+    '#show_messages' => $show_messages,
+    '#success' => $success,
+    'content' => $content,
+  );
+
+  global $theme;
+
+  $regions = system_region_list($theme);
+  // Load all region content assigned via blocks.
+  foreach (array_keys($regions) as $region) {
+    if (!isset($elements[$region])) {
+      $elements[$region] =  array();
+    }
+    // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE.
+    if (!(!$show_blocks && ($region == 'left' || $region == 'right'))) {
+      $elements[$region]['blocks'] = array('#markup' => theme('blocks', $region));
+    }
+  }
+
+  // Alter any part of the page before it's rendered.
+  drupal_alter('page', $elements);
+  return page_elements_builder($elements);
+}
+
+/**
+ * Adds any required properties non-form elements on the page.
+ *
+ * Similar to form_builder().
+ */
+function page_elements_builder($elements) {
+  // Use element defaults.
+  if ((!empty($elements['#type'])) && ($info = _element_info($elements['#type']))) {
+    // Overlay $info onto $elements, retaining preexisting keys.
+    $elements += $info;
+  }
+
+  // We start off assuming all elements are in the correct order.
+  $elements['#sorted'] = TRUE;
+
+  // Recurse through all child elements.
+  $count = 0;
+  foreach (element_children($elements) as $key) {
+    // Assign a decimal placeholder weight to preserve original array order.
+    if (!isset($form[$key]['#weight'])) {
+      $elements[$key]['#weight'] = $count/1000;
+    }
+    else {
+      // If one of the child elements has a weight then we will need to sort
+      // later.
+      unset($elements['#sorted']);
+    }
+    if (empty($elements[$key]['#type']) || $elements[$key]['#type'] != 'form') {
+      $elements[$key] = page_elements_builder($elements[$key]);
+    }
+    $count++;
+  }
+  return $elements;
+}
+
+function drupal_render_page($elements) {
+  $render_type = '';
+  if (isset($_GET['render'])) {
+    $render_type = $_GET['render'];
+  }
+  // jQuery sets a HTTP_X_REQUESTED_WITH header of 'XMLHttpRequest'.
+  if (!$render_type) {
+    // Set the render type based on the request header.
+    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
+      $render_type = 'json';
+    }
+    else {
+      $render_type = 'xhtml';
+    }
+  }
+  switch ($render_type) {
+    case 'xhtml':
+    case 'html':
+      $render = 'drupal_render';
+      break;
+
+    default:
+      $render = 'drupal_' . $render_type . '_render';
+      if (!drupal_function_exists($render)) {
+        $render = 'drupal_render';
+      }
+      break;
+  }
+
+  return $render($elements);
+}
+
+/**
+ * Render the elements into simple XML.
+ */
+function drupal_xml_render($elements) {
+  return drupal_render($elements, 'theme_xml');
+}
+
+function render(&$element) {
+  echo drupal_render($element);
 }
 
 /**
@@ -2068,7 +2186,7 @@ function drupal_get_js($scope = 'header'
   // with HTML 4, we need to comment out the CDATA-tag.
   $embed_prefix = "\n<!--//--><![CDATA[//><!--\n";
   $embed_suffix = "\n//--><!]]>\n";
- 
+
   foreach ($javascript as $type => $data) {
     if (!$data) continue;
 
@@ -2699,7 +2817,7 @@ function drupal_alter($type, &$data) {
 
 
 /**
- * Renders HTML given a structured array tree.
+ * Renders HTML or other output given a structured array tree.
  *
  * Recursively iterates over each of the array elements, generating HTML code.
  * This function is usually called from within a another function, like
@@ -2707,10 +2825,13 @@ function drupal_alter($type, &$data) {
  *
  * @param $elements
  *   The structured array describing the data to be rendered.
+ * @param $callback
+ *   Optional parameter defining which function to use to mediate conversion of
+ *   each elemement to a string.  Use the default, 'theme', for XHTML.
  * @return
- *   The rendered HTML.
+ *   The rendered content (XHTML or other depending on $callback).
  */
-function drupal_render(&$elements) {
+function drupal_render(&$elements, $callback = 'theme') {
   if (!isset($elements) || (isset($elements['#access']) && !$elements['#access'])) {
     return NULL;
   }
@@ -2729,7 +2850,7 @@ function drupal_render(&$elements) {
   if (isset($elements['#pre_render'])) {
     foreach ($elements['#pre_render'] as $function) {
       if (drupal_function_exists($function)) {
-        $elements = $function($elements);
+        $elements = $function($elements, $callback);
       }
     }
   }
@@ -2754,12 +2875,12 @@ function drupal_render(&$elements) {
         $elements['#markup'] = '';
       }
 
-      $content = theme($elements['#theme'], $elements);
+      $content = $callback($elements['#theme'], $elements);
     }
     // Render each of the children using drupal_render and concatenate them.
     if (!isset($content) || $content === '') {
       foreach ($children as $key) {
-        $content .= drupal_render($elements[$key]);
+        $content .= drupal_render($elements[$key], $callback);
       }
     }
   }
@@ -2769,7 +2890,8 @@ function drupal_render(&$elements) {
 
   // Until now, we rendered the children, here we render the element itself
   if (!isset($elements['#printed'])) {
-    $content = theme(!empty($elements['#type']) ? $elements['#type'] : 'markup', $elements);
+    // The default $callback is 'theme'.
+    $content = $callback(!empty($elements['#type']) ? $elements['#type'] : 'markup', $elements);
     $elements['#printed'] = TRUE;
   }
 
@@ -2780,7 +2902,7 @@ function drupal_render(&$elements) {
     if (isset($elements['#post_render'])) {
       foreach ($elements['#post_render'] as $function) {
         if (drupal_function_exists($function)) {
-          $content = $function($content, $elements);
+          $content = $function($content, $elements, $callback);
         }
       }
     }
@@ -2790,6 +2912,139 @@ function drupal_render(&$elements) {
   }
 }
 
+
+/**
+ * Renders elements of structured array tree, retaining the structure.
+ *
+ * Recursively iterates over each of the array elements, generating output.
+ * This function is usually called from within a another function.
+ *
+ * @param $elements
+ *   The structured array describing the data to be rendered.
+ * @param $callback
+ *   Optional parameter defining which funciton to use to mediate conversion of
+ *   each elemement to a string.  Use the default, 'theme', for HTML.
+ * @return
+ *   The rendered HTML.
+ */
+function drupal_render_array(&$elements, $callback = 'theme') {
+  if (!isset($elements) || (isset($elements['#access']) && !$elements['#access'])) {
+    $elements = NULL;
+  }
+
+  // If the default values for this element haven't been loaded yet, populate
+  // them.
+  if (!isset($elements['#defaults_loaded']) || !$elements['#defaults_loaded']) {
+    if ((!empty($elements['#type'])) && ($info = _element_info($elements['#type']))) {
+      $elements += $info;
+    }
+  }
+
+  // Make any final changes to the element before it is rendered. This means
+  // that the $element or the children can be altered or corrected before the
+  // element is rendered into the final text.
+  if (isset($elements['#pre_render'])) {
+    foreach ($elements['#pre_render'] as $function) {
+      if (drupal_function_exists($function)) {
+        $elements = $function($elements, $callback);
+      }
+    }
+  }
+
+  $content = '';
+  // Either the elements did not go through form_builder or one of the children
+  // has a #weight.
+  if (!isset($elements['#sorted'])) {
+    uasort($elements, "element_sort");
+  }
+  $elements += array('#title' => NULL, '#description' => NULL);
+  if (!isset($elements['#children'])) {
+    $children = element_children($elements);
+    /* Render all the children that use a theme function */
+    if (!$children && isset($elements['#theme']) && empty($elements['#theme_used'])) {
+      $elements['#theme_used'] = TRUE;
+
+      $previous = array();
+      foreach (array('#type', '#prefix', '#suffix') as $key) {
+        $previous[$key] = isset($elements[$key]) ? $elements[$key] : NULL;
+      }
+      // If we rendered a single element, then we will skip the renderer.
+      $elements['#printed'] = TRUE;
+      $elements['#type'] = 'markup';
+      $elements['#value'] = '';
+
+      unset($elements['#prefix'], $elements['#suffix']);
+
+      $args[] = $elements['#theme'];
+      $args[] = $elements;
+      if (!empty($elements['#theme arguments'])) {
+        foreach($elements['#theme arguments'] as $value) {
+          $args[] = $value;
+        }
+      }
+      // The default $callback is 'theme'.
+      $content = call_user_func_array($callback, $args);
+
+      foreach (array('#type', '#prefix', '#suffix') as $key) {
+        $elements[$key] = isset($previous[$key]) ? $previous[$key] : NULL;
+      }
+    }
+    // Render each of the children using drupal_render_array
+    if (!isset($content) || $content === '') {
+      foreach ($children as $key) {
+        drupal_render_array($elements[$key], $callback);
+      }
+    }
+  }
+
+  // Until now, we rendered the children, here we render the element itself
+  if (!isset($elements['#printed']) && !$children) {
+    // The default $callback is 'theme'.
+    $content = $callback(!empty($elements['#type']) ? $elements['#type'] : 'markup', $elements);
+    $elements['#printed'] = TRUE;
+  }
+
+  if (isset($content) && $content !== '') {
+    // Filter the outputted content and make any last changes before the
+    // content is sent to the browser. The changes are made on $content
+    // which allows the output'ed text to be filtered.
+    if (isset($elements['#post_render'])) {
+      foreach ($elements['#post_render'] as $function) {
+        if (drupal_function_exists($function)) {
+          $content = $function($content, $elements, $callback);
+        }
+      }
+    }
+    $prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
+    $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
+    $elements['#value'] = $prefix . $content . $suffix;
+  }
+}
+
+function element_property_preserve_in_array($key) {
+  switch ($key) {
+    case '#title':
+    case '#value':
+    case '#type':
+      return TRUE;
+
+    default:
+      return FALSE;
+  }
+}
+
+function drupal_json_render($elements) {
+  drupal_set_header('Content-Type: text/javascript; charset=utf-8');
+  drupal_render_array($elements);
+  return drupal_to_js($elements);
+}
+
+function drupal_printr_render($elements) {
+  drupal_set_header('Content-Type: text/plain; charset=utf-8');
+  drupal_render_array($elements);
+  return print_r($elements, 1);
+}
+
 /**
  * Function used by uasort to sort structured arrays by weight.
  */
@@ -2840,18 +3095,18 @@ function drupal_common_theme() {
       'arguments' => array('text' => NULL)
     ),
     'page' => array(
-      'arguments' => array('content' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE),
+      'arguments' => array('elements' => NULL),
       'template' => 'page',
     ),
     'maintenance_page' => array(
-      'arguments' => array('content' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE),
+      'arguments' => array('elements' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE),
       'template' => 'maintenance-page',
     ),
     'update_page' => array(
-      'arguments' => array('content' => NULL, 'show_messages' => TRUE),
+      'arguments' => array('elements' => NULL, 'show_messages' => TRUE),
     ),
     'install_page' => array(
-      'arguments' => array('content' => NULL),
+      'arguments' => array('elements' => NULL),
     ),
     'task_list' => array(
       'arguments' => array('items' => NULL, 'active' => NULL),
Index: includes/form.inc
===================================================================
RCS file: /Users/Shared/code/drupal/includes/form.inc,v
retrieving revision 1.277
diff -u -p -r1.277 form.inc
--- includes/form.inc	18 Jul 2008 07:06:24 -0000	1.277
+++ includes/form.inc	12 Aug 2008 00:58:45 -0000
@@ -143,9 +143,10 @@ function drupal_get_form($form_id) {
     $form = drupal_rebuild_form($form_id, $form_state, $args);
   }
 
-  // If we haven't redirected to a new location by now, we want to
-  // render whatever form array is currently in hand.
-  return drupal_render_form($form_id, $form);
+  // If we haven't redirected to a new location by now, we want to prepare for
+  // rendering whatever form array is currently in hand.
+  drupal_set_form_theme($form_id, $form);
+  return $form;
 }
 
 /**
@@ -586,7 +587,7 @@ function drupal_validate_form($form_id, 
  *   A string containing the path of the page to display when processing
  *   is complete.
  */
-function drupal_render_form($form_id, &$form) {
+function drupal_set_form_theme($form_id, &$form) {
   // Don't override #theme if someone already set it.
   if (!isset($form['#theme'])) {
     init_theme();
@@ -595,9 +596,6 @@ function drupal_render_form($form_id, &$
       $form['#theme'] = $form_id;
     }
   }
-
-  $output = drupal_render($form);
-  return $output;
 }
 
 /**
Index: includes/theme.inc
===================================================================
RCS file: /Users/Shared/code/drupal/includes/theme.inc,v
retrieving revision 1.431
diff -u -p -r1.431 theme.inc
--- includes/theme.inc	2 Aug 2008 19:01:02 -0000	1.431
+++ includes/theme.inc	12 Aug 2008 00:58:45 -0000
@@ -476,6 +476,14 @@ function list_themes($refresh = FALSE) {
 }
 
 /**
+ * Dummy function for now.
+ */
+function theme_xml() {
+  $args = func_get_args();
+  return call_user_func_array('theme', $args);
+}
+
+/**
  * Generate the themed output.
  *
  * All requests for theme hooks must go through this function. It examines
@@ -637,12 +645,9 @@ function theme() {
     }
 
     if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) {
-      // This construct ensures that we can keep a reference through
-      // call_user_func_array.
-      $args = array(&$variables, $hook);
       foreach ($info['preprocess functions'] as $preprocess_function) {
         if (drupal_function_exists($preprocess_function)) {
-          call_user_func_array($preprocess_function, $args);
+          $preprocess_function($variables, $hook);
         }
       }
     }
@@ -1278,7 +1283,13 @@ function theme_submenu($links) {
  * @return
  *   An HTML string representing the table.
  */
-function theme_table($header, $rows, $attributes = array(), $caption = NULL, $colgroups = array()) {
+function theme_table($element) {
+
+  $header = $element['#header'];
+  $rows = $element['#rows'];
+  $attributes = $element['#attributes'];
+  $caption = $element['#caption'];
+  $colgroups = $element['#colgroups'];
 
   // Add sticky headers, if applicable.
   if (count($header)) {
@@ -1478,7 +1489,12 @@ function theme_mark($type = MARK_NEW) {
  * @return
  *   A string containing the list output.
  */
-function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = array()) {
+function theme_item_list($list) {
+  $items = $list['#items'];
+  $title = $list['#title'];
+  $type = $list['#list_type'];
+  $attributes = $list['#attributes'];
+
   $output = '<div class="item-list">';
   if (isset($title)) {
     $output .= '<h3>' . $title . '</h3>';
@@ -1786,17 +1802,8 @@ function template_preprocess_page(&$vari
   global $theme;
   // Populate all block regions.
   $regions = system_region_list($theme);
-  // Load all region content assigned via blocks.
   foreach (array_keys($regions) as $region) {
-    // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE.
-    if (!(!$variables['show_blocks'] && ($region == 'left' || $region == 'right'))) {
-      $blocks = theme('blocks', $region);
-    }
-    else {
-      $blocks = '';
-    }
-    // Assign region to a region variable.
-    isset($variables[$region]) ? $variables[$region] .= $blocks : $variables[$region] = $blocks;
+    $variables[$region] = &$variables['elements'][$region];
   }
 
   // Set up layout variable.
@@ -1823,6 +1830,8 @@ function template_preprocess_page(&$vari
       $head_title[] = variable_get('site_slogan', '');
     }
   }
+
+  $variables['content']           = &$variables['elements']['content'];
   $variables['head_title']        = implode(' | ', $head_title);
   $variables['base_path']         = base_path();
   $variables['front_page']        = url();
@@ -1834,7 +1843,7 @@ function template_preprocess_page(&$vari
   $variables['language']          = $GLOBALS['language'];
   $variables['language']->dir     = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
   $variables['logo']              = theme_get_setting('logo');
-  $variables['messages']          = $variables['show_messages'] ? theme('status_messages') : '';
+  $variables['messages']          = $variables['elements']['#show_messages'] ? theme('status_messages') : '';
   $variables['mission']           = isset($mission) ? $mission : '';
   $variables['main_menu']     = theme_get_setting('toggle_main_menu') ? menu_main_menu() : array();
   $variables['secondary_menu']   = theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() : array();
@@ -1986,6 +1995,7 @@ function template_preprocess_node(&$vari
  */
 function template_preprocess_block(&$variables) {
   static $block_counter = array();
+
   // All blocks get an independent counter for each region.
   if (!isset($block_counter[$variables['block']->region])) {
     $block_counter[$variables['block']->region] = 1;
Index: includes/theme.maintenance.inc
===================================================================
RCS file: /Users/Shared/code/drupal/includes/theme.maintenance.inc,v
retrieving revision 1.15
diff -u -p -r1.15 theme.maintenance.inc
--- includes/theme.maintenance.inc	1 Jul 2008 20:36:40 -0000	1.15
+++ includes/theme.maintenance.inc	12 Aug 2008 00:58:45 -0000
@@ -164,7 +164,7 @@ function theme_update_page($content, $sh
   drupal_set_header('Content-Type: text/html; charset=utf-8');
 
   // Assign content and show message flag.
-  $variables['content'] = $content;
+  $variables['elements']['content'] = array('#value' => $content);
   $variables['show_messages'] = $show_messages;
   // The maintenance preprocess function is recycled here.
   template_preprocess_maintenance_page($variables);
@@ -239,6 +239,8 @@ function template_preprocess_maintenance
       $head_title[] = variable_get('site_slogan', '');
     }
   }
+
+  $variables['content']           = &$variables['elements']['content']);
   $variables['head_title']        = implode(' | ', $head_title);
   $variables['base_path']         = base_path();
   $variables['front_page']        = url();
Index: modules/aggregator/aggregator.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/aggregator/aggregator.admin.inc,v
retrieving revision 1.12
diff -u -p -r1.12 aggregator.admin.inc
--- modules/aggregator/aggregator.admin.inc	11 Aug 2008 07:05:26 -0000	1.12
+++ modules/aggregator/aggregator.admin.inc	12 Aug 2008 01:07:13 -0000
@@ -22,25 +22,33 @@ function aggregator_admin_overview() {
 function aggregator_view() {
   $result = db_query('SELECT f.*, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.etag, f.modified, f.image, f.block ORDER BY f.title');
 
-  $output = '<h3>' . t('Feed overview') . '</h3>';
+  $output['feed_overview'] = array('#markup' => '<h3>' . t('Feed overview') . '</h3>');
 
   $header = array(t('Title'), t('Items'), t('Last update'), t('Next update'), array('data' => t('Operations'), 'colspan' => '3'));
   $rows = array();
   while ($feed = db_fetch_object($result)) {
     $rows[] = array(l($feed->title, "aggregator/sources/$feed->fid"), format_plural($feed->items, '1 item', '@count items'), ($feed->checked ? t('@time ago', array('@time' => format_interval(time() - $feed->checked))) : t('never')), ($feed->checked ? t('%time left', array('%time' => format_interval($feed->checked + $feed->refresh - time()))) : t('never')), l(t('edit'), "admin/content/aggregator/edit/feed/$feed->fid"), l(t('remove items'), "admin/content/aggregator/remove/$feed->fid"), l(t('update items'), "admin/content/aggregator/update/$feed->fid"));
   }
-  $output .= theme('table', $header, $rows);
+  $output['feed_table'] = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
 
   $result = db_query('SELECT c.cid, c.title, count(ci.iid) as items FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid GROUP BY c.cid, c.title ORDER BY title');
 
-  $output .= '<h3>' . t('Category overview') . '</h3>';
+  $output['category_overview'] = array('#markup' => '<h3>' . t('Category overview') . '</h3>');
 
   $header = array(t('Title'), t('Items'), t('Operations'));
   $rows = array();
   while ($category = db_fetch_object($result)) {
     $rows[] = array(l($category->title, "aggregator/categories/$category->cid"), format_plural($category->items, '1 item', '@count items'), l(t('edit'), "admin/content/aggregator/edit/category/$category->cid"));
   }
-  $output .= theme('table', $header, $rows);
+  $output['category_table'] = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
 
   return $output;
 }
Index: modules/aggregator/aggregator.pages.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/aggregator/aggregator.pages.inc,v
retrieving revision 1.15
diff -u -p -r1.15 aggregator.pages.inc
--- modules/aggregator/aggregator.pages.inc	16 Jul 2008 21:59:25 -0000	1.15
+++ modules/aggregator/aggregator.pages.inc	12 Aug 2008 01:12:46 -0000
@@ -231,7 +231,11 @@ function theme_aggregator_categorize_ite
       }
     }
   }
-  $output .= theme('table', array('', t('Categorize')), $rows);
+  $table = array(
+    '#header' => array('', t('Categorize')),
+    '#rows' => $rows,
+  ) + _element_info('table');
+  $output .= theme('table', $table);
   $output .= drupal_render($form['submit']);
   $output .= drupal_render($form);
 
Index: modules/blog/blog.pages.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/blog/blog.pages.inc,v
retrieving revision 1.10
diff -u -p -r1.10 blog.pages.inc
--- modules/blog/blog.pages.inc	22 May 2008 19:27:13 -0000	1.10
+++ modules/blog/blog.pages.inc	12 Aug 2008 00:58:45 -0000
@@ -23,18 +23,21 @@ function blog_page_user($account) {
     $items[] = t('You are not allowed to post a new blog entry.');
   }
 
-  $output = theme('item_list', $items);
+  $output[] = array(
+    '#type' => 'item_list',
+    '#items' => $items
+  );
 
   $result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid);
   $has_posts = FALSE;
 
   while ($node = db_fetch_object($result)) {
-    $output .= node_view(node_load($node->nid), 1);
+    $output[] = array('#markup' => node_view(node_load($node->nid), 1));
     $has_posts = TRUE;
   }
 
   if ($has_posts) {
-    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+    $output['pager'] = array('#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)));
   }
   else {
     if ($account->uid == $user->uid) {
@@ -55,25 +58,27 @@ function blog_page_user($account) {
 function blog_page_last() {
   global $user;
 
-  $output = '';
   $items = array();
 
   if (user_access('edit own blog')) {
     $items[] = l(t('Create new blog entry.'), "node/add/blog");
   }
 
-  $output = theme('item_list', $items);
+  $output['blog_links'] = array(
+    '#type' => 'item_list',
+    '#items' => $items
+  );
 
   $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10));
   $has_posts = FALSE;
 
   while ($node = db_fetch_object($result)) {
-    $output .= node_view(node_load($node->nid), 1);
+    $output['nodes'][] = array('#markup' => node_view(node_load($node->nid), 1));
     $has_posts = TRUE;
   }
 
   if ($has_posts) {
-    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+    $output['pager'] = array('#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)));
   }
   else {
     drupal_set_message(t('No blog entries have been created.'));
Index: modules/book/book.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/book/book.admin.inc,v
retrieving revision 1.12
diff -u -p -r1.12 book.admin.inc
--- modules/book/book.admin.inc	5 Jul 2008 06:00:51 -0000	1.12
+++ modules/book/book.admin.inc	12 Aug 2008 01:22:47 -0000
@@ -16,7 +16,11 @@ function book_admin_overview() {
   }
   $headers = array(t('Book'), t('Operations'));
 
-  return theme('table', $headers, $rows);
+  return array(
+    '#type' => 'table', 
+    '#header' => $headers, 
+    '#rows' => $rows,
+  );
 }
 
 /**
@@ -248,6 +252,11 @@ function theme_book_admin_table($form) {
     $rows[] = $row;
   }
 
-  return theme('table', $header, $rows, array('id' => 'book-outline'));
+  $table = array(
+    '#header' => $header,
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'book-outline'),
+  ) + _element_info('table');
+  return theme('table', $table);
 }
 
Index: modules/comment/comment.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/comment/comment.admin.inc,v
retrieving revision 1.10
diff -u -p -r1.10 comment.admin.inc
--- modules/comment/comment.admin.inc	16 Jul 2008 21:59:26 -0000	1.10
+++ modules/comment/comment.admin.inc	12 Aug 2008 00:58:45 -0000
@@ -167,8 +167,12 @@ function theme_comment_admin_overview($f
   else {
     $rows[] = array(array('data' => t('No comments available.'), 'colspan' => '6'));
   }
+  $table = array(
+    '#header' => $form['header']['#value'],
+    '#rows' => $rows,
+  ) + _element_info('table');
+  $output .= theme('table', $table);
 
-  $output .= theme('table', $form['header']['#value'], $rows);
   if ($form['pager']['#markup']) {
     $output .= drupal_render($form['pager']);
   }
Index: modules/comment/comment.module
===================================================================
RCS file: /Users/Shared/code/drupal/modules/comment/comment.module,v
retrieving revision 1.645
diff -u -p -r1.645 comment.module
--- modules/comment/comment.module	3 Aug 2008 18:52:27 -0000	1.645
+++ modules/comment/comment.module	12 Aug 2008 00:58:45 -0000
@@ -981,7 +981,11 @@ function comment_render($node, $cid = 0)
         $comments .= '</div>';
       }
       $output .= $comments;
-      $output .= theme('pager', NULL, $comments_per_page, 0);
+      $element = array(
+        '#type' => 'pager',
+        '#limit' => $comments_per_page,
+      ) + _element_info('pager');
+      $output .= theme('pager', $element);
     }
 
     // If enabled, show new comment form if it's not already being displayed.
@@ -1408,7 +1412,7 @@ function comment_form(&$form_state, $edi
  *   The form title.
  */
 function comment_form_box($edit, $title = NULL) {
-  return theme('box', $title, drupal_get_form('comment_form', $edit, $title));
+  return theme('box', $title, drupal_render(drupal_get_form('comment_form', $edit, $title)));
 }
 
 /**
Index: modules/dblog/dblog.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/dblog/dblog.admin.inc,v
retrieving revision 1.8
diff -u -p -r1.8 dblog.admin.inc
--- modules/dblog/dblog.admin.inc	19 Jul 2008 07:44:45 -0000	1.8
+++ modules/dblog/dblog.admin.inc	12 Aug 2008 00:58:45 -0000
@@ -51,7 +51,7 @@ function dblog_overview() {
     WATCHDOG_EMERG    => 'dblog-emerg',
   );
 
-  $output = drupal_get_form('dblog_filter_form');
+  $output['filter_form'] = drupal_get_form('dblog_filter_form');
 
   $header = array(
     ' ',
@@ -90,9 +90,16 @@ function dblog_overview() {
   if (!$rows) {
     $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 6));
   }
-
-  $output .= theme('table', $header, $rows, array('id' => 'admin-dblog'));
-  $output .= theme('pager', NULL, 50, 0);
+  $output['messages_table'] = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'admin-dblog'),
+  );
+  $output['pager'] = array(
+    '#type' => 'pager',
+    '#limit' => 50,
+  );
 
   return $output;
 }
@@ -118,8 +125,12 @@ function dblog_top($type) {
   if (empty($rows)) {
     $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 2));
   }
-
-  $output  = theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output  = theme('table', $table);
   $output .= theme('pager', NULL, 30, 0);
 
   return $output;
@@ -171,8 +182,13 @@ function dblog_event($id) {
         $dblog->link,
       ),
     );
-    $attributes = array('class' => 'dblog-event');
-    $output = theme('table', array(), $rows, $attributes);
+    $table = array(
+      '#type' => 'table',
+      '#header' => array(),
+      '#rows' => $rows,
+      '#attributes' => array('class' => 'dblog-event'),
+    );
+    $output = theme('table', $table);
   }
   return $output;
 }
Index: modules/filter/filter.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/filter/filter.admin.inc,v
retrieving revision 1.13
diff -u -p -r1.13 filter.admin.inc
--- modules/filter/filter.admin.inc	24 Jul 2008 16:27:51 -0000	1.13
+++ modules/filter/filter.admin.inc	12 Aug 2008 01:28:11 -0000
@@ -80,8 +80,12 @@ function theme_filter_admin_overview($fo
       unset($form[$id]);
     }
   }
-  $header = array(t('Name'), t('Roles'), t('Default'), t('Weight'), array('data' => t('Operations'), 'colspan' => 2));
-  $output = theme('table', $header, $rows, array('id' => 'input-format-order'));
+  $table = array(
+    '#header' => array(t('Name'), t('Roles'), t('Default'), t('Weight'), array('data' => t('Operations'), 'colspan' => 2)),
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'input-format-order'),
+  ) + _element_info('table');
+  $output = theme('table', $table);
   $output .= drupal_render($form);
 
   drupal_add_tabledrag('input-format-order', 'order', 'sibling', 'input-format-order-weight');
@@ -375,7 +379,6 @@ function filter_admin_order(&$form_state
  * @ingroup themeable
  */
 function theme_filter_admin_order($form) {
-  $header = array(t('Name'), t('Weight'));
   $rows = array();
   foreach (element_children($form['names']) as $id) {
     // Don't take form control structures.
@@ -387,8 +390,12 @@ function theme_filter_admin_order($form)
       );
     }
   }
-
-  $output = theme('table', $header, $rows, array('id' => 'filter-order'));
+  $table = array(
+    '#header' => array(t('Name'), t('Weight')),
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'filter-order'),
+  ) + _element_info('table');
+  $output = theme('table', $table);
   $output .= drupal_render($form);
 
   drupal_add_tabledrag('filter-order', 'order', 'sibling', 'filter-order-weight', NULL, NULL, FALSE);
Index: modules/filter/filter.module
===================================================================
RCS file: /Users/Shared/code/drupal/modules/filter/filter.module,v
retrieving revision 1.218
diff -u -p -r1.218 filter.module
--- modules/filter/filter.module	11 Aug 2008 18:01:51 -0000	1.218
+++ modules/filter/filter.module	12 Aug 2008 01:35:05 -0000
@@ -233,7 +233,11 @@ function filter_filter_tips($delta, $for
                 );
               }
             }
-            $output .= theme('table', $header, $rows);
+            $table = array(
+              '#header' => $header,
+              '#rows' => $rows,
+            ) + _element_info('table');
+            $output .= theme('table', $table);
 
             $output .= '<p>' . t('Most unusual characters can be directly entered without any problems.') . '</p>';
             $output .= '<p>' . t('If you do encounter problems, try using HTML character entities. A common example looks like &amp;amp; for an ampersand &amp; character. For a full list of entities see HTML\'s <a href="@html-entities">entities</a> page. Some of the available characters include:', array('@html-entities' => 'http://www.w3.org/TR/html4/sgml/entities.html')) . '</p>';
@@ -253,7 +257,11 @@ function filter_filter_tips($delta, $for
                 array('data' => $entity[1], 'class' => 'get')
               );
             }
-            $output .= theme('table', $header, $rows);
+            $table = array(
+              '#header' => $header,
+              '#rows' => $rows,
+            ) + _element_info('table');
+            $output .= theme('table', $table);
             return $output;
         }
       }
Index: modules/menu/menu.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/menu/menu.admin.inc,v
retrieving revision 1.32
diff -u -p -r1.32 menu.admin.inc
--- modules/menu/menu.admin.inc	16 Jul 2008 21:59:27 -0000	1.32
+++ modules/menu/menu.admin.inc	12 Aug 2008 01:44:46 -0000
@@ -214,7 +214,12 @@ function theme_menu_overview_form($form)
   }
   $output = '';
   if ($rows) {
-    $output .= theme('table', $header, $rows, array('id' => 'menu-overview'));
+    $table = array(
+      '#header' => $header,
+      '#rows' => $rows,
+      '#attributes' => array('id' => 'menu-overview'),
+    ) + _element_info('table');
+    $output .= theme('table', $table);
   }
   $output .= drupal_render($form);
   return $output;
Index: modules/node/content_types.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/node/content_types.inc,v
retrieving revision 1.57
diff -u -p -r1.57 content_types.inc
--- modules/node/content_types.inc	16 Jul 2008 21:59:27 -0000	1.57
+++ modules/node/content_types.inc	12 Aug 2008 01:47:40 -0000
@@ -42,7 +42,11 @@ function node_overview_types() {
     $rows[] = array(array('data' => t('No content types available.'), 'colspan' => '5', 'class' => 'message'));
   }
 
-  return theme('table', $header, $rows);
+  return array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
 }
 
 /**
Index: modules/node/node.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/node/node.admin.inc,v
retrieving revision 1.24
diff -u -p -r1.24 node.admin.inc
--- modules/node/node.admin.inc	19 Jul 2008 19:04:24 -0000	1.24
+++ modules/node/node.admin.inc	12 Aug 2008 01:49:05 -0000
@@ -585,8 +585,11 @@ function theme_node_admin_nodes($form) {
   else {
     $rows[] = array(array('data' => t('No posts available.'), 'colspan' => '6'));
   }
-
-  $output .= theme('table', $header, $rows);
+  $table = array(
+    '#header' => $header,
+    '#rows' => $rows,
+  ) + _element_info('table');
+  $output .= theme('table', $table);
   if ($form['pager']['#markup']) {
     $output .= drupal_render($form['pager']);
   }
Index: modules/node/node.module
===================================================================
RCS file: /Users/Shared/code/drupal/modules/node/node.module,v
retrieving revision 1.971
diff -u -p -r1.971 node.module
--- modules/node/node.module	3 Aug 2008 19:02:06 -0000	1.971
+++ modules/node/node.module	12 Aug 2008 02:17:19 -0000
@@ -1398,7 +1398,11 @@ function theme_node_search_admin($form) 
     $row[] = drupal_render($form['factors'][$key]);
     $rows[] = $row;
   }
-  $output .= theme('table', $header, $rows);
+  $table = array(
+    '#header' => $header,
+    '#rows' => $rows,
+  ) + _element_info('table');
+  $output .= theme('table', $table);
 
   $output .= drupal_render($form);
   return $output;
@@ -1789,17 +1793,17 @@ function node_feed($nids = FALSE, $chann
 function node_page_default() {
   $result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10));
 
-  $output = '';
+  $output = array();
   $num_rows = FALSE;
   while ($node = db_fetch_object($result)) {
-    $output .= node_view(node_load($node->nid), 1);
+    $output[] = array('#markup' => node_view(node_load($node->nid), 1));
     $num_rows = TRUE;
   }
 
   if ($num_rows) {
     $feed_url = url('rss.xml', array('absolute' => TRUE));
     drupal_add_feed($feed_url, variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
-    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+    $output[] = array('#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)));
   }
   else {
     $default_message = '<h1 class="title">' . t('Welcome to your new Drupal website!') . '</h1>';
@@ -1812,7 +1816,7 @@ function node_page_default() {
     $default_message .= '</ol>';
     $default_message .= '<p>' . t('For more information, please refer to the <a href="@help">help section</a>, or the <a href="@handbook">online Drupal handbooks</a>. You may also post at the <a href="@forum">Drupal forum</a>, or view the wide range of <a href="@support">other support options</a> available.', array('@help' => url('admin/help'), '@handbook' => 'http://drupal.org/handbooks', '@forum' => 'http://drupal.org/forum', '@support' => 'http://drupal.org/support')) . '</p>';
 
-    $output = '<div id="first-time">' . $default_message . '</div>';
+    $output = array('#markup' => '<div id="first-time">' . $default_message . '</div>');
   }
   drupal_set_title('');
 
Index: modules/openid/openid.pages.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/openid/openid.pages.inc,v
retrieving revision 1.6
diff -u -p -r1.6 openid.pages.inc
--- modules/openid/openid.pages.inc	14 Apr 2008 17:48:38 -0000	1.6
+++ modules/openid/openid.pages.inc	12 Aug 2008 01:59:04 -0000
@@ -47,8 +47,12 @@ function openid_user_identities($account
     $rows[] = array($identity->authname, l(t('Delete'), 'user/' . $account->uid . '/openid/delete/' . $identity->aid));
   }
 
-  $output = theme('table', $header, $rows);
-  $output .= drupal_get_form('openid_user_add');
+  $output['accounts'] = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output['openid_user_add'] = drupal_get_form('openid_user_add');
   return $output;
 }
 
Index: modules/path/path.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/path/path.admin.inc,v
retrieving revision 1.9
diff -u -p -r1.9 path.admin.inc
--- modules/path/path.admin.inc	3 Aug 2008 05:21:20 -0000	1.9
+++ modules/path/path.admin.inc	12 Aug 2008 02:00:33 -0000
@@ -13,7 +13,7 @@
  */
 function path_admin_overview($keys = NULL) {
   // Add the filter form above the overview table.
-  $output = drupal_get_form('path_admin_filter_form', $keys);
+  $output['path_admin_filter_form'] = drupal_get_form('path_admin_filter_form', $keys);
   // Enable language column if locale is enabled or if we have any alias with language
   $count = db_result(db_query("SELECT COUNT(*) FROM {url_alias} WHERE language != ''"));
   $multilanguage = (module_exists('locale') || $count);
@@ -55,8 +55,12 @@ function path_admin_overview($keys = NUL
     $rows[] = array(array('data' => $empty_message, 'colspan' => ($multilanguage ? 5 : 4)));
   }
 
-  $output .= theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 50, 0);
+  $output['aliases'] = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output['pager'] = array('#markup' => theme('pager', NULL, 50, 0));
 
   return $output;
 }
Index: modules/system/system.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/system/system.admin.inc,v
retrieving revision 1.84
diff -u -p -r1.84 system.admin.inc
--- modules/system/system.admin.inc	9 Aug 2008 12:41:23 -0000	1.84
+++ modules/system/system.admin.inc	12 Aug 2008 00:58:45 -0000
@@ -1117,8 +1117,12 @@ function system_ip_blocking() {
   }
 
   $output .= drupal_get_form('system_ip_blocking_form');
-
-  $output .= theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output .= theme('table', $table);
 
   return $output;
 }
@@ -1823,8 +1827,12 @@ function _system_sql($data, $keys) {
       $rows[] = array(check_plain($key), check_plain($data[$key]), $explanation);
     }
   }
-
-  return theme('table', array(t('Variable'), t('Value'), t('Description')), $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => array(t('Variable'), t('Value'), t('Description')),
+    '#rows' => $rows,
+  );
+  return theme('table', $table);
 }
 
 /**
@@ -2107,8 +2115,12 @@ function theme_system_modules_fieldset($
     $row[] = array('data' => $description, 'class' => 'description');
     $rows[] = $row;
   }
-
-  return theme('table', $form['#header'], $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $form['#header'],
+    '#rows' => $rows,
+  );
+  return theme('table', $table);
 }
 
 /**
@@ -2159,8 +2171,12 @@ function theme_system_modules_uninstall(
   if (empty($rows)) {
     $rows[] = array(array('data' => t('No modules are available to uninstall.'), 'colspan' => '3', 'align' => 'center', 'class' => 'message'));
   }
-
-  $output  = theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output  = theme('table', $table);
   $output .= drupal_render($form);
 
   return $output;
@@ -2183,8 +2199,12 @@ function theme_system_theme_select_form(
     $rows[] = $row;
   }
 
-  $header = array(t('Screenshot'), t('Name'), t('Selected'));
-  $output = theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => array(t('Screenshot'), t('Name'), t('Selected')),
+    '#rows' => $rows,
+  );
+  $output = theme('table', $table);
   return $output;
 }
 
@@ -2241,8 +2261,12 @@ function theme_system_themes_form($form)
     $rows[] = $row;
   }
 
-  $header = array(t('Screenshot'), t('Name'), t('Version'), t('Enabled'), t('Default'), t('Operations'));
-  $output = theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => array(t('Screenshot'), t('Name'), t('Version'), t('Enabled'), t('Default'), t('Operations')),
+    '#rows' => $rows,
+  );
+  $output = theme('table', $table);
   $output .= drupal_render($form);
   return $output;
 }
\ No newline at end of file
Index: modules/system/system.module
===================================================================
RCS file: /Users/Shared/code/drupal/modules/system/system.module,v
retrieving revision 1.612
diff -u -p -r1.612 system.module
--- modules/system/system.module	2 Aug 2008 19:01:02 -0000	1.612
+++ modules/system/system.module	12 Aug 2008 02:20:53 -0000
@@ -323,6 +323,21 @@ function system_elements() {
     '#input' => TRUE,
   );
 
+  /**
+   * Common page elements.
+   */
+  $type['table']  = array(
+    '#header' => array(),
+    '#rows' => array(),
+    '#caption' => NULL,
+    '#colgroups' => array(),
+  );
+
+  $type['item_list'] = array(
+    '#items' => array(),
+    '#title' => NULL,
+    '#list_type' => 'ul',
+  );
   return $type;
 }
 
Index: modules/user/user.admin.inc
===================================================================
RCS file: /Users/Shared/code/drupal/modules/user/user.admin.inc,v
retrieving revision 1.24
diff -u -p -r1.24 user.admin.inc
--- modules/user/user.admin.inc	24 Jul 2008 16:28:52 -0000	1.24
+++ modules/user/user.admin.inc	12 Aug 2008 00:58:45 -0000
@@ -19,8 +19,8 @@ function user_admin($callback_arg = '') 
         $output = drupal_get_form('user_multiple_delete_confirm');
       }
       else {
-        $output = drupal_get_form('user_filter_form');
-        $output .= drupal_get_form('user_admin_account');
+        $output[] = drupal_get_form('user_filter_form');
+        $output[] = drupal_get_form('user_admin_account');
       }
   }
   return $output;
@@ -606,7 +606,13 @@ function theme_user_admin_perm($form) {
     }
   }
   $output = theme('system_compact_link');
-  $output .= theme('table', $header, $rows, array('id' => 'permissions'));
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#attributes' => array('id' => 'permissions'),
+  );
+  $output .= theme('table', $table);
   $output .= drupal_render($form);
   return $output;
 }
@@ -738,8 +744,12 @@ function theme_user_admin_account($form)
   else {
     $rows[] = array(array('data' => t('No users available.'), 'colspan' => '7'));
   }
-
-  $output .= theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output .= theme('table', $table);
   if ($form['pager']['#markup']) {
     $output .= drupal_render($form['pager']);
   }
@@ -768,7 +778,12 @@ function theme_user_admin_new_role($form
   $rows[] = array(drupal_render($form['name']), array('data' => drupal_render($form['submit']), 'colspan' => 2));
 
   $output = drupal_render($form);
-  $output .= theme('table', $header, $rows);
+  $table = array(
+    '#type' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  $output .= theme('table', $table);
 
   return $output;
 }
Index: modules/user/user.module
===================================================================
RCS file: /Users/Shared/code/drupal/modules/user/user.module,v
retrieving revision 1.914
diff -u -p -r1.914 user.module
--- modules/user/user.module	8 Aug 2008 19:48:43 -0000	1.914
+++ modules/user/user.module	12 Aug 2008 00:58:45 -0000
@@ -760,7 +760,7 @@ function user_block($op = 'list', $delta
         if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
 
           $block['subject'] = t('User login');
-          $block['content'] = drupal_get_form('user_login_block');
+          $block['content'] = drupal_render(drupal_get_form('user_login_block'));
         }
         return $block;
 
Index: themes/garland/page.tpl.php
===================================================================
RCS file: /Users/Shared/code/drupal/themes/garland/page.tpl.php,v
retrieving revision 1.20
diff -u -p -r1.20 page.tpl.php
--- themes/garland/page.tpl.php	28 Apr 2008 09:25:27 -0000	1.20
+++ themes/garland/page.tpl.php	12 Aug 2008 00:58:45 -0000
@@ -14,7 +14,7 @@
   </head>
   <body class="<?php print $body_classes ?>">
 
-  <div id="header-region" class="clear-block"><?php print $header ?></div>
+  <div id="header-region" class="clear-block"><?php render($header) ?></div>
 
   <div id="wrapper">
     <div id="container" class="clear-block">
@@ -38,7 +38,7 @@
       <?php if ($left): ?>
         <div id="sidebar-left" class="sidebar">
           <?php if ($search_box): ?><div class="block block-theme"><?php print $search_box ?></div><?php endif; ?>
-          <?php print $left ?>
+          <?php render($left) ?>
         </div>
       <?php endif; ?>
 
@@ -52,16 +52,16 @@
           <?php if ($show_messages && $messages): print $messages; endif; ?>
           <?php print $help; ?>
           <div class="clear-block">
-            <?php print $content ?>
+            <?php render($content) ?>
           </div>
           <?php print $feed_icons ?>
-          <div id="footer"><?php print $footer_message . $footer ?></div>
+          <div id="footer"><?php print $footer_message; render($footer) ?></div>
       </div></div></div></div> <!-- /.left-corner, /.right-corner, /#squeeze, /#center -->
 
       <?php if ($right): ?>
         <div id="sidebar-right" class="sidebar">
           <?php if (!$left && $search_box): ?><div class="block block-theme"><?php print $search_box ?></div><?php endif; ?>
-          <?php print $right ?>
+          <?php render($right) ?>
         </div>
       <?php endif; ?>
 
