diff -EwBurNd ipdf/inc/channels.h column/ipdf/inc/channels.h
--- ipdf/inc/channels.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/channels.h	2007-10-22 17:00:36.000000000 +0200
@@ -49,7 +49,7 @@
     int         nZoominState;
     int         nZoomoutState;
     int         nRotateState;
-    int         nContinousState;
+    int         nViewState;
     int         nZoombackState;
     int         nBackwardState;
     int         nForwardState;
@@ -85,8 +85,8 @@
     int     getZoomOutState() const { return nZoomoutState; }
     void    setRotateState(const int state) { nRotateState = state; }
     int     getRotateState() const { return nRotateState; }
-    void    setContinousState(const int state) { nContinousState = state; }
-    int     getContinousState() const { return nContinousState; }
+    void    setViewState(const int state) { nViewState = state; }
+    int     getViewState() const { return nViewState; }
     void    setZoombackState(const int state) { nZoombackState = state; }
     int     getZoombackState() const { return nZoombackState; }
     int     getBackwardState() const { return nBackwardState; }
diff -EwBurNd ipdf/inc/GtkMgr.h column/ipdf/inc/GtkMgr.h
--- ipdf/inc/GtkMgr.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/GtkMgr.h	2007-10-19 14:34:55.000000000 +0200
@@ -5,7 +5,7 @@
 #include "splash/SplashBitmap.h"
 #include "splash/SplashTypes.h"
 #include <gtk/gtk.h> 
-
+#include "utils.h"
 
 class GtkMgr
 {
@@ -44,6 +44,8 @@
     void            setLineColor(const int color);
     void            setLineAttributes(const int width, const int style = LineSolid);
     void            drawLine(const int x1, const int y1, const int x2, const int y2);
+    void            drawRectangle(const int x, const int y, const int w, const int h);
+    void            drawRectangle(rectangle rect);
+
 };
 #endif
-
diff -EwBurNd ipdf/inc/LayoutMgr.h column/ipdf/inc/LayoutMgr.h
--- ipdf/inc/LayoutMgr.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/LayoutMgr.h	2007-10-22 09:49:45.000000000 +0200
@@ -63,6 +63,9 @@
     // portrait <-> landscape
     void    rotate(Controller * ctrl, const int angle);
 
+    // column mode
+    GBool getColumnCount(Controller *ctrl, int p, int &n);
+    GBool getColumnRect(Controller *ctrl, int p, int n, rectangle &crect);
 };
 
 #endif
diff -EwBurNd ipdf/inc/PDFCore.h column/ipdf/inc/PDFCore.h
--- ipdf/inc/PDFCore.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/PDFCore.h	2007-10-14 13:29:27.000000000 +0200
@@ -41,7 +41,7 @@
 {
 private:
     PDFDoc * pdfdoc;
-    SplashOutputDev * outputDev;
+    SplashOutputDev * splashOut;
     TextOutputDev * textOut;
     Controller * ctrl;
 
diff -EwBurNd ipdf/inc/PDFPortraitView.h column/ipdf/inc/PDFPortraitView.h
--- ipdf/inc/PDFPortraitView.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/PDFPortraitView.h	2007-10-22 15:23:15.000000000 +0200
@@ -72,6 +72,15 @@
     void zoomFitContinousMode();
     GBool doLinkContinousMode(const int x, const int y);
 
+    ////////////////////////// for column mode ///////////////////////////
+    void advanceColumn(int &start, int &end, const int pageNumber, const ContinousModeScroll scroll);
+    GBool doColumnTap(const int x, const int y);
+    void getNextColumn(int &startPage, int &colNum, rectangle &colRect);
+    void getPreviousColumn(int &startPage, int &colNum, rectangle &colRect);
+    void moveToBottomColumn(const rectangle column);
+    void moveToColumn(const rectangle column);
+    void moveToColumnPage(int &pn);
+
     ////////////////////////// page display /////////////////////////////////
     // displayPage -> displayPages -> drawPages -> drawPageImage
     void displayPages(const int start, const int end);
diff -EwBurNd ipdf/inc/PDFViewerLog.h column/ipdf/inc/PDFViewerLog.h
--- ipdf/inc/PDFViewerLog.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/PDFViewerLog.h	2007-10-22 21:17:22.000000000 +0200
@@ -20,16 +20,16 @@
 #define _PDFVIEWER_LOG_H_
 
 #define PV_LOGGING_ON       0 
-#define PV_WARNING_ON       1
+#define PV_WARNING_ON       0
 #define PV_ERROR_ON         1
-#define PV_DUMP_ON          1
+#define PV_DUMP_ON          0
 #define PV_MEM_ON           1
 #define PV_LIST_ON          1
-#define PV_PROFILE_ON       1
+#define PV_PROFILE_ON       0
 #define PV_SCB_ON           0
 #define PV_TOOLBAR_ON       0 
 
-#define SYSLOG_ON           1
+#define SYSLOG_ON           0
 #if (SYSLOG_ON)
 #include <syslog.h>
 #endif
diff -EwBurNd ipdf/inc/PDFView.h column/ipdf/inc/PDFView.h
--- ipdf/inc/PDFView.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/PDFView.h	2007-10-22 11:31:50.000000000 +0200
@@ -85,6 +85,8 @@
     void        issuePrevNextPages(const int offset, const int from = 0, const int time = 0);
     void        issueLinks(CPageInfo *page);
     void        issueLink(Link * p);
+    void        waitForPage(const int pn);
+    void        forceItem(const int pn);
     
 public:
     ////////////////////// toolbar states /////////////////////////////
@@ -97,8 +99,10 @@
     ///////////////////////// view & mode ////////////////////////////
     GBool       isPageMode(); 
     GBool       isContinousMode();
+    GBool       isColumnMode();
     void        setPageMode();
     void        setContinousMode();
+    void        setColumnMode();
     GBool       isPortraitView();
     GBool       isLandscapeView();
 
diff -EwBurNd ipdf/inc/Settings.h column/ipdf/inc/Settings.h
--- ipdf/inc/Settings.h	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/inc/Settings.h	2007-10-22 21:01:04.000000000 +0200
@@ -44,6 +44,7 @@
 #define SmallOffset     5
 #define RectThreshold   25
 #define ProtectWidth    5
+#define RenderWait      300      // max time to wait (s) for a forced page render
 
 #define PageBreak       1
 #define PageRepeat      20
@@ -70,6 +71,7 @@
 #define ModePage        2
 #define ModeNewspaper   4       // this two decide pre-render algorithm
 #define ModeA4          8       // for A4 pages
+#define ModeColumn     16
 
 // IPC buffer
 #define IPC_BUF_MAX     1024
@@ -140,6 +142,18 @@
                 currentItem;    // current page item.
     HistoryItem record;         // for zoomback
 
+    double      colXSpace;      // amount of space to deduct from the start of
+    double      colYSpace;      // a column when zooming in; as
+				// percentages of screensize
+
+    int         colMinLines;    // min number of lines before a textblock
+				// is considered to be a column
+
+    GBool       colHighlight;   // highlight the current column to
+				// aid algorithm understanding
+
+    int         colNr;          // current focused column
+
 private:
     void        clearHistory();
 
@@ -178,6 +192,14 @@
     void setScreenSize(const int, const int);
     void setScreenRect(const rectangle & rect);
     
+    // columns
+    int getColMinLines() { return colMinLines; }
+    GBool getColHighlight() { return colHighlight; }
+    void setColNr(const int n) { colNr = n; }
+    int getColNr() { return colNr; }
+    int getColXSpace() { return (int) (colXSpace * drawAreaWidth); }
+    int getColYSpace() { return (int) (colYSpace * drawAreaHeight); }
+
     // page
     int getCurrentPage() const { return currentPage; }
     void setCurrentPage(const int p);
diff -EwBurNd ipdf/src/channels.cpp column/ipdf/src/channels.cpp
--- ipdf/src/channels.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/channels.cpp	2007-10-22 17:00:46.000000000 +0200
@@ -90,9 +90,9 @@
     // draw
     tbEnableUpdate(ertoolbarChannel, ER_PDF_VIEWER_UA_ID); 
     
-    nPanState = nZoominState = nZoomoutState = iconState_normal;
+    nRotateState = nPanState = nZoominState = nZoomoutState = iconState_normal;
     nZoombackState = iconState_grey;
-    nContinousState = iconState_normal;
+    nViewState = iconID_page_mode;
     nRotateState = PortraitToLandscape;
     nBackwardState = nForwardState = iconState_grey;
 
@@ -407,17 +407,9 @@
             tbSetStatePlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_landscape_portrait, iconState_selected);
         }
 
-        // page/continous mode 
-        if (iconState_normal == nContinousState)
-        {
-            tbAppendPlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_page_mode, ccVwrToolbar);
+	// page/continous/column mode
+        tbAppendPlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, nViewState, ccVwrToolbar);
             tbSetStatePlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_page_mode, iconState_normal);
-        }
-        else if (3 == nContinousState)
-        {
-            tbAppendPlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_continuous_mode, ccVwrToolbar);
-            tbSetStatePlatformIcon(ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_continuous_mode, iconState_selected);
-        }            
 
         // zoom fit
         tbAppendPlatformIcon(  ertoolbarChannel, ER_PDF_VIEWER_UA_ID, iconID_zoomfit, ccVwrToolbar);
diff -EwBurNd ipdf/src/GtkMgr.cpp column/ipdf/src/GtkMgr.cpp
--- ipdf/src/GtkMgr.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/GtkMgr.cpp	2007-10-19 14:36:13.000000000 +0200
@@ -195,3 +194,12 @@
     XDrawLine(display, GDK_WINDOW_XWINDOW(window->window), GDK_GC_XGC(gc), x1, y1, x2, y2);
 }
 
+void GtkMgr::drawRectangle(const int x, const int y, const int w, const int h)
+{
+    XDrawRectangle(display, GDK_WINDOW_XWINDOW(window->window), GDK_GC_XGC(gc), x, y, w, h);
+}
+
+void GtkMgr::drawRectangle(rectangle rect)
+{
+    XDrawRectangle(display, GDK_WINDOW_XWINDOW(window->window), GDK_GC_XGC(gc), rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+}
diff -EwBurNd ipdf/src/LayoutMgr.cpp column/ipdf/src/LayoutMgr.cpp
--- ipdf/src/LayoutMgr.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/LayoutMgr.cpp	2007-10-22 21:02:38.000000000 +0200
@@ -237,3 +237,94 @@
     return bound.hitTest(x, y);
 }
 
+GBool CLayoutMgr::getColumnCount(Controller *ctrl, int p, int &n)
+{
+    CPageInfo *page = ctrl->pageList.getPage(p);
+    TextFlow *tf;
+    TextBlock *tb;
+
+    n = -1;
+
+    if (page == NULL)
+    {
+        PV_LOGPRINTF("getColumnCount: page %d has not been rendered", p);
+        return gFalse;
+    }
+
+    for (tf = page->text->getTextFlows(); tf; tf = tf->getNext())
+    {
+	for (tb = tf->getTextBlocks(); tb; tb = tb->getNext())
+	{
+	    if (tb->getLineCount() >= ctrl->settings.getColMinLines())
+	    {
+                n++;
+            }
+        }
+    }
+
+    return gTrue;
+}
+
+GBool CLayoutMgr::getColumnRect(Controller *ctrl, int p, int n, rectangle &crect)
+{
+    // Retrieve nth column rect
+    CPageInfo *page = ctrl->pageList.getPage(p);
+    const rectangle prect = posTab[p - 1];
+    TextFlow *tf;
+    TextBlock *tb;
+    double xMin, xMax, yMin, yMax;
+    int rotation, i = n;
+    int ax = prect.left - ctrl->settings.getScreenX();
+    int ay = prect.top - ctrl->settings.getScreenY();
+
+    if (page == NULL)
+    {
+        PV_LOGPRINTF("getColumnRect: page %d has not been rendered", p);
+        return gFalse;
+    }
+
+    for (tf = page->text->getTextFlows(); tf; tf = tf->getNext())
+    {
+	for (tb = tf->getTextBlocks(); tb; tb = tb->getNext())
+	{
+	    if (tb->getLineCount() > ctrl->settings.getColMinLines())
+	    {
+                PV_LOGPRINTF("getColumnRect: page %d, column %d = (textflow%08x/textbox%08x)",
+                             p, n - i, (int) tf, (int) tb);
+		if (i > 0)
+		{
+		    i--;
+		}
+		else
+		{
+		    // get coordinates
+		    tb->getBBox(&xMin, &yMin, &xMax, &yMax, &rotation);
+		    // check rotation
+		    if (page->pageRotate == rotation)
+		    {
+			// calculate crect in screen terms
+			crect.left = (int) xMin + ax;
+			crect.right = (int) xMax + ax;
+			crect.top = (int) yMin + ay;
+			crect.bottom = (int) yMax + ay;
+
+			PV_LOGPRINTF("getColumnRect: page %d, column %d = (textflow%08x/textbox%08x) = rect(%f, %f, %f, %f) = pagerect(%d, %d, %d, %d)",
+				     p, n, (int) tf, (int) tb,
+				     xMin, yMin, xMax, yMax,
+				     crect.left, crect.top, crect.right, crect.bottom);
+			return gTrue;
+		    }
+		    else
+		    {
+			PV_LOGPRINTF("getColumnRect: ignored page %d, column %d = (textflow%08x/textbox%08x) = rect(%f, %f, %f, %f); rotation %d != %d",
+				     p, n - i, (int) tf, (int) tb,
+				     xMin, yMin, xMax, yMax,
+				     rotation, page->pageRotate);
+		    }
+		}
+	    }
+	}
+    }
+
+    return gFalse;
+}
diff -EwBurNd ipdf/src/PDFCore.cpp column/ipdf/src/PDFCore.cpp
--- ipdf/src/PDFCore.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/PDFCore.cpp	2007-10-14 19:23:08.000000000 +0200
@@ -24,15 +24,16 @@
 CPDFCore::CPDFCore(SplashColorMode colorModeA, int bitmapRowPadA,
 	         GBool reverseVideoA, SplashColorPtr paperColorA)
 {
-    outputDev = NULL;//new SplashOutputDev(colorModeA, bitmapRowPadA, reverseVideoA, paperColorA);
-    textOut = NULL;//new TextOutputDev(NULL, gTrue, gFalse, gFalse);
+    splashOut = NULL;
+    textOut = NULL;
     pdfdoc = NULL;    
     ctrl   = NULL;
 }
 
 CPDFCore::~CPDFCore(void)
 {
-    if (outputDev) { delete outputDev; outputDev = NULL; }
+    if (textOut) { delete textOut; textOut = NULL; }
+    if (splashOut) { delete splashOut; splashOut = NULL; }
     if (pdfdoc) { delete pdfdoc; pdfdoc = NULL; }
     ctrl = NULL;
 }
@@ -63,15 +64,20 @@
     }
     
     // done
-    if (NULL == outputDev)
+    if (NULL == textOut)
+    {
+        textOut = new TextOutputDev(NULL, gFalse, gFalse, gFalse);
+    }
+
+    if (NULL == splashOut)
     {
         SplashColor     white;
         white[0] = 255;
         white[1] = 255;
         white[2] = 255;
-        outputDev = new SplashOutputDev(splashModeMono8, 4, gFalse, white);
+	splashOut = new SplashOutputDev(splashModeMono8, 4, gFalse, white);
     }
-    outputDev->startDoc(pdfdoc->getXRef());
+    splashOut->startDoc(pdfdoc->getXRef());
     return ret;
 }
 
@@ -84,7 +90,8 @@
 // only close the document
 void CPDFCore::close()
 {
-    if (outputDev) {  delete outputDev; outputDev = NULL; }
+    if (textOut) { delete textOut; textOut = NULL; }
+    if (splashOut) {  delete splashOut; splashOut = NULL; }
     if (pdfdoc) { delete pdfdoc; pdfdoc = NULL; }
 }
 
@@ -146,19 +153,19 @@
 
     RenderRet ret = Render_Error;
     
-    ret = pdfdoc->displayPage(outputDev, info.pageNumber, 
+    ret = pdfdoc->displayPage(splashOut, info.pageNumber,
         info.hDPI, info.vDPI, info.rotate, useMediaBox, crop, doLinks,
         abortCheckCbk, abortCheckCbkData);
     
     // check result
     if (ret == Render_Error || ret == Render_Invalid)
     {
-        PV_ERRORPRINTF("Render page error!");
+	PV_ERRORPRINTF("Splash render page error!");
         return ret;
     }
 
     // bitmap has been allocated
-    info.bitmap = outputDev->takeBitmap();
+    info.bitmap = splashOut->takeBitmap();
     if (ret == Render_Done)
     {
 #if (PV_PROFILE_ON)
@@ -167,8 +174,8 @@
 #endif
 	    
         // copy ctm and ictm
-        memcpy(info.ctm, outputDev->getDefCTM(), 6 * sizeof(double));
-        memcpy(info.ictm, outputDev->getDefICTM(), 6 * sizeof(double));        
+	memcpy(info.ctm, splashOut->getDefCTM(), 6 * sizeof(double));
+	memcpy(info.ictm, splashOut->getDefICTM(), 6 * sizeof(double));
                 
         // take links
         info.links  = pdfdoc->takeLinks();
diff -EwBurNd ipdf/src/PDFLandscapeView.cpp column/ipdf/src/PDFLandscapeView.cpp
--- ipdf/src/PDFLandscapeView.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/PDFLandscapeView.cpp	2007-10-14 14:14:10.000000000 +0200
@@ -913,18 +913,26 @@
     }            
     
     // mode
-    if (view->ctrl->channels.getContinousState() == iconState_normal &&
+    if (view->ctrl->channels.getViewState() != iconID_continuous_mode &&
         view->isContinousMode())
     {
         bDirty = gTrue;
-        view->ctrl->channels.setContinousState(3);
+	view->ctrl->channels.setViewState(iconID_continuous_mode);
     }        
-    else if (view->ctrl->channels.getContinousState() == 3 &&
+    else if (view->ctrl->channels.getViewState() != iconID_page_mode &&
              view->isPageMode())
     {
         bDirty = gTrue;
-        view->ctrl->channels.setContinousState(iconState_normal);
+	view->ctrl->channels.setViewState(iconID_page_mode);
+    }
+    /* landscape does not yet have a column mode
+    else if (view->ctrl->channels.getViewState() != iconID_start_reading &&
+	     view->isColumnMode())
+    {
+	bDirty = gTrue;
+	view->ctrl->channels.setViewState(iconID_start_reading);
     }
+    */
 
     // backward
     if (view->ctrl->channels.getBackwardState() == iconState_grey &&
@@ -1301,9 +1309,9 @@
         int y = view->ctrl->settings.getScreenY();
         view->ctrl->settings.setScreenY(rect.left - y);
     }
-    else if (view->isContinousMode())
+    else if (view->isContinousMode() || view->isColumnMode())
     {
-        // from continous mode to page mode
+	// from continous mode / column mode to page mode
         view->setPageMode();
         
         // adjust position, in page mode, display page from top or from offset?
diff -EwBurNd ipdf/src/PDFPortraitView.cpp column/ipdf/src/PDFPortraitView.cpp
--- ipdf/src/PDFPortraitView.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/PDFPortraitView.cpp	2007-10-22 20:55:07.000000000 +0200
@@ -16,6 +16,8 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/* Column mode copyright (c) 2007, Willem Dijkstra <wpd@xs4all.nl> */
+
 #include "PDFPortraitView.h"
 #include "PDFView.h"
 #include "controller.h"
@@ -47,7 +49,8 @@
     {
         // validatePosition();
     }
-    else if (view->isContinousMode())
+    else if (view->isContinousMode() ||
+	     view->isColumnMode())
     {
         // update zoom, otherwise zoomPage and zoomWidth will cause
         // page size problems, because not all pages are rendered in
@@ -184,6 +187,16 @@
                 return FALSE;
         }
         PV_LOGPRINTF("Seems no link!");                                    
+
+        if (view->isColumnMode())
+        {
+            // determine if a column got tapped
+            if (doColumnTap(x, y))
+            {
+                displayPage(view->ctrl->settings.getCurrentPage(), ScrollToPosition);
+                return FALSE;
+            }
+        }
     }
     if (view->isPanEnable())
     {
@@ -412,7 +425,7 @@
                 }                    
             }
             
-            displayPage(pg);
+	    displayPage(pg, ScrollToPage);
             break;
         }                
         case ccVwrToolbar:
@@ -439,7 +452,8 @@
                 {
                     zoomFitPageMode();
                 }
-                else if (view->isContinousMode())
+		else if (view->isContinousMode() ||
+			 view->isColumnMode()) // TODO
                 {
                     zoomFitContinousMode();
                 }
@@ -448,6 +462,11 @@
                      iconID == iconID_landscape_portrait)
             {
                 view->ctrl->channels.setRotateState(RotateDirty);  
+                if (view->isColumnMode())
+                {
+                    switchMode();
+                }
+
                 if (view->isPageMode())
                 {                  
                     view->rotatePageMode(-90);
@@ -458,7 +477,8 @@
                 }                    
             }
             else if (iconID == iconID_page_mode ||
-                     iconID == iconID_continuous_mode)
+		     iconID == iconID_continuous_mode ||
+		     iconID == iconID_start_reading)
             {
                 switchMode();
             }
@@ -562,15 +582,18 @@
     }
     else if (view->isContinousMode())
     {
-        // calcuate pages should be displayed from pagenumber and scroll mode
-        int start = pageNumber, end = pageNumber;
-        getPagesRange(start, end, pageNumber, scroll);
+	int start, end;
+        start = end = pageNumber;
 
-        // debug
-        PV_LOGPRINTF("Visible page range [%d, %d] current page %d", start, end, 
-            view->ctrl->settings.getCurrentPage());
+	getPagesRange(start, end, pageNumber, scroll);
+	displayPages(start, end);
+    }
+    else if (view->isColumnMode())
+    {
+        int start, end;
+        start = end = pageNumber;
 
-        // display them
+        advanceColumn(start, end, pageNumber, scroll);
         displayPages(start, end);
     }
 }
@@ -817,7 +840,7 @@
         }
         layout.updatePageRect(x, y, page->bitmap->getWidth(), page->bitmap->getHeight());
     }
-    else if (view->isContinousMode())
+    else if (view->isContinousMode() || view->isColumnMode())
     {
         rectangle rect;
         layout.getPageRect(page->pageNumber, rect);
@@ -825,12 +848,21 @@
         y = rect.top - view->ctrl->settings.getScreenY();
     }
 
-    // display image. draw border only in continous mode
-    view->ctrl->gtkMgr.drawImage(page->bitmap,
+    view->ctrl->gtkMgr.drawImage(
+        page->bitmap,
         0, 0, 
         x, y,
         page->bitmap->getWidth(), page->bitmap->getHeight(),
-        view->isContinousMode());
+        view->isContinousMode() || view->isColumnMode());
+
+    if (view->isColumnMode() && view->ctrl->settings.getColHighlight())
+    {
+        rectangle crect;
+        if (layout.getColumnRect(view->ctrl, page->pageNumber, view->ctrl->settings.getColNr(), crect) == gTrue)
+        {
+            view->ctrl->gtkMgr.drawRectangle(crect);
+        }
+    }
 
     // draw scribble, x & y refers page start position in screen
     drawScribble(x, y, page->pageNumber);
@@ -859,7 +891,7 @@
             view->ctrl->channels.setPanState(iconState_grey);
         }
     }
-    else if (view->isContinousMode() &&
+    else if ((view->isContinousMode() || view->isColumnMode()) &&
              rect.right - rect.left <= view->ctrl->settings.getScreenWidth() &&
              rect.bottom - rect.top <= view->ctrl->settings.getScreenHeight() &&
              view->ctrl->channels.getPanState() != iconState_grey)
@@ -935,17 +967,23 @@
     }            
 
     // mode
-    if (view->ctrl->channels.getContinousState() == iconState_normal &&
+    if (view->ctrl->channels.getViewState() != iconID_continuous_mode &&
         view->isContinousMode())
     {
         bDirty = gTrue;
-        view->ctrl->channels.setContinousState(3);
+	view->ctrl->channels.setViewState(iconID_continuous_mode);
     }        
-    else if (view->ctrl->channels.getContinousState() == 3 &&
+    else if (view->ctrl->channels.getViewState() != iconID_page_mode &&
              view->isPageMode())
     {
         bDirty = gTrue;
-        view->ctrl->channels.setContinousState(iconState_normal);
+	view->ctrl->channels.setViewState(iconID_page_mode);
+    }
+    else if (view->ctrl->channels.getViewState() != iconID_start_reading &&
+	     view->isColumnMode())
+    {
+	bDirty = gTrue;
+	view->ctrl->channels.setViewState(iconID_start_reading);
     }
 
     // backward
@@ -1017,7 +1055,8 @@
     {
         zoomFromRectPageMode(rect);
     }
-    else if (view->isContinousMode())
+    else if (view->isContinousMode() ||
+	     view->isColumnMode()) // TODO
     {
         zoomFromRectContinousMode(rect);
     }
@@ -1235,28 +1274,53 @@
 void CPDFPortraitView::validatePosition()
 {
     rectangle rect; 
+    int sy = view->ctrl->settings.getScreenY();
+    int sx = view->ctrl->settings.getScreenX();
     int w = 0;
     layout.getVirtualScreen(rect);    
-    if (view->isContinousMode())
+    if (view->isColumnMode())
+    {
+        w = view->ctrl->settings.getScreenWidth();
+        int h = view->ctrl->settings.getScreenHeight();
+
+        layout.getPageRect(view->ctrl->settings.getCurrentPage(), rect);
+        if (sy + h > rect.bottom)
+        {
+            view->ctrl->settings.setScreenY(rect.bottom - h);
+        }
+        else if (sy < rect.top)
+        {
+            view->ctrl->settings.setScreenY(rect.top);
+        }
+
+        if (sx + w > rect.right)
+        {
+            view->ctrl->settings.setScreenX(rect.right - w - Margin);
+        }
+        else if (sx < rect.left)
+        {
+            view->ctrl->settings.setScreenX(rect.left + Margin);
+        }
+    }
+    else if (view->isContinousMode())
     {
         w = rect.right - rect.left;
-        if (view->ctrl->settings.getScreenY() < rect.top + Margin)
+	if (sy < rect.top + Margin)
         {
             view->ctrl->settings.setScreenY(rect.top + Margin);
         }
-        else if (view->ctrl->settings.getScreenY() > 
-            rect.bottom - view->ctrl->settings.getScreenHeight() - Margin)
+	else if (sy > rect.bottom - view->ctrl->settings.getScreenHeight() - Margin)
         {
             view->ctrl->settings.setScreenY(rect.bottom - view->ctrl->settings.getScreenHeight() - Margin);
         }
 
         if (w > view->ctrl->settings.getScreenWidth())
         {
-            if (view->ctrl->settings.getScreenX() < rect.left + Margin)
+	    if (sx < rect.left + Margin)
             {
                 view->ctrl->settings.setScreenX(rect.left + Margin);
             }
-            else if (view->ctrl->settings.getScreenX() + view->ctrl->settings.getScreenWidth() > rect.right - Margin)
+	    else if (sx + view->ctrl->settings.getScreenWidth() > rect.right - Margin)
             {
                 view->ctrl->settings.setScreenX(rect.right - view->ctrl->settings.getScreenWidth() - Margin);
             }
@@ -1273,11 +1337,11 @@
         int h = rect.bottom - rect.top;
         if ( h > view->ctrl->settings.getScreenHeight())
         {
-            if (view->ctrl->settings.getScreenY() < view->ctrl->settings.getScreenHeight() - h + Margin)
+	    if (sy < view->ctrl->settings.getScreenHeight() - h + Margin)
             {
                 view->ctrl->settings.setScreenY(view->ctrl->settings.getScreenHeight() - h + Margin);
             }
-            else if (view->ctrl->settings.getScreenY() > -Margin)
+	    else if (sy > -Margin)
             {
                 view->ctrl->settings.setScreenY(-Margin); 
             }
@@ -1289,11 +1353,11 @@
                 
         if (w > view->ctrl->settings.getScreenWidth())
         {
-            if (view->ctrl->settings.getScreenX() < view->ctrl->settings.getScreenWidth() - w + Margin)
+	    if (sx < view->ctrl->settings.getScreenWidth() - w + Margin)
             {
                 view->ctrl->settings.setScreenX(view->ctrl->settings.getScreenWidth() - w + Margin);
             }
-            else if (view->ctrl->settings.getScreenX() > -Margin) 
+	    else if (sy > -Margin)
             {
                 view->ctrl->settings.setScreenX(-Margin); 
             }
@@ -1324,7 +1388,19 @@
     }
     else if (view->isContinousMode())
     {
-        // from continous mode to page mode
+	// from continous mode to column mode
+        int pn = view->ctrl->settings.getCurrentPage();
+	view->setColumnMode();
+
+        // reset page position
+        init();
+
+        moveToColumnPage(pn);
+
+    }
+    else if (view->isColumnMode())
+    {
+	// from column mode to page mode
         view->setPageMode();
 
         // adjust position
@@ -1337,7 +1413,6 @@
     
     // disable zoomback
     view->ctrl->settings.disableZoomBack();
-    
     displayPage(view->ctrl->settings.getCurrentPage());
 }
 
@@ -1447,3 +1522,329 @@
     view->ctrl->scbMgr.drawScribblePage(pn, 
         view->ctrl, x, y);
 }
+
+void CPDFPortraitView::advanceColumn(int &start, int &end, const int pageNumber, const ContinousModeScroll scroll)
+{
+    rectangle prect;
+    rectangle crect;
+    int pn = view->ctrl->settings.getCurrentPage();
+    int spn = pn;
+    int cn = view->ctrl->settings.getColNr();
+
+    if (scroll == ScrollToPage)
+    {
+        pn = pageNumber;
+        moveToColumnPage(pn);
+        start = end = pn;
+	return;
+    }
+
+    if (scroll == ScrollToNextPage)
+    {
+        if ((layout.getColumnRect(view->ctrl, pn, cn, crect) == gTrue) &&
+            (crect.bottom > view->ctrl->settings.getScreenHeight()))
+        {
+            // column has not yet been viewed to completion
+            PV_LOGPRINTF("advanceColumn: move down; current column partly obscured");
+            layout.getPageRect(pn, prect);
+            view->ctrl->settings.moveScreenY(view->ctrl->settings.getScreenHeight() - PageRepeat);
+        }
+        else
+        {
+            while (1)
+            {
+                PV_LOGPRINTF("advanceColumn: start at page %d, column %d", pn, cn);
+                getNextColumn(pn, cn, crect);
+                PV_LOGPRINTF("advanceColumn: goto page %d, column %d", pn, cn);
+
+                if (spn != pn)
+                {
+                    // we moved to a next page
+                    PV_LOGPRINTF("advanceColumn: moved to first column on a new page");
+                    moveToColumn(crect);
+                    break;
+                } else {
+                    if ((crect.left >= 0) && (crect.right <= view->ctrl->settings.getScreenWidth()) &&
+                        (crect.top >= 0) && (crect.bottom <= view->ctrl->settings.getScreenHeight()))
+                    {
+                        PV_LOGPRINTF("advanceColumn: column already in full view - move on");
+                        continue;
+                    }
+                    // determine if this column is out of view
+                    if ((crect.right > view->ctrl->settings.getScreenWidth()) ||
+                        (crect.left < 0))
+                    {
+                        // move to next column bar
+                        PV_LOGPRINTF("advanceColumn: move to new columnbar on same page");
+                        moveToColumn(crect);
+                        break;
+                    }
+                    if (crect.bottom > view->ctrl->settings.getScreenHeight())
+                    {
+                        // column has not yet been viewed to completion
+                        PV_LOGPRINTF("advanceColumn: move down; current column partly obscured");
+                        view->ctrl->settings.moveScreenY(view->ctrl->settings.getScreenHeight() - PageRepeat);
+                        break;
+                    }
+                }
+            }
+        }
+
+        view->ctrl->settings.setCurrentPage(pn);
+	validatePosition();
+        start = end = pn;
+        return;
+    }
+
+    if (scroll == ScrollToPrevPage)
+    {
+        if ((layout.getColumnRect(view->ctrl, pn, cn, crect) == gTrue) &&
+            (crect.top < 0))
+        {
+            // column bottom is in view, top is not
+            PV_LOGPRINTF("advanceColumn: move up; current column partly obscured");
+            layout.getPageRect(pn, prect);
+            view->ctrl->settings.moveScreenY(- view->ctrl->settings.getScreenHeight() + PageRepeat);
+        }
+        else
+        {
+            while (1)
+            {
+                PV_LOGPRINTF("advanceColumn: start at page %d, column %d", pn, cn);
+                getPreviousColumn(pn, cn, crect);
+                PV_LOGPRINTF("advanceColumn: goto page %d, column %d", pn, cn);
+
+                if (spn != pn)
+                {
+                    // we moved to a previous page
+                    PV_LOGPRINTF("advanceColumn: moved to last column on a previous page");
+                    crect.top = crect.bottom - view->ctrl->settings.getScreenHeight() + PageRepeat;
+                    moveToBottomColumn(crect);
+                    break;
+                } else {
+                    if ((crect.left >= 0) && (crect.right <= view->ctrl->settings.getScreenWidth()) &&
+                        (crect.top >= 0) && (crect.bottom <= view->ctrl->settings.getScreenHeight()))
+                    {
+                        PV_LOGPRINTF("advanceColumn: column already in full view - move on");
+                        continue;
+                    }
+
+                    // determine if this column is out of view
+                    if ((crect.right > view->ctrl->settings.getScreenWidth()) ||
+                        (crect.left < 0))
+                    {
+                        // move to next column bar
+                        PV_LOGPRINTF("advanceColumn: move to new columnbar on same page");
+                        moveToBottomColumn(crect);
+                        break;
+                    }
+                    if (crect.top < 0)
+                    {
+                        // column has not yet been viewed to completion
+                        PV_LOGPRINTF("advanceColumn: move up; current column partly obscured");
+                        view->ctrl->settings.moveScreenY(- view->ctrl->settings.getScreenHeight() + PageRepeat);
+                        break;
+                    }
+                }
+            }
+        }
+
+        view->ctrl->settings.setCurrentPage(pn);
+	validatePosition();
+        start = end = pn;
+        return;
+    }
+
+    if (scroll == ScrollToPosition)
+    {
+	// position is ready, need check
+	validatePosition();
+        start = end = pn;
+	return;
+    }
+
+    if (scroll == ScrollToNextPages)
+    {
+        // "scrolltonextpages" on columns => scroll to next page / column 0
+        moveToColumnPage(++pn);
+        start = end = pn;
+	return;
+    }
+
+    if (scroll == ScrollToPrevPages)
+    {
+        // "scrolltoprevpages" on columns => scroll to the previous page / column 0
+        moveToColumnPage(--pn);
+        start = end = pn;
+	return;
+    }
+
+    if (scroll == ScrollRedraw)
+    {
+	start = nStart; end = nEnd;
+    }
+}
+
+GBool CPDFPortraitView::doColumnTap(const int x, const int y)
+{
+    int cn = 0;
+    int pn = view->ctrl->settings.getCurrentPage();
+    rectangle crect;
+
+    for (;layout.getColumnRect(view->ctrl, pn, cn, crect); cn++)
+    {
+        if ((crect.left <= x) && (crect.right >= x) &&
+            (crect.top <= y) && (crect.bottom >= y))
+        {
+            // found column containing tap
+            view->ctrl->settings.setColNr(cn);
+            moveToColumn(crect);
+            return gTrue;
+        }
+    }
+
+    return gFalse;
+}
+
+void CPDFPortraitView::getNextColumn(int &pageNumber, int &columnNumber, rectangle &colRect)
+{
+    GBool next = gFalse;
+
+    ++columnNumber;
+    // current page needs to be rendered
+    view->waitForPage(pageNumber);
+
+    // we might need to access the next page, prerender it
+    view->forceItem(pageNumber + 1);
+
+    while ((pageNumber <= view->ctrl->core->getNumPages()) &&
+           ((next = layout.getColumnRect(view->ctrl, pageNumber, columnNumber, colRect)) == gFalse))
+    {
+        PV_LOGPRINTF("getNextColumn: no more on page %d", pageNumber);
+        ++pageNumber;
+        view->waitForPage(pageNumber);
+        view->forceItem(pageNumber + 1);
+        columnNumber = 0;
+    }
+
+    view->ctrl->settings.setColNr(columnNumber);
+
+    if ((pageNumber > view->ctrl->core->getNumPages()) ||
+        (next == gFalse))
+    {
+        pageNumber = view->ctrl->core->getNumPages();
+        layout.getPageRect(pageNumber, colRect);
+        colRect.bottom = colRect.bottom - colRect.top;
+        colRect.top = colRect.bottom - view->ctrl->settings.getScreenHeight();
+        return;
+    }
+
+    return;
+}
+
+void CPDFPortraitView::getPreviousColumn(int &pageNumber, int &columnNumber, rectangle &columnRect)
+{
+    GBool next = gFalse;
+
+    if (--columnNumber < 0)
+    {
+        --pageNumber;
+        view->waitForPage(pageNumber);
+        layout.getColumnCount(view->ctrl, pageNumber, columnNumber);
+    } else {
+        view->waitForPage(pageNumber);
+    }
+
+    view->forceItem(pageNumber - 1);
+
+    while ((pageNumber > 0) &&
+           ((next = layout.getColumnRect(view->ctrl, pageNumber, columnNumber, columnRect)) == gFalse))
+    {
+        PV_LOGPRINTF("getPreviousColumn: no more on page %d", pageNumber);
+        --pageNumber;
+        view->waitForPage(pageNumber);
+        view->forceItem(pageNumber - 1);
+        layout.getColumnCount(view->ctrl, pageNumber, columnNumber);
+    }
+
+    view->ctrl->settings.setColNr(columnNumber);
+
+    if ((pageNumber <= 0) ||
+        (next == gFalse))
+    {
+        pageNumber = 1;
+        view->ctrl->settings.setColNr(0);
+        layout.getPageRect(pageNumber, columnRect);
+        columnRect.bottom = columnRect.top + view->ctrl->settings.getScreenHeight();
+        return;
+    }
+
+    return;
+}
+
+void CPDFPortraitView::moveToColumn(const rectangle columnRect)
+{
+    // reposition the screen to show columnRect on current page
+    int sw = view->ctrl->settings.getScreenWidth();
+    int cw = (columnRect.right - columnRect.left);
+    int dx = (cw > sw) ? 0 : min((sw - cw) / 2, view->ctrl->settings.getColXSpace());
+    int dy = view->ctrl->settings.getColYSpace();
+    PV_LOGPRINTF("movetoColumn(): screen x,y (%d, %d) crect (%d, %d, %d, %d) new x, y (%d, %d)",
+                 view->ctrl->settings.getScreenX(),
+                 view->ctrl->settings.getScreenY(),
+                 columnRect.left, columnRect.top, columnRect.right, columnRect.bottom,
+                 columnRect.left - dx,
+                 columnRect.top - dy);
+    view->ctrl->settings.moveScreenX(columnRect.left - dx);
+    view->ctrl->settings.moveScreenY(columnRect.top - dy);
+}
+
+void CPDFPortraitView::moveToBottomColumn(const rectangle columnRect)
+{
+    // reposition the screen to show the bottom of the columnRect on the current page
+    int sw = view->ctrl->settings.getScreenWidth();
+    int cw = (columnRect.right - columnRect.left);
+    int dx = (cw > sw) ? 0 : min((sw - cw) / 2, view->ctrl->settings.getColXSpace());
+    int dy = view->ctrl->settings.getScreenHeight() - view->ctrl->settings.getColYSpace();
+    PV_LOGPRINTF("moveToBottomColumn(): screen x,y (%d, %d) crect (%d, %d, %d, %d) new x, y (%d, %d)",
+                 view->ctrl->settings.getScreenX(),
+                 view->ctrl->settings.getScreenY(),
+                 columnRect.left, columnRect.top, columnRect.right, columnRect.bottom,
+                 columnRect.left - dx,
+                 columnRect.bottom - dy);
+    view->ctrl->settings.moveScreenX(columnRect.left - dx);
+    view->ctrl->settings.moveScreenY(columnRect.bottom - dy);
+}
+
+void CPDFPortraitView::moveToColumnPage(int &pageNumber)
+{
+    // move to column 0 on a particular page number
+    int columnNumber = 0;
+    rectangle rect;
+
+    if (pageNumber < 1)
+    {
+        pageNumber = 1;
+    }
+    else if (pageNumber > view->ctrl->core->getNumPages())
+    {
+        pageNumber = view->ctrl->core->getNumPages();
+    }
+
+    view->ctrl->settings.setCurrentPage(pageNumber);
+    view->ctrl->settings.setColNr(columnNumber);
+    view->waitForPage(pageNumber);
+
+    if (layout.getColumnRect(view->ctrl, pageNumber, columnNumber, rect) == gFalse)
+    {
+        // cannot obtain first column layout
+        layout.getPageRect(pageNumber, rect);
+        rect.bottom = rect.top + view->ctrl->settings.getScreenHeight();
+        view->ctrl->settings.setScreenY(rect.top);
+    }
+    else
+    {
+        moveToColumn(rect);
+    }
+    validatePosition();
+}
diff -EwBurNd ipdf/src/PDFView.cpp column/ipdf/src/PDFView.cpp
--- ipdf/src/PDFView.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/PDFView.cpp	2007-10-22 16:34:04.000000000 +0200
@@ -218,6 +218,11 @@
     return (ctrl->settings.getMode() & ModeContinous);
 }
 
+GBool CPDFView::isColumnMode()
+{
+    return (ctrl->settings.getMode() & ModeColumn);
+}
+
 void CPDFView::setPageMode()
 {
     ctrl->settings.setMode(ModePage);
@@ -228,6 +233,11 @@
     ctrl->settings.setMode(ModeContinous);
 }
 
+void CPDFView::setColumnMode()
+{
+    ctrl->settings.setMode(ModeColumn);
+}
+
 GBool CPDFView::isPortraitView()
 {
     return (ctrl->settings.getRotate() == 0 ||
@@ -717,3 +727,37 @@
 }
 
 
+void CPDFView::forceItem(const int pn)
+{
+    issueItem(pn, gTrue, 0);
+    ctrl->thread.signal();
+}
+
+void CPDFView::waitForPage(const int pn)
+{
+    CPageInfo * page;
+    int s = 0;
+
+    // ensure page number is legal
+    if (pn < 1 || pn > ctrl->core->getNumPages())
+    {
+	return;
+    }
+
+    page = ctrl->pageList.getPage(pn);
+
+    if (page == NULL)
+    {
+	// ay caramba - need page n now - render it and wait
+	ctrl->thread.clearTodoList();
+	forceItem(pn);
+        ctrl->channels.busy_blink();
+        PV_LOGPRINTF("waitForPage(%d): waiting upto %d seconds for rendering to complete",
+                     pn, RenderWait);
+	while ((ctrl->pageList.getPage(pn) == NULL) &&
+	       (s++ < RenderWait))
+	{
+	    sleep(1);
+	}
+    }
+}
diff -EwBurNd ipdf/src/rebuild_static_poppler.sh column/ipdf/src/rebuild_static_poppler.sh
--- ipdf/src/rebuild_static_poppler.sh	1970-01-01 01:00:00.000000000 +0100
+++ column/ipdf/src/rebuild_static_poppler.sh	2007-10-19 13:50:46.000000000 +0200
@@ -0,0 +1,2 @@
+arm-linux-g++ -g -O2 -DHAVE_CONFIG_H -Wall -Werror -I.. -DLOCALE_DIR=\"/usr/share/locale\" -DDATA_DIR=\"/usr/share/ipdf\" -pthread -Wl,-zmuldefs -o ipdf main.o PDFApp.o GtkMgr.o PageInfo.o PDFCore.o PDFView.o RenderThread.o channels.o controller.o Settings.o PDFLandscapeView.o PDFPortraitView.o LayoutMgr.o DisplayList.o utils.o ScribbleMgr.o GtkAuthDialog.o  ../../poppler/poppler/.libs/libpoppler.a -L/usr/local/arm/oe/arm-linux/lib -lerdm -leripc -lermanifest -lerscribble -lxml2 -lpthread -lz -lgthread-2.0 -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -ljpeg
+arm-linux-strip ipdf
diff -EwBurNd ipdf/src/Settings.cpp column/ipdf/src/Settings.cpp
--- ipdf/src/Settings.cpp	2007-10-13 19:30:08.000000000 +0200
+++ column/ipdf/src/Settings.cpp	2007-10-22 21:01:48.000000000 +0200
@@ -56,6 +56,12 @@
     renderDir = RenderNext; 
     mode = ModePage; zbState = iconState_grey;
     enableScb = gTrue; currentItem = 0; 
+
+    colXSpace = 0.05;
+    colYSpace = 0.30;
+    colMinLines = 2;
+    colHighlight = gTrue;
+    colNr = 0;
 }
 
 CSettings::~CSettings(void)
@@ -154,6 +160,7 @@
         ermXmlGetInt(&manifest, "/package/viewer-settings/rotation", &rotate);
         ermXmlGetInt(&manifest, "/package/viewer-settings/positionx", &screenX);
         ermXmlGetInt(&manifest, "/package/viewer-settings/positiony", &screenY);
+        ermXmlGetInt(&manifest, "/package/viewer-settings/column", &colNr);
         ermXmlGetString(&manifest, "/package/viewer-settings/mode", tmp, MAX);
         
         if (0 == strcasecmp(tmp, "continous"))
@@ -164,6 +171,10 @@
         {
             mode = ModePage;
         }
+        else if (0 == strcasecmp(tmp, "column"))
+        {
+            mode = ModeColumn;
+        }
 
         // check scribble state at first.
         // if the string contains any invalid characters, just disable scribble.
@@ -249,6 +260,13 @@
         }
         ermXmlSetInt(&manifest, "/package/viewer-settings/positiony", screenY);                    
 
+        // column number
+        if (RET_OK != ermXmlExist(&manifest, "/package/viewer-settings/column"))
+        {
+            ermXmlNewString(&manifest, "/package/viewer-settings", "column", "");
+        }
+        ermXmlSetInt(&manifest, "/package/viewer-settings/column", colNr);
+
         // mode
         if (RET_OK != ermXmlExist(&manifest, "/package/viewer-settings/mode"))
         {
@@ -258,6 +277,10 @@
         {
             ermXmlSetString(&manifest, "/package/viewer-settings/mode", "continous");
         }
+        else if (mode == ModeColumn)
+        {
+            ermXmlSetString(&manifest, "/package/viewer-settings/mode", "column");
+        }
         else 
         {
             ermXmlSetString(&manifest, "/package/viewer-settings/mode", "page");
