Uses the virtual constructor idiom for the screen object, and moves
the xforms-specific stuff into the subclass. Also documentation
+ sundry cleanups.

Note that screen has long needed further refactoring, but that is
something above and beyond this patch and this time.

With this patch applied :

 47 files changed, 622 insertions, 682 deletions

which is rather healthy, though my merges are starting to get tricky
as some stuff is unfinished and not ready for primetime. Eventually I'll
reach the point of "this is what I have left" for xforms/general code,
and hope somebody else can work out what we need to do...

Is this patch OK ?

thanks
john

? a.diff
? lg.diff
? cvs.log
? gui.diff
? scroll.diff
? frontends/xforms/a.diff
Index: BufferView2.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView2.C,v
retrieving revision 1.131
diff -u -r1.131 BufferView2.C
--- BufferView2.C       12 Jun 2002 02:54:15 -0000      1.131
+++ BufferView2.C       12 Jun 2002 16:02:58 -0000
@@ -594,7 +594,7 @@
 {
        if (theLockingInset() && available()) {
                y += text->cursor.iy() + theLockingInset()->insetInInsetY();
-               if (screen().fitManualCursor(text, this, x, y, asc, desc)) {
+               if (screen().fitManualCursor(this, text, x, y, asc, desc)) {
                        updateScrollbar();
                        return true;
                }
Index: BufferView_pimpl.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView_pimpl.C,v
retrieving revision 1.252
diff -u -r1.252 BufferView_pimpl.C
--- BufferView_pimpl.C  12 Jun 2002 15:01:31 -0000      1.252
+++ BufferView_pimpl.C  12 Jun 2002 16:03:06 -0000
@@ -18,6 +18,7 @@
 #include "frontends/Dialogs.h"
 #include "frontends/Alert.h"
 #include "frontends/FileDialog.h"
+#include "frontends/LScreenFactory.h"
 #include "lyxtext.h"
 #include "lyxrow.h"
 #include "paragraph.h"
@@ -146,7 +147,7 @@
          using_xterm_cursor(false)
 {
        workarea_.reset(new WorkArea(xpos, ypos, width, height));
-       screen_.reset(new LScreen(workarea()));
+       screen_.reset(LScreenFactory::create(workarea()));
  
        // Setup the signals
        
workarea().scrollDocView.connect(boost::bind(&BufferView::Pimpl::scrollDocView, this, 
_1));
@@ -407,8 +408,7 @@
 
 void BufferView::Pimpl::updateScreen()
 {
-       // Regenerate the screen.
-       screen().reset();
+       screen().redraw(bv_->text, bv_);
 }
 
 
Index: frontends/LScreenFactory.h
===================================================================
RCS file: frontends/LScreenFactory.h
diff -N frontends/LScreenFactory.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ frontends/LScreenFactory.h  12 Jun 2002 16:03:07 -0000
@@ -0,0 +1,23 @@
+/**
+ * \file LScreenFactory.h
+ * Copyright 2002 the LyX Team
+ * Read the file COPYING
+ *
+ * \author John Levon <[EMAIL PROTECTED]>
+ */
+
+#ifndef LSCREENFACTORY_H
+#define LSCREENFACTORY_H
+ 
+class WorkArea;
+class LScreen;
+ 
+namespace LScreenFactory {
+       /**
+        * Make a screen renderer. Used because we want to 
+        * generate a toolkit-specific instance.
+        */
+       LScreen * create(WorkArea & owner);
+}
+
+#endif // LSCREEN_FACTORY_H
Index: frontends/Makefile.am
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/Makefile.am,v
retrieving revision 1.41
diff -u -r1.41 Makefile.am
--- frontends/Makefile.am       12 Jun 2002 09:47:10 -0000      1.41
+++ frontends/Makefile.am       12 Jun 2002 16:03:07 -0000
@@ -23,6 +23,7 @@
        FileDialog.h \
        Liason.C \
        Liason.h \
+       LScreenFactory.h \
        Menubar.C \
        Menubar.h \
        Painter.C \
Index: frontends/screen.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/screen.C,v
retrieving revision 1.6
diff -u -r1.6 screen.C
--- frontends/screen.C  12 Jun 2002 10:31:33 -0000      1.6
+++ frontends/screen.C  12 Jun 2002 16:03:07 -0000
@@ -1,284 +1,87 @@
-/* This file is part of
-* ======================================================
-*
-*           LyX, The Document Processor
-*
-*          Copyright 1995 Matthias Ettrich
-*           Copyright 1995-1998 The LyX Team
-*
-* ====================================================== */
-
-#include <config.h>
+/**
+ * \file screen.C
+ * Copyright 2002 the LyX Team
+ * Read the file COPYING
+ *
+ * \author John Levon <[EMAIL PROTECTED]>
+ */
 
 #ifdef __GNUG__
 #pragma implementation
 #endif
 
-#include <algorithm>
+#include <config.h>
 
 #include "screen.h"
 #include "lyxtext.h"
 #include "lyxrow.h"
-#include "frontends/Painter.h"
-#include "frontends/WorkArea.h"
-#include "buffer.h"
 #include "BufferView.h"
+#include "buffer.h"
+#include "WorkArea.h"
+#include "Painter.h"
 #include "font_metrics.h"
-#include "insets/insettext.h"
-#include "frontends/xforms/ColorHandler.h"
 #include "language.h"
+#include "debug.h"
 
-using std::max;
 using std::min;
-
-namespace {
-
-GC createGC()
-{
-       XGCValues val;
-       val.foreground = BlackPixel(fl_get_display(),
-                                   DefaultScreen(fl_get_display()));
-
-       val.function = GXcopy;
-       val.graphics_exposures = false;
-       val.line_style = LineSolid;
-       val.line_width = 0;
-       return XCreateGC(fl_get_display(), RootWindow(fl_get_display(), 0),
-                        GCForeground | GCFunction | GCGraphicsExposures
-                        | GCLineWidth | GCLineStyle , &val);
-}
-
-} // namespace anon
-
-
-// Constructor
-LScreen::LScreen(WorkArea & o)
-       : owner(o), force_clear(true)
+using std::max;
+using std::endl;
+ 
+LScreen::LScreen()
+       : force_clear_(true), cursor_visible_(false)
 {
-       // the cursor isnt yet visible
-       cursor_visible = false;
-       cursor_pixmap = 0;
-       cursor_pixmap_x = 0;
-       cursor_pixmap_y = 0;
-       cursor_pixmap_w = 0;
-       cursor_pixmap_h = 0;
-
-       // We need this GC
-       gc_copy = createGC();
 }
 
 
 LScreen::~LScreen()
 {
-       XFreeGC(fl_get_display(), gc_copy);
 }
 
+// FIXME: GUII these cursor methods need to decide
+// whether the workarea is focused or not
 
-void LScreen::reset()
+void LScreen::showCursor(LyXText const * text, BufferView const * bv)
 {
-       XFreeGC(fl_get_display(), gc_copy);
-       // the cursor isnt yet visible
-       cursor_visible = false;
-       cursor_pixmap = 0;
-       cursor_pixmap_x = 0;
-       cursor_pixmap_y = 0;
-       cursor_pixmap_w = 0;
-       cursor_pixmap_h = 0;
-
-       // We need this GC
-       gc_copy = createGC();
-}
+       if (cursor_visible_)
+               return;
  
+       workarea().getPainter().start();
  
-void LScreen::setCursorColor()
-{
-       if (!lyxColorHandler.get()) return;
-
-       GC gc = lyxColorHandler->getGCForeground(LColor::cursor);
-
-       XGCValues val;
-       XGetGCValues(fl_get_display(),
-                    gc, GCForeground, &val);
-       XChangeGC(fl_get_display(), gc_copy, GCForeground, &val);
-}
-
-
-void LScreen::redraw(LyXText * text, BufferView * bv)
-{
-       drawFromTo(text, bv, 0, owner.workHeight(), 0, 0, text == bv->text);
-       expose(0, 0, owner.workWidth(), owner.workHeight());
-       if (cursor_visible) {
-               cursor_visible = false;
-               bv->showCursor();
-       }
-}
-
-
-void LScreen::expose(int x, int y, int exp_width, int exp_height)
-{
-       XCopyArea(fl_get_display(),
-                 owner.getPixmap(),
-                 owner.getWin(),
-                 gc_copy,
-                 x, y,
-                 exp_width, exp_height,
-                 x + owner.xpos(),
-                 y + owner.ypos());
-}
-
-
-void LScreen::drawFromTo(LyXText * text, BufferView * bv,
-                          int y1, int y2, int y_offset, int x_offset,
-                          bool internal)
-{
-       int y_text = text->first_y + y1;
-
-       // get the first needed row
-       Row * row = text->getRowNearY(y_text);
-       // y_text is now the real beginning of the row
-
-       int y = y_text - text->first_y;
-       // y1 is now the real beginning of row on the screen
-
-       while (row != 0 && y < y2) {
-               LyXText::text_status st = text->status();
-               text->getVisibleRow(bv, y + y_offset,
-                                   x_offset, row, y + text->first_y);
-               internal = internal && (st != LyXText::CHANGED_IN_DRAW);
-               while (internal && text->status() == LyXText::CHANGED_IN_DRAW) {
-                       text->fullRebreak(bv);
-                       st = LyXText::NEED_MORE_REFRESH;
-                       text->setCursor(bv, text->cursor.par(),
-                                       text->cursor.pos());
-                       text->status(bv, st);
-                       // we should be sure our row-pointer is still valid, so it's
-                       // better to recompute it.
-                       y_text = y + text->first_y;
-                       row = text->getRowNearY(y_text);
-                       y = y_text - text->first_y;
-                       text->getVisibleRow(bv, y + y_offset,
-                                           x_offset, row, y + text->first_y);
-               }
-               y += row->height();
-               row = row->next();
-       }
-       force_clear = false;
-
-       // maybe we have to clear the screen at the bottom
-       if ((y < y2) && text->bv_owner) {
-               owner.getPainter().fillRectangle(0, y,
-                                                owner.workWidth(),
-                                                y2 - y,
-                                              LColor::bottomarea);
-       }
-}
-
-
-void LScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row,
-                          int y_text, int y_offset, int x_offset)
-{
-       int const y = y_text - text->first_y + y_offset;
-
-       if (((y + row->height()) > 0) &&
-           ((y - row->height()) <= static_cast<int>(owner.workHeight()))) {
-               // ok there is something visible
-               text->getVisibleRow(bv, y, x_offset, row, y + text->first_y);
-       }
-       force_clear = false;
-}
-
-
-/* draws the screen, starting with textposition y. uses as much already
- * printed pixels as possible */
-void LScreen::draw(LyXText * text, BufferView * bv, unsigned int y)
-{
-       if (cursor_visible) hideCursor();
-
-       int const old_first = text->first_y;
-       bool internal = (text == bv->text);
-       text->first_y = y;
-
-       // is any optimiziation possible?
-       if ((y - old_first) < owner.workHeight()
-           && (old_first - y) < owner.workHeight())
-       {
-               if (text->first_y < old_first) {
-                       drawFromTo(text, bv, 0,
-                                  old_first - text->first_y, 0, 0, internal);
-                       XCopyArea (fl_get_display(),
-                                  owner.getWin(),
-                                  owner.getWin(),
-                                  gc_copy,
-                                  owner.xpos(),
-                                  owner.ypos(),
-                                  owner.workWidth(),
-                                  owner.workHeight() - old_first + text->first_y,
-                                  owner.xpos(),
-                                  owner.ypos() + old_first - text->first_y
-                               );
-                       // expose the area drawn
-                       expose(0, 0,
-                              owner.workWidth(),
-                              old_first - text->first_y);
-               } else  {
-                       drawFromTo(text, bv,
-                                  owner.workHeight() + old_first - text->first_y,
-                                  owner.workHeight(), 0, 0, internal);
-                       XCopyArea (fl_get_display(),
-                                  owner.getWin(),
-                                  owner.getWin(),
-                                  gc_copy,
-                                  owner.xpos(),
-                                  owner.ypos() + text->first_y - old_first,
-                                  owner.workWidth(),
-                                  owner.workHeight() + old_first - text->first_y,
-                                  owner.xpos(),
-                                  owner.ypos());
-                       // expose the area drawn
-                       expose(0, owner.workHeight() + old_first - text->first_y,
-                              owner.workWidth(), text->first_y - old_first);
-               }
-       } else {
-               // make a dumb new-draw
-               drawFromTo(text, bv, 0, owner.workHeight(), 0, 0, internal);
-               expose(0, 0, owner.workWidth(), owner.workHeight());
-       }
-}
-
-
-void LScreen::showCursor(LyXText const * text, BufferView const * bv)
-{
-       if (!cursor_visible) {
-               Cursor_Shape shape = BAR_SHAPE;
-               if (text->real_current_font.language() !=
-                   bv->buffer()->params.language
-                   || text->real_current_font.isVisibleRightToLeft()
-                   != bv->buffer()->params.language->RightToLeft())
-                       shape = (text->real_current_font.isVisibleRightToLeft())
-                               ? REVERSED_L_SHAPE : L_SHAPE;
-               showManualCursor(text, text->cursor.x(), text->cursor.y(),
-                                font_metrics::maxAscent(text->real_current_font),
-                                font_metrics::maxDescent(text->real_current_font),
-                                shape);
+       Cursor_Shape shape = BAR_SHAPE;
+       BufferParams const & bp(bv->buffer()->params);
+       LyXFont const & realfont(text->real_current_font);
+
+       if (realfont.language() != bp.language
+               || realfont.isVisibleRightToLeft() 
+               != bp.language->RightToLeft()) {
+               shape = (realfont.isVisibleRightToLeft())
+                       ? REVERSED_L_SHAPE : L_SHAPE;
        }
+ 
+       showManualCursor(text, text->cursor.x(), text->cursor.y(),
+               font_metrics::maxAscent(realfont),
+               font_metrics::maxDescent(realfont),
+               shape);
+ 
+       workarea().getPainter().end();
 }
 
 
-/* returns true if first has changed, otherwise false */
-bool LScreen::fitManualCursor(LyXText * text, BufferView * bv,
-                               int /*x*/, int y, int asc, int desc)
+bool LScreen::fitManualCursor(BufferView * bv, LyXText * text,
+       int /*x*/, int y, int asc, int desc)
 {
+       int const vheight = workarea().workHeight();
        int newtop = text->first_y;
-
-       if (y + desc - text->first_y >= static_cast<int>(owner.workHeight()))
-               newtop = y - 3 * owner.workHeight() / 4;  // the scroll region must be 
so big!!
+ 
+       if (y + desc - text->first_y >= vheight)
+               newtop = y - 3 * vheight / 4;  // the scroll region must be so big!!
        else if (y - asc < text->first_y
                && text->first_y > 0) {
-               newtop = y - owner.workHeight() / 4;
+               newtop = y - vheight / 4;
        }
 
        newtop = max(newtop, 0); // can newtop ever be < 0? (Lgb)
-
+ 
        if (newtop != text->first_y) {
                draw(text, bv, newtop);
                text->first_y = newtop;
@@ -288,126 +91,28 @@
 }
 
 
-void LScreen::showManualCursor(LyXText const * text, int x, int y,
-                                int asc, int desc, Cursor_Shape shape)
-{
-       // Update the cursor color.
-       setCursorColor();
-
-       int const y1 = max(y - text->first_y - asc, 0);
-       int const y_tmp = min(y - text->first_y + desc,
-                             static_cast<int>(owner.workHeight()));
-
-       // Secure against very strange situations
-       int const y2 = max(y_tmp, y1);
-
-       if (cursor_pixmap) {
-               XFreePixmap(fl_get_display(), cursor_pixmap);
-               cursor_pixmap = 0;
-       }
-
-       if (y2 > 0 && y1 < int(owner.workHeight())) {
-               cursor_pixmap_h = y2 - y1 + 1;
-               cursor_pixmap_y = y1;
-
-               switch (shape) {
-               case BAR_SHAPE:
-                       cursor_pixmap_w = 1;
-                       cursor_pixmap_x = x;
-                       break;
-               case L_SHAPE:
-                       cursor_pixmap_w = cursor_pixmap_h/3;
-                       cursor_pixmap_x = x;
-                       break;
-               case REVERSED_L_SHAPE:
-                       cursor_pixmap_w = cursor_pixmap_h/3;
-                       cursor_pixmap_x = x - cursor_pixmap_w + 1;
-                       break;
-               }
-
-               cursor_pixmap =
-                       XCreatePixmap (fl_get_display(),
-                                      fl_root,
-                                      cursor_pixmap_w,
-                                      cursor_pixmap_h,
-                                      fl_get_visual_depth());
-               XCopyArea (fl_get_display(),
-                          owner.getWin(),
-                          cursor_pixmap,
-                          gc_copy,
-                          owner.xpos() + cursor_pixmap_x,
-                          owner.ypos() + cursor_pixmap_y,
-                          cursor_pixmap_w,
-                          cursor_pixmap_h,
-                          0, 0);
-               XDrawLine(fl_get_display(),
-                         owner.getWin(),
-                         gc_copy,
-                         x + owner.xpos(),
-                         y1 + owner.ypos(),
-                         x + owner.xpos(),
-                         y2 + owner.ypos());
-               switch (shape) {
-               case BAR_SHAPE:
-                       break;
-               case L_SHAPE:
-               case REVERSED_L_SHAPE:
-                       int const rectangle_h = (cursor_pixmap_h + 10) / 20;
-                       XFillRectangle(fl_get_display(),
-                                      owner.getWin(),
-                                      gc_copy,
-                                      cursor_pixmap_x + owner.xpos(),
-                                      y2 - rectangle_h + 1 + owner.ypos(),
-                                      cursor_pixmap_w - 1, rectangle_h);
-                       break;
-               }
-
-       }
-       cursor_visible = true;
-}
-
-
-void LScreen::hideCursor()
-{
-       if (!cursor_visible) return;
-
-       if (cursor_pixmap) {
-               XCopyArea (fl_get_display(),
-                          cursor_pixmap,
-                          owner.getWin(),
-                          gc_copy,
-                          0, 0,
-                          cursor_pixmap_w, cursor_pixmap_h,
-                          cursor_pixmap_x + owner.xpos(),
-                          cursor_pixmap_y + owner.ypos());
-       }
-       cursor_visible = false;
-}
-
-
 void LScreen::cursorToggle(BufferView * bv) const
 {
-       if (cursor_visible)
+       if (cursor_visible_)
                bv->hideCursor();
        else
                bv->showCursor();
 }
 
 
-/* returns a new top so that the cursor is visible */
 unsigned int LScreen::topCursorVisible(LyXCursor const & cursor, int top_y)
 {
-       int const vheight = owner.workHeight();
-       int newtop = top_y; 
+       int const vheight = workarea().workHeight();
+       int newtop = top_y;
 
        Row * row = cursor.row();
 
        // Is this a hack? Yes, probably... (Lgb)
        if (!row)
                return max(newtop, 0);
-
+       
        if (cursor.y() - row->baseline() + row->height()
-           - top_y >= vheight) {
+           - top_y >= (unsigned int)vheight) {
                if (row->height() < vheight
                    && row->height() > vheight / 4) {
                        newtop = cursor.y()
@@ -418,8 +123,8 @@
                        newtop = cursor.y()
                                - vheight / 2;   /* the scroll region must be so big!! 
*/
                }
-
-       } else if (static_cast<int>(cursor.y() - row->baseline()) <
+               
+       } else if (static_cast<int>((cursor.y()) - row->baseline()) <
                   top_y && top_y > 0) {
                if (row->height() < vheight
                    && row->height() > vheight / 4) {
@@ -437,8 +142,6 @@
 }
 
 
-/* scrolls the screen so that the cursor is visible, if necessary.
-* returns true if a change was made, otherwise false */
 bool LScreen::fitCursor(LyXText * text, BufferView * bv)
 {
        // Is a change necessary?
@@ -449,28 +152,33 @@
        return result;
 }
 
-
+  
 void LScreen::update(LyXText * text, BufferView * bv,
-                      int y_offset, int x_offset)
+       int yo, int xo)
 {
+       int const vwidth = workarea().workWidth();
+       int const vheight = workarea().workHeight();
+
+       workarea().getPainter().start();
+ 
        switch (text->status()) {
        case LyXText::NEED_MORE_REFRESH:
        {
                int const y = max(int(text->refresh_y - text->first_y), 0);
-               drawFromTo(text, bv, y, owner.workHeight(), y_offset, x_offset);
+               drawFromTo(text, bv, y, vheight, yo, xo);
                text->refresh_y = 0;
                // otherwise this is called ONLY from BufferView_pimpl(update)
                // or we should see to set this flag accordingly
                if (text != bv->text)
                        text->status(bv, LyXText::UNCHANGED);
-               expose(0, y, owner.workWidth(), owner.workHeight() - y);
+               expose(0, y, vwidth, vheight - y);
        }
        break;
        case LyXText::NEED_VERY_LITTLE_REFRESH:
        {
                // ok I will update the current cursor row
                drawOneRow(text, bv, text->refresh_row, text->refresh_y,
-                          y_offset, x_offset);
+                          yo, xo);
                // this because if we had a major update the refresh_row could
                // have been set to 0!
                if (text->refresh_row) {
@@ -478,8 +186,8 @@
                        // or we should see to set this flag accordingly
                        if (text != bv->text)
                                text->status(bv, LyXText::UNCHANGED);
-                       expose(0, text->refresh_y - text->first_y + y_offset,
-                                  owner.workWidth(), text->refresh_row->height());
+                       expose(0, text->refresh_y - text->first_y + yo,
+                                  vwidth, text->refresh_row->height());
                }
        }
        break;
@@ -488,12 +196,14 @@
                // Nothing needs done
                break;
        }
+ 
+       workarea().getPainter().end();
 }
 
 
 void LScreen::toggleSelection(LyXText * text, BufferView * bv,
                                bool kill_selection,
-                               int y_offset, int x_offset)
+                               int yo, int xo)
 {
        // only if there is a selection
        if (!text->selection.set()) return;
@@ -503,45 +213,140 @@
                                     - text->selection.end.row()->baseline()
                                     + text->selection.end.row()->height()),
                    text->first_y),
-               static_cast<int>(text->first_y + owner.workHeight()));
+               static_cast<int>(text->first_y + workarea().workHeight()));
        int const top = min(
                max(static_cast<int>(text->selection.start.y() -
                                     text->selection.start.row()->baseline()),
                    text->first_y),
-               static_cast<int>(text->first_y + owner.workHeight()));
+               static_cast<int>(text->first_y + workarea().workHeight()));
 
        if (kill_selection)
                text->selection.set(false);
+ 
+       workarea().getPainter().start();
+ 
        drawFromTo(text, bv, top - text->first_y, bottom - text->first_y,
-                  y_offset, x_offset);
+                  yo, xo);
        expose(0, top - text->first_y,
-              owner.workWidth(),
-              bottom - text->first_y - (top - text->first_y));
+              workarea().workWidth(),
+              bottom - text->first_y - (top - text->first_y));
+ 
+       workarea().getPainter().end();
 }
-
-
+ 
+  
 void LScreen::toggleToggle(LyXText * text, BufferView * bv,
-                            int y_offset, int x_offset)
+                            int yo, int xo)
 {
        if (text->toggle_cursor.par() == text->toggle_end_cursor.par()
            && text->toggle_cursor.pos() == text->toggle_end_cursor.pos())
                return;
-
+       
        int const top_tmp = text->toggle_cursor.y()
                - text->toggle_cursor.row()->baseline();
        int const bottom_tmp = text->toggle_end_cursor.y()
                - text->toggle_end_cursor.row()->baseline()
                + text->toggle_end_cursor.row()->height();
-
-       int const offset = y_offset < 0 ? y_offset : 0;
+       
+       int const offset = yo < 0 ? yo : 0;
        int const bottom = min(max(bottom_tmp, text->first_y),
-                    static_cast<int>(text->first_y + owner.workHeight()))-offset;
+               static_cast<int>(text->first_y + workarea().workHeight())) - offset;
        int const top = min(max(top_tmp, text->first_y),
-                 static_cast<int>(text->first_y + owner.workHeight()))-offset;
+               static_cast<int>(text->first_y + workarea().workHeight())) - offset;
+
+       workarea().getPainter().start();
 
        drawFromTo(text, bv, top - text->first_y,
-                  bottom - text->first_y, y_offset,
-                  x_offset);
-       expose(0, top - text->first_y, owner.workWidth(),
+                  bottom - text->first_y, yo,
+                  xo);
+       expose(0, top - text->first_y, workarea().workWidth(),
               bottom - text->first_y - (top - text->first_y));
+ 
+       workarea().getPainter().end();
+}
+
+
+void LScreen::redraw(LyXText * text, BufferView * bv)
+{
+       workarea().getPainter().start();
+
+       if (!text) {
+               greyOut();
+               expose(0, 0, workarea().workWidth(), workarea().workHeight());
+               workarea().getPainter().end();
+               return;
+       }
+
+       drawFromTo(text, bv, 0, workarea().workHeight(), 0, 0, text == bv->text);
+       expose(0, 0, workarea().workWidth(), workarea().workHeight());
+ 
+       workarea().getPainter().end();
+ 
+       if (cursor_visible_) {
+               cursor_visible_ = false;
+               bv->showCursor();
+       }
+ 
+}
+
+
+void LScreen::greyOut()
+{
+       workarea().getPainter().fillRectangle(0, 0,
+               workarea().workWidth(),
+               workarea().workHeight(),
+               LColor::bottomarea);
+}
+
+
+void LScreen::drawFromTo(LyXText * text, BufferView * bv,
+       int y1, int y2, int yo, int xo,
+       bool internal)
+{
+       int y_text = text->first_y + y1;
+  
+       // get the first needed row
+       Row * row = text->getRowNearY(y_text);
+       // y_text is now the real beginning of the row
+  
+       int y = y_text - text->first_y;
+       // y1 is now the real beginning of row on the screen
+       
+       while (row != 0 && y < y2) {
+               LyXText::text_status st = text->status();
+               text->getVisibleRow(bv, y + yo,
+                                   xo, row, y + text->first_y);
+               internal = internal && (st != LyXText::CHANGED_IN_DRAW);
+               while (internal && text->status() == LyXText::CHANGED_IN_DRAW) {
+                       text->fullRebreak(bv);
+                       st = LyXText::NEED_MORE_REFRESH;
+                       text->setCursor(bv, text->cursor.par(), text->cursor.pos());
+                       text->status(bv, st);
+                       text->getVisibleRow(bv, y + yo,
+                                           xo, row, y + text->first_y);
+               }
+               y += row->height();
+               row = row->next();
+       }
+       force_clear_ = false;
+
+       // maybe we have to clear the screen at the bottom
+       if ((y < y2) && text->bv_owner) {
+               workarea().getPainter().fillRectangle(0, y,
+                       workarea().workWidth(), y2 - y,
+                       LColor::bottomarea);
+       }
+}
+
+
+void LScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row,
+       int y_text, int yo, int xo)
+{
+       int const y = y_text - text->first_y + yo;
+
+       if (((y + row->height()) > 0) &&
+           ((y - row->height()) <= static_cast<int>(workarea().workHeight()))) {
+               text->getVisibleRow(bv, y, xo, row, y + text->first_y);
+       }
+       force_clear_ = false;
 }
Index: frontends/screen.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/screen.h,v
retrieving revision 1.3
diff -u -r1.3 screen.h
--- frontends/screen.h  12 Jun 2002 10:31:33 -0000      1.3
+++ frontends/screen.h  12 Jun 2002 16:03:09 -0000
@@ -6,29 +6,25 @@
  *
  * \author unknown
  * \author John Levon <[EMAIL PROTECTED]>
- */ 
+ */
 
-#ifndef LYXSCREEN_H
-#define LYXSCREEN_H
+#ifndef SCREEN_H
+#define SCREEN_H
 
 #ifdef __GNUG__
 #pragma interface
 #endif
-
-#include <X11/Xlib.h>
-
+ 
 class LyXText;
 class LyXCursor;
 class WorkArea;
-class Buffer;
 class BufferView;
-
 struct Row;
 
 /**
  * LScreen - document rendering management
  *
- * This class is used to manage the on-screen rendering inside the
+ * This class is used to manage the on-screen rendering inside the 
  * work area; it is responsible for deciding which LyXText rows
  * need re-drawing.
  *
@@ -39,34 +35,64 @@
  */
 class LScreen {
 public:
-       ///
+       /// types of cursor in work area
        enum Cursor_Shape {
-               ///
+               /// normal I-beam
                BAR_SHAPE,
-               ///
+               /// L-shape for locked insets of a different language
                L_SHAPE,
-               ///
+               /// reverse L-shape for RTL text
                REVERSED_L_SHAPE
        };
 
-       ///
-       LScreen(WorkArea &);
+       LScreen();
 
-       ///
-       ~LScreen();
-
-       void reset();
+       virtual ~LScreen();
+        
+       /**
+        * draw the screen from a given position
+        * @param y the text position to draw from
+        *
+        * Uses as much of the already printed pixmap as possible 
+        */
+       virtual void draw(LyXText *, BufferView *, unsigned int y) = 0;
  
-       /// Sets the cursor color to LColor::cursor.
-       void setCursorColor();
-
-       /** Draws the screen form textposition y. Uses as much of
-           the already printed pixmap as possible */
-       void draw(LyXText *, BufferView *, unsigned int y);
-
-       /// Redraws the screen, without using existing pixmap
+       /**
+        * showManualCursor - display the cursor on the work area
+        * @param text the lyx text containing the cursor
+        * @param x the x position of the cursor
+        * @param y the y position of the row's baseline
+        * @param asc ascent of the row
+        * @param desc descent of the row
+        * @param shape the current shape
+        */
+       virtual void showManualCursor(LyXText const *, int x, int y,
+                             int asc, int desc,
+                             Cursor_Shape shape) = 0;
+       
+       /// unpaint the cursor painted by showManualCursor()
+       virtual void hideCursor() = 0;
+ 
+       /**
+        * fit the cursor onto the visible work area, scrolling if necessary
+        * @param bv the buffer view
+        * @param vheight the height of the visible region
+        * @param base_y the top of the lyxtext to look at
+        * @param x the new x position
+        * @param y the new y position
+        * @param a ascent of the cursor's row
+        * @param d descent of the cursor's row
+        * @return true if the work area needs scrolling as a result
+        */
+       bool fitManualCursor(BufferView * bv, LyXText * text,
+               int x, int y, int a, int d);
+ 
+       /// redraw the screen, without using existing pixmap
        void redraw(LyXText *, BufferView *);
-
+   
+       /// draw the cursor if it's not already shown
+       void showCursor(LyXText const *, BufferView const *);
+ 
        /**
         * topCursorVisible - get a new "top" to make the cursor visible
         * @param c the cursor
@@ -75,70 +101,71 @@
         * This helper function calculates a new y co-ordinate for
         * the top of the containing region such that the cursor contained
         * within the LyXText is "nicely" visible.
-        */ 
+        */
        unsigned int topCursorVisible(LyXCursor const & c, int top_y);
  
-       /// Redraws the screen such that the cursor is visible
+       /**
+        * fitCursor - fit the cursor onto the work area
+        * @param text the text containing the cursor
+        * @param bv the bufferview
+        * @return true if a change was necessary
+        *
+        * Scrolls the screen so that the cursor is visible,
+        */
        bool fitCursor(LyXText *, BufferView *);
-       ///
-       void showCursor(LyXText const *, BufferView const *);
-       ///
-       void hideCursor();
-       ///
+ 
+       /// show the cursor if it's not, and vice versa
        void cursorToggle(BufferView *) const;
-       ///
-       void showManualCursor(LyXText const *, int x, int y,
-                             int asc, int desc,
-                             Cursor_Shape shape);
-       /// returns 1 if first has changed, otherwise 0
-       bool fitManualCursor(LyXText *, BufferView *, int, int, int, int);
-       ///
+
+       /**
+        * update - update part of the screen rendering
+        * @param text the containing text region
+        * @param bv the bufferview
+        * @param xo the x offset into the text
+        * @param yo the x offset into the text
+        * 
+        * Updates part of the screen. If text->status is
+        * LyXText::NEED_MORE_REFRESH, we update from the
+        * point of change and to the end of the screen.
+        * If text->status is LyXText::NEED_VERY_LITTLE_REFRESH,
+        * we only update the current row. 
+        */
+       void update(LyXText * text, BufferView * bv, int yo = 0, int xo = 0);
+ 
+       /// FIXME
        void toggleSelection(LyXText *, BufferView *, bool = true,
                             int y_offset = 0, int x_offset = 0);
-       ///
+ 
+       /// FIXME - at least change the name !!
        void toggleToggle(LyXText *, BufferView *,
                          int y_offset = 0, int x_offset = 0);
+       
+       /// FIXME
+       bool forceClear() const { return force_clear_; }
+
+protected:
+       /// copies specified area of pixmap to screen
+       virtual void expose(int x, int y, int exp_width, int exp_height) = 0;
 
-       /** Updates part of the screen. If text->status is
-           LyXText::NEED_MORE_REFRESH, we update from the
-           point of change and to the end of the screen.
-           If text->status is LyXText::NEED_VERY_LITTLE_REFRESH,
-           we only update the current row. */
-       void update(LyXText *, BufferView *, int y_offset=0, int x_offset=0);
-       ///
-       bool forceClear() const { return force_clear; }
-
-       ///
-       bool cursor_visible;
-private:
-       /// Copies specified area of pixmap to screen
-       void expose(int x, int y, int exp_width, int exp_height);
-
+       /// get the work area
+       virtual WorkArea & workarea() const = 0;
+ 
        /// y1 and y2 are coordinates of the screen
        void drawFromTo(LyXText *, BufferView *, int y1, int y2,
-                       int y_offset = 0, int x_offset = 0, bool internal=false);
+                       int y_offset = 0, int x_offset = 0, bool internal = false);
 
        /// y is a coordinate of the text
        void drawOneRow(LyXText *, BufferView *, Row * row,
                        int y_text, int y_offset = 0, int x_offset = 0);
-
-       ///
-       WorkArea & owner;
-
-       ///
-       Pixmap cursor_pixmap;
-       ///
-       int cursor_pixmap_x;
-       ///
-       int cursor_pixmap_y;
-       ///
-       int cursor_pixmap_w;
-       ///
-       int cursor_pixmap_h;
-       ///
-       GC gc_copy;
-       ///
-       bool force_clear;
+ 
+       /// grey out (no buffer)
+       void greyOut();
+ 
+       /// FIXME ?
+       bool force_clear_;
+ 
+       /// is the blinking cursor currently drawn
+       bool cursor_visible_;
 };
 
-#endif
+#endif // SCREEN_H
Index: frontends/xforms/LScreenFactory.C
===================================================================
RCS file: frontends/xforms/LScreenFactory.C
diff -N frontends/xforms/LScreenFactory.C
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ frontends/xforms/LScreenFactory.C   12 Jun 2002 16:03:10 -0000
@@ -0,0 +1,23 @@
+/**
+ * \file LScreenFactory.C
+ * Copyright 2002 the LyX Team
+ * Read the file COPYING
+ *
+ * \author John Levon <[EMAIL PROTECTED]>
+ */
+
+#include <config.h>
+ 
+#include "frontends/LScreenFactory.h"
+
+#include "XWorkArea.h"
+#include "xscreen.h"
+ 
+namespace LScreenFactory {
+
+LScreen * create(WorkArea & owner)
+{
+       return new XScreen(static_cast<WorkArea &>(owner));
+} 
+ 
+}
Index: frontends/xforms/Makefile.am
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/frontends/xforms/Makefile.am,v
retrieving revision 1.71
diff -u -r1.71 Makefile.am
--- frontends/xforms/Makefile.am        12 Jun 2002 09:47:10 -0000      1.71
+++ frontends/xforms/Makefile.am        12 Jun 2002 16:03:10 -0000
@@ -199,6 +199,7 @@
        FormVCLog.h \
        input_validators.C \
        input_validators.h \
+       LScreenFactory.C \
        lyx_gui.C \
        lyxlookup.C \
        lyxlookup.h \
@@ -229,7 +230,9 @@
        xforms_resize.C \
        xforms_resize.h \
        $(XFORMSGIMAGE) xformsBC.C \
-       xformsBC.h
+       xformsBC.h \
+       xscreen.h \
+       xscreen.C
 
 libxforms.la: $(libxforms_la_OBJECTS) $(libxforms_la_DEPENDENCIES)
 
Index: frontends/xforms/xscreen.C
===================================================================
RCS file: frontends/xforms/xscreen.C
diff -N frontends/xforms/xscreen.C
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ frontends/xforms/xscreen.C  12 Jun 2002 16:03:12 -0000
@@ -0,0 +1,258 @@
+/**
+ * \file xscreen.C
+ * Copyright 1995-2002 the LyX Team
+ * Read the file COPYING
+ *
+ * \author unknown
+ * \author John Levon <[EMAIL PROTECTED]>
+ */
+
+#include <config.h>
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include <algorithm>
+#include <X11/Xlib.h>
+
+#include "frontends/screen.h"
+#include "frontends/font_metrics.h"
+#include "XWorkArea.h"
+#include "xscreen.h"
+#include "lyxtext.h"
+#include "lyxrow.h"
+#include "Painter.h"
+#include "WorkArea.h"
+#include "buffer.h"
+#include "BufferView.h"
+#include "insets/insettext.h"
+#include "ColorHandler.h"
+#include "language.h"
+
+using std::max;
+using std::min;
+
+namespace {
+
+GC createGC()
+{
+       XGCValues val;
+       val.foreground = BlackPixel(fl_get_display(), 
+                                   DefaultScreen(fl_get_display()));
+       
+       val.function = GXcopy;
+       val.graphics_exposures = false;
+       val.line_style = LineSolid;
+       val.line_width = 0;
+       return XCreateGC(fl_get_display(), RootWindow(fl_get_display(), 0), 
+                        GCForeground | GCFunction | GCGraphicsExposures
+                        | GCLineWidth | GCLineStyle , &val);
+}
+
+} // namespace anon
+
+
+// Constructor
+XScreen::XScreen(WorkArea & o)
+       : LScreen(), owner_(o)
+{
+       // the cursor isnt yet visible
+       cursor_pixmap = 0;
+       cursor_pixmap_x = 0;
+       cursor_pixmap_y = 0;
+       cursor_pixmap_w = 0;
+       cursor_pixmap_h = 0;
+
+       // We need this GC
+       gc_copy = createGC();
+}
+
+
+XScreen::~XScreen()
+{
+       XFreeGC(fl_get_display(), gc_copy);
+}
+
+ 
+void XScreen::setCursorColor() 
+{
+       if (!lyxColorHandler.get()) return;
+
+       GC gc = lyxColorHandler->getGCForeground(LColor::cursor);
+       
+       XGCValues val;
+       XGetGCValues(fl_get_display(),
+                    gc, GCForeground, &val);
+       XChangeGC(fl_get_display(), gc_copy, GCForeground, &val);
+}
+
+
+void XScreen::showManualCursor(LyXText const * text, int x, int y,
+                                int asc, int desc, Cursor_Shape shape)
+{
+       // Update the cursor color.
+       setCursorColor();
+       
+       int const y1 = max(y - text->first_y - asc, 0);
+       int const y_tmp = min(y - text->first_y + desc,
+                             static_cast<int>(owner_.workHeight()));
+
+       // Secure against very strange situations
+       int const y2 = max(y_tmp, y1);
+       
+       if (cursor_pixmap) {
+               XFreePixmap(fl_get_display(), cursor_pixmap);
+               cursor_pixmap = 0;
+       }
+
+       if (y2 > 0 && y1 < int(owner_.workHeight())) {
+               cursor_pixmap_h = y2 - y1 + 1;
+               cursor_pixmap_y = y1;
+
+               switch (shape) {
+               case BAR_SHAPE:
+                       cursor_pixmap_w = 1;
+                       cursor_pixmap_x = x;
+                       break;
+               case L_SHAPE:
+                       cursor_pixmap_w = cursor_pixmap_h/3;
+                       cursor_pixmap_x = x;
+                       break;
+               case REVERSED_L_SHAPE:
+                       cursor_pixmap_w = cursor_pixmap_h/3;
+                       cursor_pixmap_x = x - cursor_pixmap_w + 1;
+                       break;
+               }
+
+               cursor_pixmap = 
+                       XCreatePixmap (fl_get_display(),
+                                      fl_root,
+                                      cursor_pixmap_w,
+                                      cursor_pixmap_h,
+                                      fl_get_visual_depth());
+               XCopyArea (fl_get_display(),
+                          owner_.getWin(),
+                          cursor_pixmap,
+                          gc_copy,
+                          owner_.xpos() + cursor_pixmap_x,
+                          owner_.ypos() + cursor_pixmap_y,
+                          cursor_pixmap_w,
+                          cursor_pixmap_h,
+                          0, 0);
+               XDrawLine(fl_get_display(),
+                         owner_.getWin(),
+                         gc_copy,
+                         x + owner_.xpos(),
+                         y1 + owner_.ypos(),
+                         x + owner_.xpos(),
+                         y2 + owner_.ypos());
+               switch (shape) {
+               case BAR_SHAPE:
+                       break;
+               case L_SHAPE:
+               case REVERSED_L_SHAPE:
+                       int const rectangle_h = (cursor_pixmap_h + 10) / 20;
+                       XFillRectangle(fl_get_display(),
+                                      owner_.getWin(),
+                                      gc_copy,
+                                      cursor_pixmap_x + owner_.xpos(),
+                                      y2 - rectangle_h + 1 + owner_.ypos(),
+                                      cursor_pixmap_w - 1, rectangle_h);
+                       break;
+               }
+
+       }
+       cursor_visible_ = true;
+}
+
+
+void XScreen::hideCursor()
+{
+       if (!cursor_visible_) return;
+
+       if (cursor_pixmap) {
+               XCopyArea (fl_get_display(), 
+                          cursor_pixmap,
+                          owner_.getWin(),
+                          gc_copy,
+                          0, 0, 
+                          cursor_pixmap_w, cursor_pixmap_h,
+                          cursor_pixmap_x + owner_.xpos(),
+                          cursor_pixmap_y + owner_.ypos());
+       }
+       cursor_visible_ = false;
+}
+
+ 
+void XScreen::expose(int x, int y, int exp_width, int exp_height)
+{
+       // FIXME: here we should definitely NOT do this.
+       // we need to generate an expose event for the workarea
+       // and then copy from the pixmap to the screen. This
+       // is the Sane Way (tm) 
+       XCopyArea(fl_get_display(),
+                 owner_.getPixmap(),
+                 owner_.getWin(),
+                 gc_copy,
+                 x, y,
+                 exp_width, exp_height,
+                 x + owner_.xpos(),
+                 y + owner_.ypos());
+}
+
+
+void XScreen::draw(LyXText * text, BufferView * bv, unsigned int y)
+{
+       if (cursor_visible_) hideCursor();
+
+       int const old_first = text->first_y;
+       bool internal = (text == bv->text);
+       text->first_y = y;
+
+       // is any optimization possible?
+       if ((y - old_first) < owner_.workHeight()
+           && (old_first - y) < owner_.workHeight())
+       {
+               if (text->first_y < old_first) {
+                       drawFromTo(text, bv, 0,
+                                  old_first - text->first_y, 0, 0, internal);
+                       XCopyArea (fl_get_display(),
+                                  owner_.getWin(),
+                                  owner_.getWin(),
+                                  gc_copy,
+                                  owner_.xpos(),
+                                  owner_.ypos(),
+                                  owner_.workWidth(),
+                                  owner_.workHeight() - old_first + text->first_y,
+                                  owner_.xpos(),
+                                  owner_.ypos() + old_first - text->first_y
+                               );
+                       // expose the area drawn
+                       expose(0, 0,
+                              owner_.workWidth(),
+                              old_first - text->first_y);
+               } else  {
+                       drawFromTo(text, bv,
+                                  owner_.workHeight() + old_first - text->first_y,
+                                  owner_.workHeight(), 0, 0, internal);
+                       XCopyArea (fl_get_display(),
+                                  owner_.getWin(),
+                                  owner_.getWin(),
+                                  gc_copy,
+                                  owner_.xpos(),
+                                  owner_.ypos() + text->first_y - old_first,
+                                  owner_.workWidth(),
+                                  owner_.workHeight() + old_first - text->first_y,
+                                  owner_.xpos(),
+                                  owner_.ypos());
+                       // expose the area drawn
+                       expose(0, owner_.workHeight() + old_first - text->first_y,
+                              owner_.workWidth(), text->first_y - old_first);
+               }
+       } else {
+               // make a dumb new-draw 
+               drawFromTo(text, bv, 0, owner_.workHeight(), 0, 0, internal);
+               expose(0, 0, owner_.workWidth(), owner_.workHeight());
+       }
+}
Index: frontends/xforms/xscreen.h
===================================================================
RCS file: frontends/xforms/xscreen.h
diff -N frontends/xforms/xscreen.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ frontends/xforms/xscreen.h  12 Jun 2002 16:03:12 -0000
@@ -0,0 +1,75 @@
+// -*- C++ -*-
+/**
+ * \file xscreen.h
+ * Copyright 1995-2002 the LyX Team
+ * Read the file COPYING
+ *
+ * \author unknown
+ * \author John Levon <[EMAIL PROTECTED]>
+ */
+
+#ifndef XSCREEN_H
+#define XSCREEN_H
+
+#ifdef __GNUG__
+#pragma interface
+#endif
+
+#include <X11/Xlib.h>
+
+#include "screen.h"
+
+#include "XWorkArea.h"
+ 
+/** The class XScreen is used for the main Textbody.
+    Concretely, the screen is held in a pixmap.  This pixmap is kept up to
+    date and used to optimize drawing on the screen.
+    This class also handles the drawing of the cursor and partly the selection.
+ */
+class XScreen : public LScreen {
+public:
+       ///
+       XScreen(WorkArea &);
+
+       ///
+       virtual ~XScreen();
+
+       /// Sets the cursor color to LColor::cursor.
+       virtual void setCursorColor();
+       ///
+       virtual void hideCursor();
+       ///
+       virtual void showManualCursor(LyXText const *, int x, int y,
+                             int asc, int desc,
+                             Cursor_Shape shape);
+       
+       /** Draws the screen form textposition y. Uses as much of
+           the already printed pixmap as possible */
+       virtual void draw(LyXText *, BufferView *, unsigned int y);
+
+protected:
+       /// get the work area
+       virtual WorkArea & workarea() const { return owner_; }
+ 
+       /// Copies specified area of pixmap to screen
+       virtual void expose(int x, int y, int exp_width, int exp_height); 
+ 
+private:
+       /// our owning widget
+       WorkArea & owner_;
+ 
+       ///
+       Pixmap cursor_pixmap;
+       ///
+       int cursor_pixmap_x;
+       ///
+       int cursor_pixmap_y;
+       ///
+       int cursor_pixmap_w;
+       ///
+       int cursor_pixmap_h;
+       ///
+       GC gc_copy;
+};
+
+#endif

Reply via email to