=== modified file 'includes/view.inc'
--- includes/view.inc	2008-04-02 15:17:11 +0000
+++ includes/view.inc	2008-04-02 20:04:28 +0000
@@ -165,12 +165,36 @@ class view extends views_db_object {
   }
 
   /**
+   * Get the first display that is accessible to the user.
+   *
+   * @param $displays
+   *   Either a single display id or an array of display ids.
+   */
+  function choose_display($displays, $account = NULL) {
+    if (!is_array($displays)) {
+      return $displays;
+    }
+    if (empty($account)) {
+      $account = $GLOBALS['user'];
+    }
+    foreach ($displays as $display_id) {
+      if (!empty($this->display[$display_id]->handler) && $this->display[$display_id]->handler->access($account)) {
+        return $display_id;
+      }
+    }
+    return NULL;
+  }
+
+  /**
    * Set the display as current.
    *
    * @param $display_id
-   *   The id of the display to mark as current.
+   *   The id of the display to mark as current.  May also be an array of IDs;
+   *   in this case the first display accessible to the user will be chosen.
    */
   function set_display($display_id = NULL) {
+    $display_id = $this->choose_display($display_id);
+
     // If we have not already initialized the display, do so. But be careful.
     if (empty($this->current_display)) {
       $this->init_display();
@@ -602,9 +626,14 @@ class view extends views_db_object {
    * Execute the given display, with the given arguments.
    * To be called externally by whatever mechanism invokes the view,
    * such as a page callback, hook_block, etc.
+   *
+   * @param $display_id
+   *   Either a single display ID or an array of display IDs.  If an
+   *   array is given, the first display accessible to the user will
+   *   be executed.
    */
   function execute_display($display_id = NULL, $args = array()) {
-    if (empty($this->current_display) || $this->current_display != $display_id) {
+    if (empty($this->current_display) || $this->current_display != $this->choose_display($display_id)) {
       if (!$this->set_display($display_id)) {
         return FALSE;
       }
@@ -691,9 +720,15 @@ class view extends views_db_object {
       $account = $GLOBALS['user'];
     }
 
-    if (!empty($this->display[$display_id]->handler)) {
+    if (is_array($display_id)) {
+      $display_id = $this->choose_display($display_id, $account);
+      return !empty($display_id);
+    }
+    else if (!empty($this->display[$display_id]->handler)) {
       return $this->display[$display_id]->handler->access($account);
     }
+
+    return FALSE;
   }
 
   /**

=== modified file 'views.module'
--- views.module	2008-04-02 15:17:11 +0000
+++ views.module	2008-04-02 20:21:40 +0000
@@ -110,18 +110,9 @@ function views_help($path, $arg) {
 
 /**
  * Implementation of hook_menu().
- *
- * This probably needs to actually be hook_menu_alter or something.
  */
 function views_menu() {
   $items = array();
-  foreach (views_get_page_views() as $data) {
-    list($view, $display_id) = $data;
-    $result = $view->execute_hook_menu($display_id);
-    if (is_array($result)) {
-      $items = array_merge($items, $result);
-    }
-  }
   $items['views/ajax'] = array(
     'title' => t('Views'),
     'page callback' => 'views_ajax',
@@ -134,6 +125,60 @@ function views_menu() {
 }
 
 /**
+ * Implementation of hook_menu_alter().
+ */
+function views_menu_alter(&$callbacks) {
+  $our_paths = array();
+  foreach (views_get_page_views() as $data) {
+    list($view, $display_id) = $data;
+    $result = $view->execute_hook_menu($display_id);
+    if (is_array($result)) {
+      // The menu system doesn't support having two otherwise
+      // identical paths with different placeholders.  So we
+      // want to remove the existing items from the menu whose
+      // paths would conflict with ours.
+
+      // First, we must find any existing menu items that may
+      // conflict.  We use a regular expression because we don't
+      // know what placeholders they might use.  Note that we
+      // first construct the regex itself by replacing %views_arg
+      // in the display path, then we use this constructed regex
+      // (which will be something like '#foo/%[^/]*/bar#') to
+      // search through the existing paths.
+      $regex = '#'. preg_replace('#%views_arg#', '%[^/]*', implode('|', array_keys($result))) .'#';
+      $matches = preg_grep($regex, array_keys($callbacks));
+
+      // Remove any conflicting items that were found.
+      foreach ($matches as $path) {
+        // Don't remove the paths we just added!
+        if (!isset($our_paths[$path])) {
+          unset($callbacks[$path]);
+        }
+      }
+      foreach ($result as $path => $item) {
+        if (!isset($callbacks[$path])) {
+          // Add a new item, possibly replacing (and thus effectively
+          // overriding) one that we removed above.
+          $callbacks[$path] = $item;
+        }
+        else {
+          // This item already exists, so it must be one that we added.
+          // We change the various callback arguments to pass an array
+          // of possible display IDs instead of a single ID.
+          $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1];
+          $callbacks[$path]['page arguments'][1][] = $display_id;
+          $callbacks[$path]['access arguments'][0][1] = (array)$callbacks[$path]['access arguments'][0][1];
+          $callbacks[$path]['access arguments'][0][1][] = $display_id;
+          $callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1];
+          $callbacks[$path]['load arguments'][1][] = $display_id;
+        }
+        $our_paths[$path] = TRUE;
+      }
+    }
+  }
+}
+
+/**
  * Helper function for menu loading. This will automatically be
  * called in order to 'load' a views argument; primarily it
  * will be used to perform validation.
@@ -238,8 +283,8 @@ function views_invalidate_cache() {
  * Determine if the given user has access to the view + display.
  *
  * @param $view
- *   May be a view object, or an array with the view name and the display ID,
- *   or a string to use as the view name.
+ *   May be a view object, or an array with the view name and the display ID
+ *   (or an array of display IDs), or a string to use as the view name.
  * @param $account
  *   An optional account to use; if left off, the current user will be used.
  */

