]> git.lyx.org Git - lyx.git/blob - src/frontends/WorkArea.cpp
remove Dialog::title_, direct setting the title works as well.
[lyx.git] / src / frontends / WorkArea.cpp
1 /**
2  * \file WorkArea.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Abdelrazak Younes
8  *
9  * Full author contact details are available in file CREDITS.
10  *
11  * Splash screen code added by Angus Leeming
12  */
13
14 #include <config.h>
15
16 #include "frontends/WorkArea.h"
17
18 #include "frontends/Application.h"
19 #include "frontends/FontMetrics.h"
20 #include "frontends/LyXView.h"
21
22 #include "BufferView.h"
23 #include "Buffer.h"
24 #include "BufferParams.h"
25 #include "Color.h"
26 #include "CoordCache.h"
27 #include "Cursor.h"
28 #include "debug.h"
29 #include "Font.h"
30 #include "FuncRequest.h"
31 #include "Language.h"
32 #include "LyXFunc.h"
33 #include "LyXRC.h"
34 #include "MetricsInfo.h"
35
36 #include "gettext.h"
37 #include "support/ForkedcallsController.h"
38 #include "support/FileName.h"
39
40 #include <boost/utility.hpp>
41 #include <boost/bind.hpp>
42 #include <boost/current_function.hpp>
43
44 using lyx::support::ForkedcallsController;
45
46 using std::endl;
47 using std::min;
48 using std::max;
49 using std::string;
50
51
52 namespace {
53
54 // All the below connection objects are needed because of a bug in some
55 // versions of GCC (<=2.96 are on the suspects list.) By having and assigning
56 // to these connections we avoid a segfault upon startup, and also at exit.
57 // (Lgb)
58
59 boost::signals::connection timecon;
60
61 } // anon namespace
62
63 namespace lyx {
64 namespace frontend {
65
66 WorkArea::WorkArea(Buffer & buffer, LyXView & lv)
67         : buffer_view_(new BufferView(buffer)), lyx_view_(&lv),
68         cursor_visible_(false), cursor_timeout_(400)
69 {
70         // Setup the signals
71         timecon = cursor_timeout_.timeout
72                 .connect(boost::bind(&WorkArea::toggleCursor, this));
73
74         bufferChangedConnection_ =
75                 buffer.changed.connect(
76                         boost::bind(&WorkArea::redraw, this));
77
78         bufferClosingConnection_ =
79                 buffer.closing.connect(
80                 boost::bind(&WorkArea::close, this));
81
82         cursor_timeout_.start();
83 }
84
85
86 WorkArea::~WorkArea()
87 {
88         bufferChangedConnection_.disconnect();
89         bufferClosingConnection_.disconnect();
90
91         delete buffer_view_;
92 }
93
94
95 void WorkArea::close()
96 {
97         lyx_view_->removeWorkArea(this);
98 }
99
100 //void WorkArea::setLyXView(LyXView * lyx_view)
101 //{
102 //      lyx_view_ = lyx_view;
103 //}
104
105
106 BufferView & WorkArea::bufferView()
107 {
108         return *buffer_view_;
109 }
110
111
112 BufferView const & WorkArea::bufferView() const
113 {
114         return *buffer_view_;
115 }
116
117
118 void WorkArea::stopBlinkingCursor()
119 {
120         cursor_timeout_.stop();
121         hideCursor();
122 }
123
124
125 void WorkArea::startBlinkingCursor()
126 {
127         showCursor();
128         cursor_timeout_.restart();
129 }
130
131
132 void WorkArea::redraw()
133 {
134         if (!isVisible())
135                 // No need to redraw in this case.
136                 return;
137
138         // No need to do anything if this is the current view. The BufferView
139         // metrics are already up to date.
140         if (lyx_view_ != theApp()->currentView()) {
141                 // FIXME: it would be nice to optimize for the off-screen case.
142                 buffer_view_->updateMetrics(false);
143                 buffer_view_->cursor().fixIfBroken();
144         }
145
146         updateScrollbar();
147
148         // update cursor position, because otherwise it has to wait until
149         // the blinking interval is over
150         if (cursor_visible_) {
151                 hideCursor();
152                 showCursor();
153         }
154         
155         ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo();
156
157         LYXERR(Debug::WORKAREA) << "WorkArea::redraw screen" << endl;
158
159         int const ymin = std::max(vi.y1, 0);
160         int const ymax = vi.p2 < vi.size - 1 ? vi.y2 : height();
161
162         expose(0, ymin, width(), ymax - ymin);
163
164         //LYXERR(Debug::WORKAREA)
165         //<< "  ymin = " << ymin << "  width() = " << width()
166 //              << "  ymax-ymin = " << ymax-ymin << std::endl;
167
168         if (lyxerr.debugging(Debug::WORKAREA))
169                 buffer_view_->coordCache().dump();
170 }
171
172
173 void WorkArea::processKeySym(KeySymbolPtr key, key_modifier::state state)
174 {
175         // In order to avoid bad surprise in the middle of an operation, we better stop
176         // the blinking cursor.
177         stopBlinkingCursor();
178
179         theLyXFunc().setLyXView(lyx_view_);
180         theLyXFunc().processKeySym(key, state);
181 }
182
183
184 void WorkArea::dispatch(FuncRequest const & cmd0, key_modifier::state k)
185 {
186         // Handle drag&drop
187         if (cmd0.action == LFUN_FILE_OPEN) {
188                 lyx_view_->dispatch(cmd0);
189                 return;
190         }
191
192         theLyXFunc().setLyXView(lyx_view_);
193
194         FuncRequest cmd;
195
196         if (cmd0.action == LFUN_MOUSE_PRESS) {
197                 if (k == key_modifier::shift)
198                         cmd = FuncRequest(cmd0, "region-select");
199                 else if (k == key_modifier::ctrl)
200                         cmd = FuncRequest(cmd0, "paragraph-select");
201                 else
202                         cmd = cmd0;
203         }
204         else
205                 cmd = cmd0;
206
207         // In order to avoid bad surprise in the middle of an operation, we better stop
208         // the blinking cursor.
209         if (!(cmd.action == LFUN_MOUSE_MOTION
210                 && cmd.button() == mouse_button::none))
211                 stopBlinkingCursor();
212
213         bool const needRedraw = buffer_view_->workAreaDispatch(cmd);
214
215         if (needRedraw)
216                 buffer_view_->buffer().changed();
217
218         // Skip these when selecting
219         if (cmd.action != LFUN_MOUSE_MOTION) {
220                 lyx_view_->updateLayoutChoice();
221                 lyx_view_->updateToolbars();
222         }
223
224         // GUI tweaks except with mouse motion with no button pressed.
225         if (!(cmd.action == LFUN_MOUSE_MOTION
226                 && cmd.button() == mouse_button::none)) {
227                 // Slight hack: this is only called currently when we
228                 // clicked somewhere, so we force through the display
229                 // of the new status here.
230                 lyx_view_->clearMessage();
231
232                 // Show the cursor immediately after any operation.
233                 startBlinkingCursor();
234         }
235 }
236
237
238 void WorkArea::resizeBufferView()
239 {
240         // WARNING: Please don't put any code that will trigger a repaint here!
241         // We are already inside a paint event.
242         lyx_view_->busy(true);
243         buffer_view_->resize(width(), height());
244         lyx_view_->updateLayoutChoice();
245         lyx_view_->busy(false);
246 }
247
248
249 void WorkArea::updateScrollbar()
250 {
251         buffer_view_->updateScrollbar();
252         ScrollbarParameters const & scroll_ = buffer_view_->scrollbarParameters();
253         setScrollbarParams(scroll_.height, scroll_.position,
254                 scroll_.lineScrollHeight);
255 }
256
257
258 void WorkArea::scrollBufferView(int position)
259 {
260         stopBlinkingCursor();
261         buffer_view_->scrollDocView(position);
262         redraw();
263         if (lyxrc.cursor_follows_scrollbar) {
264                 buffer_view_->setCursorFromScrollbar();
265                 lyx_view_->updateLayoutChoice();
266         }
267         // Show the cursor immediately after any operation.
268         startBlinkingCursor();
269 }
270
271
272 void WorkArea::showCursor()
273 {
274         if (cursor_visible_)
275                 return;
276
277         CursorShape shape = BAR_SHAPE;
278
279         Font const & realfont = buffer_view_->cursor().real_current_font;
280         BufferParams const & bp = buffer_view_->buffer().params();
281         bool const samelang = realfont.language() == bp.language;
282         bool const isrtl = realfont.isVisibleRightToLeft();
283
284         if (!samelang || isrtl != bp.language->rightToLeft()) {
285                 shape = L_SHAPE;
286                 if (isrtl)
287                         shape = REVERSED_L_SHAPE;
288         }
289
290         // The ERT language hack needs fixing up
291         if (realfont.language() == latex_language)
292                 shape = BAR_SHAPE;
293
294         Font const font = buffer_view_->cursor().getFont();
295         FontMetrics const & fm = theFontMetrics(font);
296         int const asc = fm.maxAscent();
297         int const des = fm.maxDescent();
298         int h = asc + des;
299         int x = 0;
300         int y = 0;
301         buffer_view_->cursor().getPos(x, y);
302         y -= asc;
303
304         // if it doesn't touch the screen, don't try to show it
305         if (y + h < 0 || y >= height())
306                 return;
307
308         cursor_visible_ = true;
309         showCursor(x, y, h, shape);
310 }
311
312
313 void WorkArea::hideCursor()
314 {
315         if (!cursor_visible_)
316                 return;
317
318         cursor_visible_ = false;
319         removeCursor();
320 }
321
322
323 void WorkArea::toggleCursor()
324 {
325         if (cursor_visible_)
326                 hideCursor();
327         else
328                 showCursor();
329
330         // Use this opportunity to deal with any child processes that
331         // have finished but are waiting to communicate this fact
332         // to the rest of LyX.
333         ForkedcallsController & fcc = ForkedcallsController::get();
334         fcc.handleCompletedProcesses();
335
336         cursor_timeout_.restart();
337 }
338
339 } // namespace frontend
340 } // namespace lyx