diff -ur a/data/epdfview-ui.xml b/data/epdfview-ui.xml
--- a/data/epdfview-ui.xml	2009-10-29 23:45:04.000000000 +0300
+++ b/data/epdfview-ui.xml	2009-10-30 01:19:38.000000000 +0300
@@ -27,6 +27,7 @@
       <menuitem name="ZoomWidth" action="ZoomWidth"/>
       <separator />
       <menuitem name="FullScreen" action="FullScreen"/>
+      <menuitem name="DualPages" action="DualPages"/>
       <separator />
       <menuitem name="RotateRight" action="RotateRight"/>
       <menuitem name="RotateLeft" action="RotateLeft"/>
diff -ur a/po/ru.po b/po/ru.po
--- a/po/ru.po	2009-10-29 23:45:04.000000000 +0300
+++ b/po/ru.po	2009-10-30 01:23:47.000000000 +0300
@@ -319,6 +319,10 @@
 msgstr "Переключить полноэкранный режим"
 
 #: src/gtk/MainView.cxx:179
+msgid "_Dual pages"
+msgstr "По две страницы"
+
+#: src/gtk/MainView.cxx:179
 msgid "Show _Toolbar"
 msgstr "Показать панель инструментов"
 
diff -ur a/src/Config.cxx b/src/Config.cxx
--- a/src/Config.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/Config.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -33,6 +33,8 @@
 static const gint DEFAULT_WINDOW_Y = 0;
 static const gboolean DEFAULT_ZOOM_TO_FIT = FALSE;
 static const gboolean DEFAULT_ZOOM_TO_WIDTH = FALSE;
+static const gboolean DEFAULT_DUAL_PAGES = FALSE;
+static const guint PAGES_COUNT = 2;
 
 // Static member attributes.
 Config *Config::m_Config = NULL;
@@ -445,6 +447,18 @@
 }
 
 ///
+/// @brief Sets the dual pages option.
+///
+/// @param activate Set to TRUE to activate the dual pages option. FALSE
+///        otherwise.
+///
+void
+Config::setDualPages (gboolean activate)
+{
+    g_key_file_set_boolean (m_Values, "main window", "dualPages", activate);
+}
+
+///
 /// @brief Gets if show the status bar.
 ///
 /// @return TRUE if the status bar should be shown, FALSE otherwise.
@@ -489,6 +503,17 @@
 }
 
 ///
+/// @brief Gets the dual pages mode option.
+///
+/// @return TRUE if the dual pages mode is activated. FALSE otherwise.
+///
+gboolean
+Config::dualPages ()
+{
+    return getBoolean ("main window", "dualPages", DEFAULT_DUAL_PAGES);
+}
+
+///
 /// @brief Gets the configuration file name.
 ///
 /// This function creates the directory where the configuration file should
@@ -507,3 +532,15 @@
 
     return configFile;
 }
+
+///
+/// @brief Gets count of pages being displayed to user in multi-pages mode.
+///
+/// @return The saved value of pages for multi-pages mode. Currently only dual
+///         pages mode is supported, so the result is always 2.
+///
+guint
+Config::getPagesCount ()
+{    
+    return PAGES_COUNT;
+}
diff -ur a/src/Config.h b/src/Config.h
--- a/src/Config.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/Config.h	2009-10-30 01:19:38.000000000 +0300
@@ -35,6 +35,7 @@
             static void destroy (void);
             static Config &getConfig (void);
             static void loadFile (gboolean load);
+            static guint getPagesCount (void);
 
             ~Config (void);
 
@@ -49,6 +50,7 @@
             gboolean showToolbar (void);
             gboolean zoomToFit (void);
             gboolean zoomToWidth (void);
+            gboolean dualPages (void);
             void save(void);
             void setExternalBrowserCommandLine (const gchar *commandLine);
             void setOpenFileFolder (const gchar *folder);
@@ -59,6 +61,7 @@
             void setWindowPos (gint x, gint y);
             void setZoomToFit (gboolean active);
             void setZoomToWidth (gboolean active);
+            void setDualPages (gboolean active);
 
         protected:
             /// The configuration values.
diff -ur a/src/FindPter.cxx b/src/FindPter.cxx
--- a/src/FindPter.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/FindPter.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -89,7 +89,10 @@
     {
         DocumentRectangle *rect = ((DocumentRectangle *)m_CurrentMatch->data);
         m_Document->notifyFindChanged (m_FindPage, rect);
-        m_Document->goToPage (m_FindPage);
+        if ( !m_Document->isPageVisible (m_FindPage) )
+        {
+            m_Document->goToPage (m_FindPage);
+        }
     }
     else
     {
@@ -118,7 +121,10 @@
     {
         DocumentRectangle *rect = ((DocumentRectangle *)m_CurrentMatch->data);
         m_Document->notifyFindChanged (m_FindPage, rect);
-        m_Document->goToPage (m_FindPage);
+        if ( !m_Document->isPageVisible (m_FindPage) )
+        {
+            m_Document->goToPage (m_FindPage);
+        }
     }
     else
     {
@@ -229,7 +235,10 @@
     }
     DocumentRectangle *rect = (DocumentRectangle *)m_CurrentMatch->data;
     m_Document->notifyFindChanged (m_FindPage, rect);
-    m_Document->goToPage (m_FindPage);
+    if ( !m_Document->isPageVisible (m_FindPage) )
+    {
+        m_Document->goToPage (m_FindPage);
+    }
 
     IFindView &view = getView ();
     view.setInformationText ("");
diff -ur a/src/gtk/MainView.cxx b/src/gtk/MainView.cxx
--- a/src/gtk/MainView.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/gtk/MainView.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -53,6 +53,7 @@
                                             gpointer);
 static void main_window_find_cb (GtkWidget *, gpointer);
 static void main_window_fullscreen_cb (GtkToggleAction *, gpointer);
+static void main_window_dualpages_cb (GtkToggleAction *, gpointer);
 static gboolean main_window_moved_or_resized_cb (GtkWidget *,
                                                  GdkEventConfigure *, gpointer);
 static void main_window_go_to_first_page_cb (GtkWidget *, gpointer);
@@ -176,6 +177,10 @@
       N_("Toggle full screen window"),
       G_CALLBACK (main_window_fullscreen_cb), FALSE },
 
+    { "DualPages", NULL, N_("_Dual pages"), NULL,
+      N_("Toggle single/dual view mode"),
+      G_CALLBACK (main_window_dualpages_cb), FALSE },
+
     { "ShowToolBar", NULL, N_("Show _Toolbar"), NULL,
       N_("Show or hide the toolbar"),
       G_CALLBACK (main_window_show_toolbar_cb), TRUE },
@@ -298,6 +303,14 @@
 }
 
 void
+MainView::activeDualPages (gboolean active)
+{
+    GtkAction *dualPages =
+        gtk_ui_manager_get_action (m_UIManager, "/MenuBar/ViewMenu/DualPages");
+    gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (dualPages), active);
+}
+
+void
 MainView::activePageModeScroll (gboolean active)
 {
     GtkAction *action =
@@ -624,6 +637,14 @@
 }
 
 void
+MainView::sensitiveDualPages (gboolean sensitive)
+{
+    GtkAction *dualPages =
+        gtk_ui_manager_get_action (m_UIManager, "/MenuBar/ViewMenu/DualPages");
+    gtk_action_set_sensitive (dualPages, sensitive);
+}
+
+void
 MainView::show (void)
 {
     Config &config = Config::getConfig ();
@@ -1183,6 +1204,18 @@
 }
 
 ///
+/// @brief The user tried to switch to dual pages mode.
+///
+void
+main_window_dualpages_cb (GtkToggleAction *action, gpointer data)
+{
+    g_assert ( NULL != data && "The data parameter is NULL.");
+
+    MainPter *pter = (MainPter *)data;
+    pter->dualPagesActivated (gtk_toggle_action_get_active (action));
+}
+
+///
 /// @brief Called when the window is moved or resized.
 ///
 /// This is used to save the current window's position and size.
diff -ur a/src/gtk/MainView.h b/src/gtk/MainView.h
--- a/src/gtk/MainView.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/gtk/MainView.h	2009-10-30 01:19:38.000000000 +0300
@@ -35,6 +35,7 @@
 
             void activeZoomFit (gboolean active);
             void activeZoomWidth (gboolean active);
+            void activeDualPages (gboolean active);
             void activePageModeScroll (gboolean active);
             void activePageModeText (gboolean active);
             gboolean isIndexVisible () const;
@@ -61,6 +62,7 @@
             void sensitiveZoomOut (gboolean sensitive);
             void sensitiveZoomFit (gboolean sensitive);
             void sensitiveZoomWidth (gboolean sensitive);
+            void sensitiveDualPages (gboolean sensitive);
             void show (void);
             void showErrorMessage (const gchar *title, const gchar *body);
             void showIndex (gboolean show);
diff -ur a/src/gtk/PageView.cxx b/src/gtk/PageView.cxx
--- a/src/gtk/PageView.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/gtk/PageView.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -54,10 +54,15 @@
                                     GTK_POLICY_AUTOMATIC,
                                     GTK_POLICY_AUTOMATIC);
 
-    // The actual page image.
-    m_PageImage = gtk_image_new ();
-    gtk_misc_set_padding (GTK_MISC (m_PageImage), 
-                          PAGE_VIEW_PADDING, PAGE_VIEW_PADDING);
+    guint pagesCount = Config::getPagesCount ();
+    // The actual page images.
+    m_PageImage = new GtkWidget *[pagesCount];
+    for ( guint pageNum = 0; pageNum < pagesCount ; ++pageNum )
+    {
+        m_PageImage[pageNum] = gtk_image_new ();
+        gtk_misc_set_padding (GTK_MISC (m_PageImage[pageNum]), 
+                              PAGE_VIEW_PADDING, PAGE_VIEW_PADDING);
+    }
 
     // I want to be able to drag the page with the left mouse
     // button, because that will make possible to move the page
@@ -66,7 +71,12 @@
     // GdkWindow, so I have to add the event box that will receive
     // the mouse events.
     m_EventBox = gtk_event_box_new ();
-    gtk_container_add (GTK_CONTAINER (m_EventBox), m_PageImage);
+    m_ImageBox = gtk_hbox_new (TRUE, 0);
+    for ( guint pageNum = 0; pageNum < pagesCount ; ++pageNum )
+    {
+        gtk_container_add (GTK_CONTAINER (m_ImageBox), m_PageImage[pageNum]);
+    }
+    gtk_container_add (GTK_CONTAINER (m_EventBox), m_ImageBox);
     gtk_scrolled_window_add_with_viewport (
             GTK_SCROLLED_WINDOW (m_PageScroll), m_EventBox);
 
@@ -75,6 +85,7 @@
 
 PageView::~PageView ()
 {
+    delete[] m_PageImage;
 }
 
 gdouble
@@ -163,7 +174,7 @@
 void
 PageView::resizePage (gint width, gint height)
 {
-    GdkPixbuf *originalPage = gtk_image_get_pixbuf (GTK_IMAGE (m_PageImage));
+    GdkPixbuf *originalPage = gtk_image_get_pixbuf (GTK_IMAGE (m_PageImage[0]));
     if ( NULL != originalPage )
     {
         GdkPixbuf *scaledPage = gdk_pixbuf_scale_simple (originalPage,
@@ -171,7 +182,7 @@
                                                          GDK_INTERP_NEAREST);
         if ( NULL != scaledPage )
         {
-            gtk_image_set_from_pixbuf (GTK_IMAGE (m_PageImage), scaledPage);
+            gtk_image_set_from_pixbuf (GTK_IMAGE (m_PageImage[0]), scaledPage);
             g_object_unref (scaledPage);
         }
     }
@@ -245,7 +256,7 @@
     GtkAdjustment *hAdjustment = gtk_scrolled_window_get_hadjustment (
             GTK_SCROLLED_WINDOW (m_PageScroll));
     gdouble hAdjValue = hAdjustment->page_size *
-        (gdouble)dx / m_PageImage->allocation.width;
+        (gdouble)dx / m_PageImage[0]->allocation.width;
     gtk_adjustment_set_value (hAdjustment,
             CLAMP (scrollX - hAdjValue,
                    hAdjustment->lower,
@@ -254,7 +265,7 @@
     GtkAdjustment *vAdjustment = gtk_scrolled_window_get_vadjustment (
             GTK_SCROLLED_WINDOW (m_PageScroll));
     gdouble vAdjValue = vAdjustment->page_size *
-        (gdouble)dy / m_PageImage->allocation.height;
+        (gdouble)dy / m_PageImage[0]->allocation.height;
     gtk_adjustment_set_value (vAdjustment,
             CLAMP (scrollY - vAdjValue,
                    vAdjustment->lower,
@@ -279,12 +290,14 @@
 }
 
 void 
-PageView::showPage (DocumentPage *page, PageScroll scroll)
+PageView::showPage (DocumentPage *page, PageScroll scroll, guint index)
 {
-    gtk_image_set_from_pixbuf (GTK_IMAGE (m_PageImage), NULL);
+    GtkWidget *image = m_PageImage[index];
+    gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
     GdkPixbuf *pixbuf = getPixbufFromPage (page);
-    gtk_image_set_from_pixbuf (GTK_IMAGE (m_PageImage), pixbuf);
+    gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
     g_object_unref (pixbuf);
+
     // Set the vertical scroll to the specified.
     if ( PAGE_SCROLL_NONE != scroll )
     {
@@ -302,7 +315,20 @@
 }
 
 void
-PageView::showText (const gchar *text)
+PageView::showSecondPage (gboolean show)
+{
+    if ( show )
+    {
+        gtk_widget_show (m_PageImage[1]);
+    }
+    else
+    {
+        gtk_widget_hide (m_PageImage[1]);
+    }
+}
+
+void
+PageView::showText (const gchar *text, guint index)
 {
     // I need to make the changes to the original Pixbuf that the GtkImage
     // controls shows.
@@ -312,14 +338,16 @@
     // server-side and therefore drawable, make the modifications
     // and set the modified pixbuf again to the GtkImage control.
     // 
-    GdkPixbuf *originalPage = gtk_image_get_pixbuf (GTK_IMAGE (m_PageImage));
+    
+    GtkWidget* image = m_PageImage[index];
+    GdkPixbuf *originalPage = gtk_image_get_pixbuf (GTK_IMAGE (image));
     if ( NULL != originalPage )
     {
         gint width = gdk_pixbuf_get_width (originalPage);
         gint height = gdk_pixbuf_get_height (originalPage);
 
         PangoLayout *layout =
-            gtk_widget_create_pango_layout (m_PageImage, text);
+            gtk_widget_create_pango_layout (image, text);
 
         // I want the text to be half the page's width.
         // Since I don't know the font's size I just set the font
@@ -349,7 +377,7 @@
         gdk_pixbuf_render_pixmap_and_mask (originalPage,
                                            &pixmap, &mask, 0);
         gdk_draw_layout (pixmap, 
-                         m_PageImage->style->black_gc, 
+                         image->style->black_gc, 
                          (width - logicalRectangle.width) / 2, 
                          height / 4 - logicalRectangle.height / 2,
                          layout);
@@ -369,7 +397,7 @@
             g_object_unref (mask);
         }
 
-        gtk_image_set_from_pixbuf (GTK_IMAGE (m_PageImage), modifiedPage);
+        gtk_image_set_from_pixbuf (GTK_IMAGE (image), modifiedPage);
         g_object_unref (modifiedPage);
     } 
 }
@@ -385,7 +413,7 @@
 }
 
 void
-PageView::getPagePosition (gint widgetX, gint widgetY, gint *pageX, gint *pageY)
+PageView::getPagePosition (gint widgetX, gint widgetY, gint *pageX, gint *pageY, guint index)
 {
     g_assert ( NULL != pageX && "Tried to save the page's X to NULL.");
     g_assert ( NULL != pageY && "Tried to save the page's Y to NULL.");
@@ -395,17 +423,18 @@
     // how many widget space is being used for padding.
     gint horizontalPadding = PAGE_VIEW_PADDING;
     gint verticalPadding = PAGE_VIEW_PADDING;
-    GdkPixbuf *page = gtk_image_get_pixbuf (GTK_IMAGE (m_PageImage));
+    GdkPixbuf *page = gtk_image_get_pixbuf (GTK_IMAGE (m_PageImage[index]));
     if ( NULL != page )
     {
         horizontalPadding =
-            (m_PageImage->allocation.width - gdk_pixbuf_get_width (page)) / 2;
+            (m_PageImage[index]->allocation.width - gdk_pixbuf_get_width (page)) / 2;
         verticalPadding =
-            (m_PageImage->allocation.height - gdk_pixbuf_get_height (page)) / 2;
+            (m_PageImage[index]->allocation.height - gdk_pixbuf_get_height (page)) / 2;
     }
-
-    *pageX = widgetX - horizontalPadding + (gint)getHorizontalScroll ();
-    *pageY = widgetY - verticalPadding + (gint)getVerticalScroll ();
+    *pageX = widgetX - horizontalPadding + (gint)getHorizontalScroll () -
+             m_PageImage[index]->allocation.x;
+    *pageY = widgetY - verticalPadding + (gint)getVerticalScroll () -
+             m_PageImage[index]->allocation.y;
 }
 
 ///
@@ -443,10 +472,7 @@
     gint event_x;
     gint event_y;
     gtk_widget_get_pointer (view->getTopWidget (), &event_x, &event_y);
-    gint x;
-    gint y;
-    view->getPagePosition (event_x, event_y, &x, &y);
-    view->getPresenter ()->mouseButtonPressed (event->button, x, y);
+    view->getPresenter ()->mouseButtonPressed (event->button, event_x, event_y);
 
     gtk_widget_grab_focus(view->getTopWidget());
     
@@ -481,10 +507,7 @@
     gint event_x;
     gint event_y;
     gtk_widget_get_pointer (view->getTopWidget (), &event_x, &event_y);
-    gint x;
-    gint y;
-    view->getPagePosition (event_x, event_y, &x, &y);
-    view->getPresenter ()->mouseMoved (x, y);
+    view->getPresenter ()->mouseMoved (event_x, event_y);
 
     return TRUE;
 }
diff -ur a/src/gtk/PageView.h b/src/gtk/PageView.h
--- a/src/gtk/PageView.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/gtk/PageView.h	2009-10-30 01:19:38.000000000 +0300
@@ -29,7 +29,7 @@
             gdouble getHorizontalScroll (void);
             GtkWidget *getTopWidget (void);
             void getPagePosition (gint widgetX, gint widgetY,
-                                  gint *pageX, gint *pageY);
+                                  gint *pageX, gint *pageY, guint index);
             void getSize (gint *width, gint *height);
             gdouble getVerticalScroll (void);
             void makeRectangleVisible (DocumentRectangle &rect, gdouble scale);
@@ -38,13 +38,15 @@
                              gint dx, gint dy);
             void setCursor (PageCursor cursorType);
             void setPresenter (PagePter *pter);
-            void showPage (DocumentPage *page, PageScroll scroll);
-            void showText (const gchar *text);
+            void showPage (DocumentPage *page, PageScroll scroll, guint index = 0);
+            void showText (const gchar *text, guint index);
+            void showSecondPage (gboolean show);
 
         protected:
             PageCursor m_CurrentCursor;
             GtkWidget *m_EventBox;
-            GtkWidget *m_PageImage;
+            GtkWidget *m_ImageBox;
+            GtkWidget **m_PageImage;
             GtkWidget *m_PageScroll;
 
             GdkPixbuf *getPixbufFromPage (DocumentPage *page);
diff -ur a/src/IDocument.cxx b/src/IDocument.cxx
--- a/src/IDocument.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/IDocument.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -31,7 +31,7 @@
 static const gdouble ZOOM_IN_MAX = 4.0;
 static const gdouble ZOOM_OUT_FACTOR = (1.0 / ZOOM_IN_FACTOR);
 static const gdouble ZOOM_OUT_MAX = 0.05409;
-static const guint CACHE_SIZE = 3;
+static const guint CACHE_SIZE = 3 * Config::getPagesCount ();
 
 /// This is the error domain that will be used to report Document's errors.
 GQuark IDocument::errorQuark = 0;
@@ -278,11 +278,14 @@
 {
     // Empty the cache to avoid displaying pages from previous file.
     clearCache ();
-    // Add the two first pages, if they exists, to the cache.
-    addPageToCache (1);
-    if ( 1 < getNumPages () )
+
+    // Add the first pages to the cache.
+    guint pageMax = getCountOfVisiblePages () * 2;
+    for ( guint pageNum = 1;
+          pageNum <= pageMax && pageNum <= (guint)getNumPages ();
+          ++pageNum)
     {
-        addPageToCache (2);
+        addPageToCache (pageNum);
     }
 
     for ( GList *item = g_list_first (m_Observers) ; NULL != item ;
@@ -954,16 +957,19 @@
 }
 
 ///
-/// @brief Gets the document's current page image.
+/// @brief Gets one of the document's current pages.
+///
+/// @param index The index of the desired page in the list of current pages.
+///              Should always be 0 for single page mode.
 ///
-/// @return The rendered image of the current page or NULL if the image
+/// @return The rendered image of the selected page or NULL if the image
 ///         is not yet available.
 ///
 
 DocumentPage *
-IDocument::getCurrentPage ()
+IDocument::getCurrentPage (guint index)
 {
-    PageCache *cachedPage = getCachedPage (m_CurrentPage);
+    PageCache *cachedPage = getCachedPage (m_CurrentPage + index);
     if ( NULL == cachedPage )
     {
         return NULL;
@@ -976,7 +982,7 @@
     if ( NULL != pageImage )
     {
         /// XXX: Only non rotated documents for now.
-        if ( m_FindPage == m_CurrentPage && NULL != m_FindRect &&
+        if ( m_FindPage == m_CurrentPage + (gint)index && NULL != m_FindRect &&
              0 == getRotation () )
         {
             pageImage->setSelection (*m_FindRect, getZoom ());
@@ -1088,7 +1094,7 @@
 void
 IDocument::goToNextPage ()
 {
-    goToPage (getCurrentPageNum() + 1);
+    goToPage (getCurrentPageNum() + getCountOfVisiblePages ());
 }
 
 ///
@@ -1104,18 +1110,49 @@
 void
 IDocument::goToPage (gint pageNum)
 {
-    if ( pageNum != m_CurrentPage && 1 <= pageNum && pageNum <= getNumPages ())
+    guint pagesCount = getCountOfVisiblePages ();
+    if ( pageNum <= getNumPages () &&
+         pageNum + pagesCount > 1 )
     {
-        m_CurrentPage = pageNum;
+        // Check boundaries first
+        if ( pageNum < 1 )
+        {
+            m_CurrentPage = 1;
+        }
+        else if ( pageNum + pagesCount - 1 > (guint)getNumPages () )
+        {
+            m_CurrentPage = getNumPages () - pagesCount + 1;
+        }
+        else if ( m_CurrentPage == pageNum )
+        {
+            return;
+        }
+        else {
+            m_CurrentPage = pageNum;
+        }
+
+        // Process the currently visible pages.
+        for ( gint num = m_CurrentPage ;
+              num < m_CurrentPage + (gint)pagesCount && num <= getNumPages ();
+              ++num )
+        {
+            addPageToCache (num);
+        }
 
-        addPageToCache (m_CurrentPage);
-        if ( 1 < m_CurrentPage )
+        // Process a bunch of previous pages.
+        for ( gint num = m_CurrentPage - 1;
+              num >= m_CurrentPage - (gint)pagesCount && num > 0;
+              --num )
         {
-            addPageToCache (m_CurrentPage - 1);
+            addPageToCache (num);
         }
-        if ( m_CurrentPage < getNumPages () )
+
+        // Process a bunch of next pages.
+        for ( gint num = m_CurrentPage + pagesCount;
+              num < m_CurrentPage + (gint)pagesCount * 2 && num <= getNumPages ();
+              ++num )
         {
-            addPageToCache (m_CurrentPage + 1);
+            addPageToCache (num);
         }
 
         notifyPageChanged ();
@@ -1131,7 +1168,7 @@
 void
 IDocument::goToPreviousPage ()
 {
-    goToPage (getCurrentPageNum () - 1);
+    goToPage (getCurrentPageNum() - getCountOfVisiblePages ());
 }
 
 ///
@@ -1479,24 +1516,25 @@
 }
 
 ///
-/// @brief Checks if the current page has a link on a given position.
+/// @brief Checks if one of the current pages has a link on a given position.
 ///
-/// Checks if under a given position the document's current page have a 
-/// link.
+/// Checks if under a given position one of the document's current pages have
+/// a link.
 ///
 /// @param x The X coordinate of the position to check.
 /// @param y The Y coordinate of the position to check.
+/// @param index The index of the page to look for a link on.
 ///
 /// @return TRUE if the document's current page has a link under the given
 ///         position. FALSE otherwise.
 ///
 gboolean
-IDocument::hasLinkAtPosition (gint x, gint y)
+IDocument::hasLinkAtPosition (gint x, gint y, guint index)
 {
     // XXX For now only non rotated pages.
     if ( 0 == getRotation () )
     {
-        DocumentPage *page = getCurrentPage ();
+        DocumentPage *page = getCurrentPage (index);
         if ( NULL != page )
         {
             return (NULL != page->getLinkAtPosition (x, y));
@@ -1513,11 +1551,12 @@
 ///
 /// @param x The X coordinate of the current page's link to activate.
 /// @param y The Y coordinate of the current page's link to activate.
+/// @param index The index of the page containing the link.
 ///
 void
-IDocument::activateLinkAtPosition (gint x, gint y)
+IDocument::activateLinkAtPosition (gint x, gint y, guint index)
 {
-    DocumentPage *page = getCurrentPage ();
+    DocumentPage *page = getCurrentPage (index);
     // XXX For now only non rotated pages.
     if ( NULL != page && 0 == getRotation () )
     {
@@ -1528,3 +1567,29 @@
         }
     }
 }
+
+///
+/// @brief Gets visibility of a particular page.
+///
+/// @return TRUE if the selected page is currently on the screen.
+///         FALSE otherwise.
+///
+gboolean
+IDocument::isPageVisible (guint pageNum)
+{ 
+    return ( pageNum >= (guint)m_CurrentPage ) &&
+           ( pageNum < (guint)m_CurrentPage + getCountOfVisiblePages () );
+}
+
+///
+/// @brief Gets count of pages being currently displayed to user.
+///
+/// @return The result depends on current view mode. The value is always 1 for
+///         single-page mode and 2 for dual-pages mode.
+///
+guint
+IDocument::getCountOfVisiblePages ()
+{ 
+    Config &config = Config::getConfig ();
+    return ( config.dualPages () ) ? Config::getPagesCount () : 1;
+}
diff -ur a/src/IDocument.h b/src/IDocument.h
--- a/src/IDocument.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/IDocument.h	2009-10-30 01:19:38.000000000 +0300
@@ -265,8 +265,11 @@
             virtual gboolean saveFile (const gchar *filename,
                                        GError **error) = 0;
 
-            virtual GdkRegion* getTextRegion (DocumentRectangle *rect) = 0;
-            virtual void setTextSelection (DocumentRectangle *rect) = 0;
+            virtual GdkRegion* getTextRegion (DocumentRectangle *rect,
+                                              guint index ) = 0;
+            virtual gchar *getTextSelection (DocumentRectangle *rect,
+                                             guint index) = 0;
+            virtual void setTextSelection (gchar *text) = 0;
 
             void attach (const IDocumentObserver *observer);
             void detach (const IDocumentObserver *observer);
@@ -318,7 +321,8 @@
             void getPageSize (gdouble *width, gdouble *height);
             gint getNumPages (void);
             void setNumPages (gint numPages);
-            DocumentPage *getCurrentPage (void);
+            DocumentPage *getCurrentPage (guint index);
+            DocumentPage *getPairedPage (void);
             DocumentPage *getEmptyPage (void);
             gint getCurrentPageNum (void);
             DocumentOutline *getOutline (void);
@@ -349,8 +353,11 @@
             void zoomToFit (gint width, gint height);
             void zoomToWidth (gint width);
 
-            gboolean hasLinkAtPosition (gint x, gint y);
-            void activateLinkAtPosition (gint x, gint y);
+            gboolean hasLinkAtPosition (gint x, gint y, guint index);
+            void activateLinkAtPosition (gint x, gint y, guint index);
+
+            gboolean isPageVisible (guint pageNum);
+            guint getCountOfVisiblePages (void);
 
             static GQuark getErrorQuark (void);
             static gchar *getErrorMessage (DocumentError errorCode);
diff -ur a/src/IMainView.h b/src/IMainView.h
--- a/src/IMainView.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/IMainView.h	2009-10-30 01:19:38.000000000 +0300
@@ -78,6 +78,17 @@
             virtual void activeZoomWidth (gboolean active) = 0;
 
             ///
+            /// @brief Actives or deactivates the dual pages option.
+            ///
+            /// The view must change the state of the dual pages option
+            /// to @a active.
+            ///
+            /// @param active TRUE if the option must be activated, FALSE
+            ///               otherwise.
+            ///
+            virtual void activeDualPages (gboolean active) = 0;
+
+            ///
             /// @brief Tells if the index is shown.
             ///
             /// @return @c TRUE if the index is currently shown, @c FALSE
@@ -355,6 +366,17 @@
             ///
             virtual void sensitiveZoomWidth (gboolean sensitive) = 0;
 
+            /// @brief Changes the sensitivity of the "Dual Pages" action.
+            ///
+            /// The view must change the sensitivity (it's called enabled or
+            /// disabled on some toolkits) of the "Dual Pages" action.
+            ///
+            /// @param sensitive Set to TRUE if need to make sensitive (enable)
+            ///                  the action (enable) or FALSE to 
+            ///                  insensitive (disable) it.
+            ///
+            virtual void sensitiveDualPages (gboolean sensitive) = 0;
+
             ///
             /// @brief Sets the page view's cursor.
             ///
diff -ur a/src/IPageView.h b/src/IPageView.h
--- a/src/IPageView.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/IPageView.h	2009-10-30 01:19:38.000000000 +0300
@@ -168,7 +168,7 @@
             ///
             /// @brief Shows a document's page.
             ///
-            /// The view must show the @a page the the presenter gives to it.
+            /// The view must show the @a page the presenter gives to it.
             /// Of course the view can use scroll bars if the page doesn't fit
             /// the current view's size, but MUST NOT change the page's size.
             ///
@@ -178,23 +178,60 @@
             /// @param page The document's page to show.
             /// @param scroll Tells the main view how to scroll the
             ///               new page.
+            /// @param index The index on the page to be displayed in the list
+            ///              of current pages. This is only used in dual pages
+            ///              and is 0 by default (for single page mode).
             ///
-            virtual void showPage (DocumentPage *page, PageScroll scroll) = 0;
+            virtual void showPage (DocumentPage *page, PageScroll scroll,
+                                   guint index = 0) = 0;
 
             ///
             /// @brief Shows text on the page.
             ///
             /// This is only used when the page is still loading but the
             /// presenter wants to show something on the user. The presenter
-            /// passes a text string to show during the rendering of the
-            /// current page. The view should put this string at the middle
-            /// of the currently shown page.
+            /// passes a text string to show during the rendering of a page.
+            /// The view should put this string at the middle of one of the
+            /// currently shown pages.
             ///
             /// @param text The text to show on the middle of the page.
+            /// @param index The index of the page to show the text on. Should
+            ///              always be 0 for single page mode.
             ///
-            virtual void showText (const gchar *text) = 0;
-            
-            
+            virtual void showText (const gchar *text, guint index) = 0;
+
+            ///
+            /// @brief Shows the second page widget.
+            ///
+            /// The view must show the paired page or hide it depending
+            /// on the @a show parameter.
+            ///
+            /// The presenter calls this when user toggles the "Dual Pages"
+            /// option.
+            ///
+            /// @param show Set to TRUE if the second page should be shown.
+            ///             FALSE otherwise.
+            ///
+            virtual void showSecondPage (gboolean show) = 0;
+
+            ///
+            /// @brief Gets a dot coordinate relative to a page.
+            ///
+            /// The view must provide to the presenter the position of a dot
+            /// relative to one of the current pages.
+            ///
+            /// @param widgetX The X coordinate relative to a widget.
+            /// @param widgetY The Y coordinate relative to a widget.
+            /// @param pageX The location to save the X coordinate relative to
+            ///              a page.
+            /// @param pageY The location to save the Y coordinate relative to
+            ///              a page.
+            /// @param index The index of the page in the list of current pages.
+            ///
+            virtual void getPagePosition (gint widgetX, gint widgetY,
+                                          gint *pageX, gint *pageY,
+                                          guint index) = 0;
+
         protected:
             ///
             /// @brief Creates a new IPageView object.
diff -ur a/src/MainPter.cxx b/src/MainPter.cxx
--- a/src/MainPter.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/MainPter.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -136,12 +136,15 @@
         view.sensitiveZoomOut (TRUE);
         view.sensitiveZoomFit (TRUE);
         view.sensitiveZoomWidth (TRUE);
+        view.sensitiveDualPages (TRUE);
         view.activeZoomFit (config.zoomToFit ());
         view.activeZoomWidth (config.zoomToWidth ());
+        view.activeDualPages (config.dualPages ());
 #if defined (HAVE_CUPS)
         view.sensitivePrint (TRUE);
 #endif // HAVE_CUPS
 
+        dualPagesActivated (config.dualPages ());
         checkZoomSettings ();
 
         // Check if we should see the outlines.
@@ -170,6 +173,7 @@
         view.sensitiveZoomOut (FALSE);
         view.sensitiveZoomFit (FALSE);
         view.sensitiveZoomWidth (FALSE);
+        view.sensitiveDualPages (FALSE);
         showSidebar = FALSE;
 #if defined (HAVE_CUPS)
         view.sensitivePrint (FALSE);
@@ -332,7 +336,7 @@
 ///
 /// @brief The "Full Screen" action was activated.
 ///
-/// @param show TRUE if Full Screen is active, FALSE otherwise.
+/// @param active TRUE if Full Screen is active, FALSE otherwise.
 ///
 void
 MainPter::fullScreenActivated (gboolean active)
@@ -341,6 +345,24 @@
 }
 
 ///
+/// @brief The "Dual Pages" action was activated.
+///
+/// @param active TRUE if Dual Pages is active, FALSE otherwise.
+///
+void
+MainPter::dualPagesActivated (gboolean active)
+{
+    Config &config = Config::getConfig ();
+    config.setDualPages (active);
+    if (active)
+    {
+        // Need to recheck boundaries
+        m_Document->goToPage (m_Document->getCurrentPageNum ());
+    }
+    m_PagePter->setDualPages (active);
+}
+
+///
 /// @brief The "Go To First Page" action was activated.
 ///
 void
diff -ur a/src/MainPter.h b/src/MainPter.h
--- a/src/MainPter.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/MainPter.h	2009-10-30 01:19:38.000000000 +0300
@@ -50,6 +50,7 @@
             void aboutBoxLinkActivated (const gchar *link);
             void findActivated (void);
             void fullScreenActivated (gboolean active);
+            void dualPagesActivated (gboolean active);
             void goToFirstPageActivated (void);
             void goToLastPageActivated (void);
             void goToNextPageActivated (void);
diff -ur a/src/PagePter.cxx b/src/PagePter.cxx
--- a/src/PagePter.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/PagePter.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -31,6 +31,8 @@
     PagePter *pter;
     /// The scroll to be used when the page is available.
     PageScroll scroll;
+    /// Location of the page to be updated (left, right or both).
+    PageLocation location;
 }
 PageNotAvailableData;
 
@@ -54,14 +56,19 @@
 };
 
 // Global variables.
-static gboolean g_WaitingForPage = FALSE;
+static const guint g_pagesCount = Config::getPagesCount ();
+static gboolean* g_WaitingForPage = new gboolean[g_pagesCount];
 
 ///
 /// @brief Constructs a new PagePter object.
 ///
 PagePter::PagePter (IDocument *document)
 {
-    m_LastSelection = NULL;
+    m_LastSelection = new GdkRegion *[g_pagesCount];
+    for ( guint pageNum = 0; pageNum < g_pagesCount ; ++pageNum )
+    {
+        m_LastSelection[pageNum] = NULL;
+    }
     m_Document = document;
     m_Document->attach (this);
     m_DragInfo = NULL;
@@ -76,6 +83,7 @@
 PagePter::~PagePter ()
 {
     delete m_DragInfo;
+    delete[] m_LastSelection;
     m_Document->detach (this);
 }
 
@@ -121,24 +129,33 @@
 {
     if ( 1 == button )
     {
-        if ( m_Document->hasLinkAtPosition (x, y) )
+        IPageView &view = getView ();
+
+        // Check for a link first
+        gint maxNum = m_Document->getCountOfVisiblePages ();;
+        for ( gint pageNum = 0; pageNum < maxNum ; ++pageNum )
         {
-            m_Document->activateLinkAtPosition (x, y);
+            gint pageX = 0;
+            gint pageY = 0;
+            view.getPagePosition (x, y, &pageX, &pageY, pageNum);
+            if ( m_Document->hasLinkAtPosition (pageX, pageY, pageNum) )
+            {
+                m_Document->activateLinkAtPosition (pageX, pageY, pageNum);
+                return;
+            }
         }
-        else
-        {
-            m_DragInfo = new DragInfo;
-            m_DragInfo->x = x;
-            m_DragInfo->y = y;
 
-            IPageView &view = getView ();
-            m_DragInfo->startX = x;
-            m_DragInfo->startY = y;
-            if(m_ScrollMode == PagePterModeScroll)
-                view.setCursor (PAGE_VIEW_CURSOR_DRAG);
-            else
-                view.setCursor (PAGE_VIEW_CURSOR_SELECT_TEXT);
-        }
+        // Link is not found
+        m_DragInfo = new DragInfo;
+        m_DragInfo->x = x;
+        m_DragInfo->y = y;
+
+        m_DragInfo->startX = x;
+        m_DragInfo->startY = y;
+        if(m_ScrollMode == PagePterModeScroll)
+            view.setCursor (PAGE_VIEW_CURSOR_DRAG);
+        else
+            view.setCursor (PAGE_VIEW_CURSOR_SELECT_TEXT);
     }
 }
 
@@ -155,17 +172,46 @@
 {
     if ( 1 == button )
     {
-        if(m_LastSelection)
-            gdk_region_destroy(m_LastSelection);
-        m_LastSelection = NULL;
+        for ( guint pageNum = 0; pageNum < g_pagesCount ; ++pageNum )
+        {
+            if (m_LastSelection[pageNum])
+                gdk_region_destroy(m_LastSelection[pageNum]);
+            m_LastSelection[pageNum] = NULL;
+        }
 
         if ( m_Document->isLoaded() &&
              m_ScrollMode == PagePterModeSelectText &&
              NULL != m_DragInfo )
         {
-            DocumentRectangle rect(m_DragInfo->startX, m_DragInfo->startY,
-                                   m_DragInfo->x, m_DragInfo->y);
-            m_Document->setTextSelection(&rect);
+
+            gint maxNum = m_Document->getCountOfVisiblePages ();
+            gchar **selections = new gchar *[maxNum];
+            IPageView &view = getView ();
+            for ( gint pageNum = 0; pageNum < maxNum ; ++pageNum )
+            {
+                gint pageStartX = 0;
+                gint pageStartY = 0;
+                view.getPagePosition (m_DragInfo->startX, m_DragInfo->startY,
+                                      &pageStartX, &pageStartY, pageNum);
+                gint pageX = 0;
+                gint pageY = 0;
+                view.getPagePosition (m_DragInfo->x, m_DragInfo->y,
+                                      &pageX, &pageY, pageNum);
+
+                DocumentRectangle rect(pageStartX, pageStartY, pageX, pageY);
+                selections[pageNum] = m_Document->getTextSelection(&rect,
+                                        pageNum);
+            }
+            GString *selection = g_string_new (NULL);
+            for ( gint pageNum = 0; pageNum < maxNum ; ++pageNum )
+            {
+                if ( selections[pageNum] )
+                {
+                    g_string_append (selection, selections[pageNum]);
+                    g_free (selections[pageNum]);
+                }
+            }
+            m_Document->setTextSelection (g_string_free(selection, FALSE));
         }
 
         delete m_DragInfo;
@@ -192,9 +238,23 @@
 PagePter::mouseMoved (gint x, gint y)
 {
     IPageView &view = getView ();
+    gint maxNum = m_Document->getCountOfVisiblePages ();
+
     if ( NULL == m_DragInfo )
     {
-        if ( m_Document->hasLinkAtPosition (x, y) )
+        gboolean isFound = FALSE;
+        for ( gint pageNum = 0; pageNum < maxNum ; ++pageNum )
+        {
+            gint pageX = 0;
+            gint pageY = 0;
+            view.getPagePosition (x, y, &pageX, &pageY, pageNum);
+            if ( m_Document->hasLinkAtPosition (pageX, pageY, pageNum) )
+            {
+                isFound = TRUE;
+            }
+        }
+
+        if ( isFound )
         {
             view.setCursor (PAGE_VIEW_CURSOR_LINK);
         }
@@ -207,26 +267,39 @@
         m_DragInfo->x = x;
         m_DragInfo->y = y;  
 
-        if(m_ScrollMode == PagePterModeScroll){
-            view.scrollPage (view.getHorizontalScroll (), view.getVerticalScroll (),
+        if (m_ScrollMode == PagePterModeScroll){
+            view.scrollPage (view.getHorizontalScroll (),
+                             view.getVerticalScroll (),
                              x - m_DragInfo->startX, y - m_DragInfo->startY);
         }
         else{
-            if(!m_Document->isLoaded())
+            if (!m_Document->isLoaded())
                 return ;
-            
-            DocumentRectangle rect(m_DragInfo->startX, m_DragInfo->startY,
-                                          m_DragInfo->x, m_DragInfo->y);
-
-            GdkRegion *region = m_Document->getTextRegion (&rect);
-
-            if( !m_LastSelection || !gdk_region_equal(m_LastSelection, region)){
-                if(m_LastSelection)
-                    gdk_region_destroy(m_LastSelection);
-                m_LastSelection = gdk_region_copy(region);
-                DocumentPage *page = m_Document->getCurrentPage();
-                if ( NULL != page )
-                    refreshPage (PAGE_SCROLL_NONE, FALSE);
+
+            for ( gint pageNum = 0; pageNum < maxNum ; ++pageNum )
+            {
+                gint pageStartX = 0;
+                gint pageStartY = 0;
+                view.getPagePosition (m_DragInfo->startX, m_DragInfo->startY,
+                                      &pageStartX, &pageStartY, pageNum);
+                gint pageX = 0;
+                gint pageY = 0;
+                view.getPagePosition (m_DragInfo->x, m_DragInfo->y,
+                                      &pageX, &pageY, pageNum);
+
+                DocumentRectangle rect(pageStartX, pageStartY, pageX, pageY);
+                GdkRegion *region = m_Document->getTextRegion (&rect, pageNum);
+
+                if ( !m_LastSelection[pageNum] ||
+                     !gdk_region_equal(m_LastSelection[pageNum], region))
+                {
+                    if(m_LastSelection[pageNum])
+                        gdk_region_destroy(m_LastSelection[pageNum]);
+                    m_LastSelection[pageNum] = gdk_region_copy(region);
+                    DocumentPage *page = m_Document->getCurrentPage (pageNum);
+                    if ( NULL != page )
+                        refreshPage (PAGE_SCROLL_NONE, FALSE);
+                }
             }
         }
     }
@@ -245,35 +318,50 @@
 void
 PagePter::notifyLoad ()
 {
-    g_WaitingForPage = FALSE;
+    for ( guint pageNum = 0 ; pageNum < g_pagesCount ; ++pageNum )
+    {
+        g_WaitingForPage[pageNum] = FALSE;
+    }
     refreshPage (PAGE_SCROLL_START, FALSE);
 }
 
 void
 PagePter::notifyPageChanged (gint pageNum)
 {
-    g_WaitingForPage = FALSE;
+    for ( guint pageNum = 0 ; pageNum < g_pagesCount ; ++pageNum )
+    {
+        g_WaitingForPage[pageNum] = FALSE;
+    }
     refreshPage (m_NextPageScroll, FALSE);
 }
 
 void
 PagePter::notifyPageRotated (gint rotation)
 {
-    g_WaitingForPage = FALSE;
+    for ( guint pageNum = 0 ; pageNum < g_pagesCount ; ++pageNum )
+    {
+        g_WaitingForPage[pageNum] = FALSE;
+    }
     refreshPage (PAGE_SCROLL_START, FALSE);
 }
 
 void
 PagePter::notifyPageZoomed (gdouble zoom)
 {
-    g_WaitingForPage = FALSE;
+    for ( guint pageNum = 0 ; pageNum < g_pagesCount ; ++pageNum )
+    {
+        g_WaitingForPage[pageNum] = FALSE;
+    }
     refreshPage (PAGE_SCROLL_NONE, TRUE);
 }
 
 void
 PagePter::notifyReload ()
 {
-    g_WaitingForPage = FALSE;
+    for ( guint pageNum = 0 ; pageNum < g_pagesCount ; ++pageNum )
+    {
+        g_WaitingForPage[pageNum] = FALSE;
+    }
     refreshPage (PAGE_SCROLL_NONE, FALSE);
 }
 
@@ -283,9 +371,14 @@
     g_assert (NULL != user && "The data parameter in NULL.");
 
     PageNotAvailableData *data = (PageNotAvailableData *)user;
-    if ( g_WaitingForPage )
+    gboolean isWaiting = FALSE;
+    for ( guint num = 0 ; num < g_pagesCount ; ++num )
+    {
+        isWaiting |= g_WaitingForPage[num];
+    }
+    if ( isWaiting )
     {
-        data->pter->refreshPage (data->scroll, FALSE);
+        data->pter->refreshPage (data->scroll, FALSE, data->location);
         return TRUE;
     }
     delete data;
@@ -303,46 +396,63 @@
 ///                   to show the scroll this new page.
 /// @param wasZoomed If this is set to TRUE then it means that the page
 ///                  has been refreshed because its scaled has changed.
+/// @param pageLocation This determines location (left, right or both) of the
+///                     page to be refreshed.
 ///
 void
-PagePter::refreshPage (PageScroll pageScroll, gboolean wasZoomed)
+PagePter::refreshPage (PageScroll pageScroll, gboolean wasZoomed,
+                       PageLocation pageLocation)
 {
     g_assert (NULL != m_Document && 
               "Tried to show a page from a NULL document.");
-    
     if ( m_Document->isLoaded () )
     {
         IPageView &view = getView ();
-        DocumentPage *documentPage = m_Document->getCurrentPage ();
-        if ( NULL != documentPage )
+
+        Config &config = Config::getConfig ();
+        if ( !config.dualPages () )
         {
-            g_WaitingForPage = FALSE;
-            if ( NULL != m_LastSelection )
-                documentPage->setSelection(m_LastSelection);
-            view.showPage (documentPage, pageScroll);
+            pageLocation = PageLocationLeft;
         }
-        else
+
+        int pageMin = (pageLocation == PageLocationRight) ? 1 : 0;
+        int pageMax = (pageLocation == PageLocationLeft) ? 0 : 1;
+
+        for (int pageIndex = pageMin ; pageIndex <= pageMax ; ++pageIndex )
         {
-            if ( !g_WaitingForPage )
+            DocumentPage *documentPage = m_Document->getCurrentPage (pageIndex);
+            if ( NULL != documentPage )
             {
-                documentPage = m_Document->getEmptyPage ();
-                if ( wasZoomed )
-                {
-                    view.resizePage (documentPage->getWidth (),
-                                     documentPage->getHeight ());
-                }
-                else
+                g_WaitingForPage[pageIndex] = FALSE;
+                if ( NULL != m_LastSelection[pageIndex] )
+                    documentPage->setSelection(m_LastSelection[pageIndex]);
+                view.showPage (documentPage, pageScroll, pageIndex);
+            }
+            else
+            {
+                if ( !g_WaitingForPage[pageIndex] )
                 {
-                    view.showPage (documentPage, pageScroll);
-                    delete documentPage;
-                    view.showText (_("Loading..."));
+                    documentPage = m_Document->getEmptyPage ();
+                    if ( wasZoomed )
+                    {
+                        view.resizePage (documentPage->getWidth (),
+                                         documentPage->getHeight ());
+                    }
+                    else
+                    {
+                        view.showPage (documentPage, pageScroll, pageIndex);
+                        delete documentPage;
+                        view.showText (_("Loading..."), pageIndex);
+                    }
+
+                    g_WaitingForPage[pageIndex] = TRUE;
+                    PageNotAvailableData *data = new PageNotAvailableData;
+                    data->pter = this;
+                    data->scroll = pageScroll;
+                    data->location = (pageIndex == 0) ?
+                                     PageLocationLeft : PageLocationRight;
+                    g_idle_add (PagePter::pageNotAvailable, data);
                 }
-
-                g_WaitingForPage = TRUE;
-                PageNotAvailableData *data = new PageNotAvailableData;
-                data->pter = this;
-                data->scroll = pageScroll;
-                g_idle_add (PagePter::pageNotAvailable, data);
             }
         }
     }
@@ -452,3 +562,16 @@
         m_Document->zoomToWidth (width);
     }
 }
+
+///
+/// @brief Sets the view mode: single/dual page.
+///
+/// @param active TRUE if Dual Pages mode should be activated,
+///               FALSE otherwise.
+///
+void
+PagePter::setDualPages (gboolean activate)
+{
+    m_PageView->showSecondPage (activate);
+    refreshPage (PAGE_SCROLL_NONE, FALSE);
+}
diff -ur a/src/PagePter.h b/src/PagePter.h
--- a/src/PagePter.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/PagePter.h	2009-10-30 01:19:38.000000000 +0300
@@ -28,6 +28,12 @@
         PagePterModeSelectText,
     };
 
+    enum PageLocation{
+        PageLocationLeft,
+        PageLocationRight,
+        PageLocationBoth,
+    };
+
     ///
     /// @class PagePter.
     /// @brief The page presenter.
@@ -58,7 +64,8 @@
             void setNextPageScroll (PageScroll next);
             void setView (IMainView &view);
             void viewResized (gint width, gint height);
-            void setMode(PagePterMode mode);
+            void setMode (PagePterMode mode);
+            void setDualPages (gboolean activate);
 
         protected:
             /// The document whose page is shown.
@@ -69,12 +76,13 @@
             PageScroll m_NextPageScroll;
             /// The page view.
             IPageView *m_PageView;
-            /// Last text selection
-            GdkRegion *m_LastSelection;
+            /// Last text selections
+            GdkRegion **m_LastSelection;
             /// What page presenter must do when user move mouse with button pressed.
             PagePterMode m_ScrollMode;
 
-            void refreshPage (PageScroll pageScroll, gboolean wasZoomed);
+            void refreshPage (PageScroll pageScroll, gboolean wasZoomed,
+                              PageLocation pageLocation = PageLocationBoth);
     };
 }
 
diff -ur a/src/PDFDocument.cxx b/src/PDFDocument.cxx
--- a/src/PDFDocument.cxx	2009-10-29 23:45:04.000000000 +0300
+++ b/src/PDFDocument.cxx	2009-10-30 01:19:38.000000000 +0300
@@ -669,13 +669,31 @@
 }
 
 void
-PDFDocument::setTextSelection (DocumentRectangle *rect)
+PDFDocument::setTextSelection (gchar *text)
+{
+    g_assert(text);
+
+    for ( GList *obs = g_list_first (m_Observers) ;
+          NULL != obs ;
+          obs = g_list_next (obs) )
+        {
+            IDocumentObserver *observer = (IDocumentObserver*)obs->data;
+            observer->notifyTextSelected(text);
+        }
+
+    g_free(text);
+}
+
+
+gchar *
+PDFDocument::getTextSelection (DocumentRectangle *rect, guint index)
 {
     g_assert(rect);
 
-    PopplerPage *page = poppler_document_get_page (m_Document, getCurrentPageNum()-1);
+    PopplerPage *page = poppler_document_get_page (m_Document,
+                          getCurrentPageNum() + index - 1);
     if(!page)
-        return;
+        return NULL;
 
     gdouble pageWidth, pageHeight;
     poppler_page_get_size(page, &pageWidth, &pageHeight);
@@ -693,29 +711,19 @@
 #else // !HAVE_POPPLER_0_6_0
     gchar *text = poppler_page_get_text(page, &textRect);
 #endif // HAVE_POPPLER_0_6_0
-    if(!text)
-        goto cleanup;
-
-    for ( GList *obs = g_list_first (m_Observers) ;
-          NULL != obs ;
-          obs = g_list_next (obs) )
-        {
-            IDocumentObserver *observer = (IDocumentObserver*)obs->data;
-            observer->notifyTextSelected(text);
-        }
 
- cleanup:
     if(page)
         g_object_unref(page);
-    if(text)
-        g_free(text);
+
+    return text;
 }
 
 GdkRegion*
-PDFDocument::getTextRegion (DocumentRectangle *r)
+PDFDocument::getTextRegion (DocumentRectangle *r, guint index)
 {
     GdkRegion *res = NULL;
-    PopplerPage *page = poppler_document_get_page (m_Document, getCurrentPageNum()-1);
+    PopplerPage *page = poppler_document_get_page (m_Document,
+                          getCurrentPageNum() + index - 1);
     if(!page)
         return NULL;
 
diff -ur a/src/PDFDocument.h b/src/PDFDocument.h
--- a/src/PDFDocument.h	2009-10-29 23:45:04.000000000 +0300
+++ b/src/PDFDocument.h	2009-10-30 01:19:38.000000000 +0300
@@ -54,8 +54,9 @@
 
             DocumentPage *renderPage (gint pageNum);
             gboolean saveFile (const gchar *fileName, GError **error);
-            GdkRegion* getTextRegion (DocumentRectangle* rect);
-            void setTextSelection (DocumentRectangle *rect);
+            GdkRegion* getTextRegion (DocumentRectangle* rect, guint index);
+            void setTextSelection (gchar *text);
+            gchar *getTextSelection (DocumentRectangle *rect, guint index);
 
         protected:
             /// The PDF document.
