diff --git a/wysiwyg-dialog-page.tpl.php b/wysiwyg-dialog-page.tpl.php
index 0811ae7..3e77d79 100644
--- a/wysiwyg-dialog-page.tpl.php
+++ b/wysiwyg-dialog-page.tpl.php
@@ -2,83 +2,27 @@
 
 /**
  * @file
- * Theme template to display a single Wysiwyg (plugin) dialog page.
- *
- * Available variables:
- *
- * General utility variables:
- * - $base_path: The base URL path of the Drupal installation. At the very
- *   least, this will always default to /.
- * - $css: An array of CSS files for the current page.
- * - $directory: The directory the theme is located in, e.g. themes/garland or
- *   themes/garland/minelli.
- * - $logged_in: TRUE if the user is registered and signed in.
- * - $is_admin: TRUE if the user has permission to access administration pages.
- *
- * Page metadata:
- * - $language: (object) The language the site is being displayed in.
- *   $language->language contains its textual representation.
- *   $language->dir contains the language direction. It will either be 'ltr' or 'rtl'.
- * - $head_title: A modified version of the page title, for use in the TITLE tag.
- * - $head: Markup for the HEAD section (including meta tags, keyword tags, and
- *   so on).
- * - $styles: Style tags necessary to import all CSS files for the page.
- * - $scripts: Script tags necessary to load the JavaScript files and settings
- *   for the page.
- *
- * Site identity:
- * - $site_name: The name of the site, empty when display has been disabled
- *   in theme settings.
- *
- * Page content (in order of occurrance in the default page.tpl.php):
- * - $breadcrumb: The breadcrumb trail for the current page.
- * - $title: The page title, for use in the actual HTML content.
- * - $help: Dynamic help text, mostly for admin pages.
- * - $messages: HTML for status and error messages. Should be displayed prominently.
- * - $tabs: Tabs linking to any sub-pages beneath the current page (e.g., the view
- *   and edit tabs when displaying a node).
- *
- * - $content: The main content of the current Drupal page.
- *
- * Footer/closing data:
- * - $footer : The footer region.
- * - $closure: Final closing markup from any modules that have altered the page.
- *   This variable should always be output last, after all other dynamic content.
- *
- * @see template_preprocess()
- * @see template_preprocess_wysiwyg_dialog_page()
+ * Theme implementation to display a single Wysiwyg (plugin) dialog page.
  */
 ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>" lang="<?php print $language->language ?>" dir="<?php print $language->dir ?>">
 
-<head>
-  <title><?php print $head_title; ?></title>
-  <?php print $head; ?>
-  <?php print $styles; ?>
-  <?php print $scripts; ?>
-  <script type="text/javascript"><?php /* Needed to avoid Flash of Unstyled Content in IE */ ?> </script>
-</head>
-<body>
   <div id="page">
-    <div id="container" class="clear-block">
-      <div id="main" class="column">
-        <?php if (!empty($breadcrumb)): ?><div id="breadcrumb"><?php print $breadcrumb; ?></div><?php endif; ?>
 
-        <div id="content">
-          <?php if (!empty($title)): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
-          <?php if (!empty($tabs)): ?><div class="tabs"><?php print $tabs; ?></div><?php endif; ?>
-          <?php if (!empty($messages)): print $messages; endif; ?>
-          <?php if (!empty($help)): print $help; endif; ?>
-          <div id="content-content" class="clear-block">
-            <?php print $content; ?>
-          </div>
-        </div>
+    <?php print $messages; ?>
 
-      </div>
-    </div>
-  </div>
-<?php print $closure; ?>
-</body>
-</html>
+    <div id="main-wrapper"><div id="main" class="clearfix">
+
+      <div id="content" class="column"><div class="section">
+        <a id="main-content"></a>
+        <?php print render($title_prefix); ?>
+        <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
+        <?php print render($title_suffix); ?>
+        <?php if ($tabs): ?><div class="tabs"><?php print render($tabs); ?></div><?php endif; ?>
+        <?php print render($page['help']); ?>
+        <?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?>
+        <?php print render($page['content']); ?>
+      </div></div> <!-- /.section, /#content -->
+
+    </div></div> <!-- /#main, /#main-wrapper -->
+
+  </div> <!-- /#page -->
diff --git a/wysiwyg.dialog.inc b/wysiwyg.dialog.inc
index 500f78d..8c42bc4 100644
--- a/wysiwyg.dialog.inc
+++ b/wysiwyg.dialog.inc
@@ -6,7 +6,68 @@
  */
 
 /**
- * Menu callback; Output a wysiwyg plugin dialog page.
+ * Page callback; Outputs a dialog page for a wysiwyg plugin.
+ *
+ * A Wysiwyg dialog is a bare minimum, simple HTML page; presented in a
+ * modal/popup window, triggered via JavaScript.
+ *
+ * However, Drupal core does not support such a concept, at all.
+ * Insanity happens on two separate layers:
+ * - All HTML pages go through the default delivery callback of
+ *   drupal_deliver_html_page(), which calls into drupal_render_page(), which
+ *   in turn *unconditionally* invokes hook_page_build() implementations. Thus,
+ *   block_page_build() and similar implementations add the entirety of their
+ *   page regions and blocks to our simple dialog page.
+ *   Obviously, we don't want that.
+ * - There is a nice default 'page' theme template implementation, which
+ *   performs all the heavy-lifting that is required for outputting a sane HTML
+ *   page through preprocess and process functions. The theme system does not
+ *   support to "inherit" preprocess and process hooks to alternative
+ *   implementations. Even a very basic HTML page requires almost all of that.
+ *   However, the default page template (normally overridden by a theme)
+ *   contains too many regions and usually also huge a header and footer.
+ *   Obviously, we don't want that.
+ *
+ * The poor workaround would be to follow the Overlay module's implementation in
+ * core: override the theme, build everything, and after doing all of that,
+ * strip away what isn't needed. Obviously, we don't want that.
+ *
+ * Instead, we bend Drupal to sane rules:
+ * - This page callback returns the actual main content.
+ * - wysiwyg_menu() defines a custom delivery callback that replaces
+ *   drupal_deliver_html_page(), just because we need to replace
+ *   drupal_render_page().
+ * - Our replacement for drupal_render_page() builds a $page that does not use
+ *   #type 'page' but #type 'wysiwyg_dialog_page' instead.
+ * - #type 'wysiwyg_dialog_page' is defined like #type 'page' in
+ *   system_element_info(), but is required, because there's no way to inherit
+ *   a theme definition but override the page template file to be used.
+ * - As a consequence, #type 'wysiwyg_dialog_page' uses
+ *   #theme 'wysiwyg_dialog_page', for which we have to implement stub
+ *   preprocess and process callbacks in order to call into the ones for
+ *   #theme 'page'.
+ *
+ * As a result we get:
+ * - A HTML response.
+ * - A HTML page wrapped into html.tpl.php.
+ * - A page title, title prefix/suffix, messages, help, etc.pp.
+ * - A simple page without regions and blocks (neither built nor rendered).
+ *
+ * @see wysiwyg_menu()
+ * @see wysiwyg_deliver_dialog_page
+ * @see wysiwyg_render_dialog_page()
+ * @see wysiwyg_element_info()
+ * @see wysiwyg_theme()
+ * @see template_preprocess_wysiwyg_dialog_page()
+ * @see template_process_wysiwyg_dialog_page()
+ *
+ * @see drupal_deliver_page()
+ * @see drupal_deliver_html_page()
+ * @see drupal_render_page()
+ * @see system_element_info()
+ * @see drupal_common_theme()
+ * @see template_preprocess_page()
+ * @see template_process_page()
  */
 function wysiwyg_dialog($plugin, $instance) {
   $plugins = wysiwyg_get_all_plugins();
@@ -27,7 +88,74 @@ function wysiwyg_dialog($plugin, $instance) {
   );
   drupal_add_js(array('wysiwyg' => $settings), 'setting');
 
-  echo theme('wysiwyg_dialog_page', $callback($instance));
+  $build = $callback($instance);
+  if (!is_array($build)) {
+    $build = array('#markup' => $build);
+  }
+  $build += array(
+    '#instance' => $instance,
+    '#plugin' => $plugin,
+  );
+  return $build;
+}
+
+/**
+ * @see drupal_deliver_html_page()
+ */
+function wysiwyg_deliver_dialog_page($page_callback_result) {
+  // Menu status constants are integers; page content is a string or array.
+  if (is_int($page_callback_result)) {
+    return drupal_deliver_html_page($page_callback_result);
+  }
+
+  // Emit the correct charset HTTP header, but not if the page callback
+  // result is NULL, since that likely indicates that it printed something
+  // in which case, no further headers may be sent, and not if code running
+  // for this page request has already set the content type header.
+  if (isset($page_callback_result) && is_null(drupal_get_http_header('Content-Type'))) {
+    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
+  }
+
+  // Send appropriate HTTP-Header for browsers and search engines.
+  global $language;
+  drupal_add_http_header('Content-Language', $language->language);
+
+  if (isset($page_callback_result)) {
+    // Print anything besides a menu constant, assuming it's not NULL or
+    // undefined.
+    print wysiwyg_render_dialog_page($page_callback_result);
+  }
+
+  // Perform end-of-request tasks.
+  drupal_page_footer();
+}
+
+/**
+ * @see drupal_render_page()
+ */
+function wysiwyg_render_dialog_page($page) {
+  $main_content_display = &drupal_static('system_main_content_added', FALSE);
+
+  // Allow menu callbacks to return strings or arbitrary arrays to render.
+  // If the array returned is not of #type page directly, we need to fill
+  // in the page with defaults.
+  if (is_string($page) || (is_array($page) && (!isset($page['#type']) || ($page['#type'] != 'page')))) {
+    drupal_set_page_content($page);
+    $page = element_info('wysiwyg_dialog_page');
+  }
+
+  // Modules alter the $page as needed. Blocks are populated into regions like
+  // 'sidebar_first', 'footer', etc.
+  drupal_alter(array('wysiwyg_dialog_page', 'page'), $page);
+
+  // If no module has taken care of the main content, add it to the page now.
+  // This allows the site to still be usable even if no modules that
+  // control page regions (for example, the Block module) are enabled.
+  if (!$main_content_display) {
+    $page['content']['system_main'] = drupal_set_page_content();
+  }
+
+  return drupal_render($page);
 }
 
 /**
@@ -35,29 +163,21 @@ function wysiwyg_dialog($plugin, $instance) {
  *
  * @see wysiwyg_dialog()
  * @see wysiwyg-dialog-page.tpl.php
- * @see template_preprocess()
+ * @see template_preprocess_page()
  */
 function template_preprocess_wysiwyg_dialog_page(&$variables) {
-  // Construct page title
-  $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
-
-  $variables['head_title']        = implode(' | ', $head_title);
-  $variables['base_path']         = base_path();
-  $variables['front_page']        = url();
-  // @todo Would a breadcrumb make sense / possible at all?
-  // $variables['breadcrumb']        = theme('breadcrumb', drupal_get_breadcrumb());
-  $variables['head']              = drupal_get_html_head();
-  $variables['help']              = theme('help');
-  $variables['language']          = $GLOBALS['language'];
-  $variables['language']->dir     = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
-  $variables['messages']          = $variables['show_messages'] ? theme('status_messages') : '';
-  $variables['site_name']         = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
-  $variables['css']               = drupal_add_css();
-  $variables['styles']            = drupal_get_css();
-  $variables['scripts']           = drupal_get_js();
-  $variables['tabs']              = theme('menu_local_tasks');
-  $variables['title']             = drupal_get_title();
-  // Closure should be filled last.
-  $variables['closure']           = theme('closure');
+  template_preprocess_page(&$variables);
+}
+
+
+/**
+ * Template process function for theme_wysiwyg_dialog_page().
+ *
+ * @see wysiwyg_dialog()
+ * @see wysiwyg-dialog-page.tpl.php
+ * @see template_process_page()
+ */
+function template_process_wysiwyg_dialog_page(&$variables) {
+  template_process_page(&$variables);
 }
 
diff --git a/wysiwyg.module b/wysiwyg.module
index ec483e0..b6a4027 100644
--- a/wysiwyg.module
+++ b/wysiwyg.module
@@ -79,9 +79,11 @@ function wysiwyg_menu() {
     'type' => MENU_LOCAL_TASK,
     'weight' => 10,
   );
+  // @see wysiwyg_dialog()
   $items['wysiwyg/%'] = array(
     'page callback' => 'wysiwyg_dialog',
     'page arguments' => array(1),
+    'delivery callback' => 'wysiwyg_deliver_dialog_page',
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
     'file' => 'wysiwyg.dialog.inc',
@@ -90,6 +92,19 @@ function wysiwyg_menu() {
 }
 
 /**
+ * Implements hook_element_info().
+ */
+function wysiwyg_element_info() {
+  // @see wysiwyg_dialog()
+  $types['wysiwyg_dialog_page'] = array(
+    '#theme' => 'wysiwyg_dialog_page',
+    '#theme_wrappers' => array('html'),
+    '#show_messages' => TRUE,
+  );
+  return $types;
+}
+
+/**
  * Implementation of hook_theme().
  *
  * @see drupal_common_theme(), common.inc
@@ -103,8 +118,9 @@ function wysiwyg_theme() {
     'wysiwyg_admin_button_table' => array(
       'render element' => 'form',
     ),
+    // @see wysiwyg_dialog()
     'wysiwyg_dialog_page' => array(
-      'variables' => array('content' => NULL, 'show_messages' => TRUE),
+      'render element' => 'page',
       'file' => 'wysiwyg.dialog.inc',
       'template' => 'wysiwyg-dialog-page',
     ),
