diff --git a/inc/fulltext.php b/inc/fulltext.php
index 14286252957dec0bc64bad0894d8519dfd27249e..c4d8a7ea737e57ed75fdb2e8c98ed6fa64c5f502 100644
--- a/inc/fulltext.php
+++ b/inc/fulltext.php
@@ -213,54 +213,55 @@ function ft_mediause($id,$max){
  * Quicksearch for pagenames
  *
  * By default it only matches the pagename and ignores the
- * namespace. This can be changed with the second parameter
+ * namespace. This can be changed with the second parameter.
+ * The third parameter allows to search in titles as well.
+ * If the function should search in titles as well, the return array
+ * has the ids as key and the titles as value.
  *
  * refactored into ft_pageLookup(), _ft_pageLookup() and trigger_event()
  *
  * @author Andreas Gohr <andi@splitbrain.org>
  */
-function ft_pageLookup($id,$pageonly=true){
-    $data = array('id' => $id, 'pageonly' => $pageonly);
-    return trigger_event('SEARCH_QUERY_PAGELOOKUP',$data,'_ft_pageLookup');
+function ft_pageLookup($id, $not_in_ns=true, $not_in_title=true){
+    $data = compact('id', 'not_in_ns', 'not_in_title');
+    return trigger_event('SEARCH_QUERY_PAGELOOKUP', $data, '_ft_pageLookup');
 }
 
 function _ft_pageLookup(&$data){
-    // split out original parameterrs
+    // split out original parameters
     $id = $data['id'];
-    $pageonly = $data['pageonly'];
+    $in_ns = !$data['not_in_ns'];
+    $in_title = !$data['not_in_title'];
 
     global $conf;
-    $id    = preg_quote($id,'/');
-    $pages = file($conf['indexdir'].'/page.idx');
-    if($id) $pages = array_values(preg_grep('/'.$id.'/',$pages));
-
-    $cnt = count($pages);
-    for($i=0; $i<$cnt; $i++){
-        if($pageonly){
-            if(!preg_match('/'.$id.'/',noNS($pages[$i]))){
-                unset($pages[$i]);
-                continue;
+    $pages  = array_map('rtrim', file($conf['indexdir'].'/page.idx'));
+    $titles = array_map('rtrim', file($conf['indexdir'].'/title.idx'));
+    $pages = array_combine($pages, $titles);
+
+    if($id !== '' && cleanID($id) !== '') {
+        $cleaned = cleanID($id);
+        $matched_pages = array();
+        foreach ($pages as $p_id => $p_title) {
+            if ((strpos($in_ns ? $p_id : noNS($p_id), $cleaned) !== false) ||
+                ($in_title && stripos($p_title, $id) !== false)) {
+                $matched_pages[$p_id] = $p_title;
             }
         }
-        if(!page_exists($pages[$i])){
-            unset($pages[$i]);
-            continue;
-        }
+        $pages = $matched_pages;
     }
 
-    $pages = array_filter($pages,'isVisiblePage'); // discard hidden pages
-    if(!count($pages)) return array();
-
+    // discard hidden pages
+    // discard nonexistent pages
     // check ACL permissions
     foreach(array_keys($pages) as $idx){
-        if(auth_quickaclcheck(trim($pages[$idx])) < AUTH_READ){
+        if(!isVisiblePage($idx) || !page_exists($idx) ||
+           auth_quickaclcheck($idx) < AUTH_READ) {
             unset($pages[$idx]);
         }
     }
 
-    $pages = array_map('trim',$pages);
-    usort($pages,'ft_pagesorter');
-    return $pages;
+    uasort($pages,'ft_pagesorter');
+    return $in_title ? $pages : array_keys($pages);
 }
 
 /**
diff --git a/inc/indexer.php b/inc/indexer.php
index 54277a88c5100c33daff8fe08a840604e21ef6b0..01ba76b08f2aa3c5536443da97c95ba3b008e6f6 100644
--- a/inc/indexer.php
+++ b/inc/indexer.php
@@ -305,6 +305,8 @@ function idx_addPage($page){
     }
     unset($page_idx); // free memory
 
+    idx_saveIndexLine('title', '', $pid, p_get_first_heading($page, false));
+
     $pagewords = array();
     // get word usage in page
     $words = idx_getPageWords($page);
diff --git a/lib/exe/ajax.php b/lib/exe/ajax.php
index a402c236f54200e868a54ff1ec1a003ecc4b81e4..9c10ca5485a4ffe4d19ceb5634d8a94fcec413ba 100644
--- a/lib/exe/ajax.php
+++ b/lib/exe/ajax.php
@@ -50,27 +50,28 @@ function ajax_qsearch(){
   global $conf;
   global $lang;
 
-  $query = cleanID($_POST['q']);
-  if(empty($query)) $query = cleanID($_GET['q']);
+  $query = $_POST['q'];
+  if(empty($query)) $query = $_GET['q'];
   if(empty($query)) return;
 
-  $data = array();
-  $data = ft_pageLookup($query);
+  $data = ft_pageLookup($query, true, false);
 
   if(!count($data)) return;
 
   print '<strong>'.$lang['quickhits'].'</strong>';
   print '<ul>';
-  foreach($data as $id){
-    print '<li>';
-    $ns = getNS($id);
-    if($ns){
-      $name = shorten(noNS($id), ' ('.$ns.')',30);
-    }else{
-      $name = $id;
+  foreach($data as $id => $title){
+    if (useHeading('navigation')) {
+        $name = $title;
+    } else {
+        $ns = getNS($id);
+        if($ns){
+          $name = shorten(noNS($id), ' ('.$ns.')',30);
+        }else{
+          $name = $id;
+        }
     }
-    print html_wikilink(':'.$id,$name);
-    print '</li>';
+    echo '<li>' . html_wikilink(':'.$id,$name) . '</li>';
   }
   print '</ul>';
 }