Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.462
diff -u -p -r1.462 form.inc
--- includes/form.inc	12 May 2010 08:26:14 -0000	1.462
+++ includes/form.inc	13 May 2010 16:38:38 -0000
@@ -264,6 +264,12 @@ function drupal_build_form($form_id, &$f
     }
   }
 
+  // Modules are able to use hook_form_alter() to alter the form prior to it
+  // being processed, but also allow them to alter the form after it has been
+  // processed. Alterations that affect display only should be implemented
+  // using this hook.
+  drupal_alter(array('form_view', 'form_view_' . $form_id), $form, $form_state, $form_id);
+
   return $form;
 }
 
@@ -774,11 +780,21 @@ function drupal_prepare_form($form_id, &
     }
   }
 
-  // Invoke hook_form_alter() and hook_form_FORM_ID_alter() implementations.
-  drupal_alter(array('form', 'form_' . $form_id), $form, $form_state, $form_id);
+  // Invoke hook_form_alter() and hook_form_FORM_ID_alter() implementations, but
+  // avoid conflict with hook_form_view_alter() and
+  // hook_form_view_FORM_ID_alter(). The only form ids that start with 'view_'
+  // are node forms for node types that start with 'view_' (see
+  // http://drupal.org/node/798062 about fixing that), and module-defined forms
+  // for modules that start with 'view_'. Altering these forms requires using
+  // hook_form_alter() with an if/switch statement. Form ids should end with
+  // '_form', so there should not be a form whose id is 'view'.
+  $types = array('form');
+  if (substr($form_id, 0, 5) != 'view_' && $form_id != 'view') {
+    $types[] = 'form_' . $form_id;
+  }
+  drupal_alter($types, $form, $form_state, $form_id);
 }
 
-
 /**
  * Validates user-submitted form data from the $form_state using
  * the validate functions defined in a structured form array.
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.167
diff -u -p -r1.167 system.api.php
--- modules/system/system.api.php	7 May 2010 12:59:07 -0000	1.167
+++ modules/system/system.api.php	13 May 2010 16:38:44 -0000
@@ -1252,7 +1252,7 @@ function hook_page_alter(&$page) {
 }
 
 /**
- * Perform alterations before a form is rendered.
+ * Perform alterations before a form is processed.
  *
  * One popular use of this hook is to add form elements to the node form. When
  * altering a node form, the node object can be accessed at $form['#node'].
@@ -1264,6 +1264,13 @@ function hook_page_alter(&$page) {
  * After all module hook implementations are invoked, the hook_form_alter()
  * implementations from themes are invoked in the same manner.
  *
+ * This hook runs before the form is processed (i.e., before element #process
+ * functions have been called), so it cannot be used to alter elements added
+ * during form processing, and changes made by an implementation of this hook
+ * will affect how the form is processed. In many cases, modules or themes only
+ * want to alter the rendering, but not the processing of a form. These cases
+ * should use hook_form_view_alter() instead.
+ *
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
@@ -1273,6 +1280,7 @@ function hook_page_alter(&$page) {
  *   name of the function that generated the form.
  *
  * @see hook_form_FORM_ID_alter()
+ * @see hook_form_view_alter()
  */
 function hook_form_alter(&$form, &$form_state, $form_id) {
   if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
@@ -1292,6 +1300,10 @@ function hook_form_alter(&$form, &$form_
  * rather than implementing hook_form_alter() and checking the form ID, or
  * using long switch statements to alter multiple forms.
  *
+ * This hook does not run for form IDs that start with 'view_', as that would
+ * conflict with hook_form_view_FORM_ID_alter(). Altering those forms requires
+ * using hook_form_alter() and checking the form ID.
+ *
  * @param $form
  *   Nested array of form elements that comprise the form.
  * @param $form_state
@@ -1314,6 +1326,53 @@ function hook_form_FORM_ID_alter(&$form,
 }
 
 /**
+ * Perform alterations before a form is rendered.
+ *
+ * Note that instead of hook_form_view_alter(), which is called for all forms,
+ * you can also use hook_form_view_FORM_ID_alter() to alter a specific form. For
+ * each module (in system weight order) the general hook implementation is
+ * invoked first, then the form ID specific implementation is called. After all
+ * module hook implementations are invoked, the general and specific
+ * implementations from themes are invoked in the same manner.
+ *
+ * @param $form
+ *   Nested array of form elements that comprise the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form.
+ * @param $form_id
+ *   String representing the name of the form itself. Typically this is the
+ *   name of the function that generated the form.
+ *
+ * @see hook_form_view_FORM_ID_alter()
+ * @see hook_form_alter()
+ */
+function hook_form_view_alter(&$form, &$form_state, $form_id) {
+  // @todo Add an example.
+}
+
+/**
+ * Provide a form-specific alteration instead of the global hook_form_view_alter().
+ *
+ * Modules can implement hook_form_view_FORM_ID_alter() to modify a specific
+ * form, rather than implementing hook_form_view_alter() and checking the form
+ * ID, or using long switch statements to alter multiple forms.
+ *
+ * @param $form
+ *   Nested array of form elements that comprise the form.
+ * @param $form_state
+ *   A keyed array containing the current state of the form.
+ *
+ * @see hook_form_view_alter()
+ */
+function hook_form_view_FORM_ID_alter(&$form, &$form_state) {
+  // Modification for the form with the given form ID goes here. For example, if
+  // FORM_ID is "user_register_form" this code would run only on the user
+  // registration form.
+
+  // @todo Add an example.
+}
+
+/**
  * Map form_ids to form builder functions.
  *
  * By default, when drupal_get_form() is called, the system will look for a
