]> git.lyx.org Git - features.git/blob - src/BufferView.C
9f051925fc8d7c044576132dd2e338abff8fdf80
[features.git] / src / BufferView.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  * 
5  *           LyX, The Document Processor
6  *        
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-1999 The LyX Team.
9  *
10  * ====================================================== */
11
12 #include <config.h>
13
14 #include <cstdlib>
15 #include <csignal>
16
17 #include <unistd.h>
18 #include <sys/wait.h>
19
20 #include "support/lstrings.h"
21
22 #ifdef __GNUG__
23 #pragma implementation
24 #endif
25
26 #include "commandtags.h"
27 #include "BufferView.h"
28 #include "bufferlist.h"
29 #include "LyXView.h"
30 #include "lyxfunc.h"
31 #include "insets/lyxinset.h"
32 #include "minibuffer.h"
33 #include "lyxscreen.h"
34 #include "up.xpm"
35 #include "down.xpm"
36 #include "debug.h"
37 #include "lyxdraw.h"
38 #include "lyx_gui_misc.h"
39 #include "BackStack.h"
40 #include "lyxtext.h"
41 #include "lyx_cb.h"
42 #include "gettext.h"
43 #include "layout.h"
44
45 extern BufferList bufferlist;
46 void sigchldhandler(pid_t pid, int *status);
47
48 extern void SetXtermCursor(Window win);
49 extern bool input_prohibited;
50 extern bool selection_possible;
51 extern void BeforeChange();
52 extern char ascii_type;
53 extern int UnlockInset(UpdatableInset* inset);
54 extern void ToggleFloat();
55 extern void MenuPasteSelection(char at);
56 extern InsetUpdateStruct *InsetUpdateList;
57 extern void UpdateInsetUpdateList();
58 extern void FreeUpdateTimer();
59
60 // This is _very_ temporary
61 FL_OBJECT * figinset_canvas;
62
63 BufferView::BufferView(LyXView *o, int xpos, int ypos,
64                        int width, int height)
65         : owner_(o)
66 {
67         buffer_ = 0;
68 #ifdef MOVE_TEXT
69         text = 0;
70 #endif
71         screen = 0;
72         work_area = 0;
73         figinset_canvas = 0;
74         scrollbar = 0;
75         button_down = 0;
76         button_up = 0;
77         timer_cursor = 0;
78         current_scrollbar_value = 0;
79         create_view(xpos, ypos, width, height);
80         // Activate the timer for the cursor 
81         fl_set_timer(timer_cursor, 0.4);
82         fl_set_focus_object(owner_->getForm(), work_area);
83         work_area_focus = true;
84         lyx_focus = false;
85 }
86
87
88 BufferView::~BufferView()
89 {
90 #ifdef MOVE_TEXT
91         delete text;
92 #endif
93 }
94
95
96 void BufferView::buffer(Buffer *b)
97 {
98         lyxerr[Debug::INFO] << "Setting buffer in BufferView" << endl;
99         if (buffer_) {
100                 buffer_->InsetSleep();
101                 buffer_->delUser(this);
102                 delete text;
103                 text = 0;
104         }
105
106         // Set current buffer
107         buffer_ = b;
108
109         if (bufferlist.getState() == BufferList::CLOSING) return;
110         
111         // Nuke old image
112         if (screen)
113                 delete screen;
114         screen = 0;
115
116         // If we are closing the buffer, use the first buffer as current
117         if (!buffer_) {
118                 buffer_ = bufferlist.first();
119         }
120
121         if (buffer_) {
122                 lyxerr[Debug::INFO] << "  Buffer addr: " << buffer_ << endl;
123                 buffer_->addUser(this);
124                 owner_->getMenus()->showMenus();
125                 // If we don't have a text object for this, we make one
126 #ifdef MOVE_TEXT
127                 if (text == 0)
128                         resizeCurrentBuffer();
129                 else {
130                         updateScreen();
131                         updateScrollbar();
132                 }
133 #else
134                 if (buffer_->text == 0)
135                         resizeCurrentBuffer();
136                 else {
137                         updateScreen();
138                         updateScrollbar();
139                 }
140 #endif
141                 screen->first = screen->TopCursorVisible();
142                 redraw();
143                 updateAllVisibleBufferRelatedPopups();
144                 buffer_->InsetWakeup();
145         } else {
146                 lyxerr[Debug::INFO] << "  No Buffer!" << endl;
147                 owner_->getMenus()->hideMenus();
148                 updateScrollbar();
149                 fl_redraw_object(work_area);
150         }
151         // should update layoutchoice even if we don't have a buffer.
152         owner_->updateLayoutChoice();
153         owner_->getMiniBuffer()->Init();
154         owner_->updateWindowTitle();
155 }
156
157
158 void BufferView::updateScreen()
159 {
160         // Regenerate the screen.
161         if (screen)
162                 delete screen;
163 #ifdef MOVE_TEXT
164         screen = new LyXScreen(FL_ObjWin(work_area),
165                                work_area->w,
166                                work_area->h,
167                                work_area->x,
168                                work_area->y,
169                                text);
170 #else
171         screen = new LyXScreen(FL_ObjWin(work_area),
172                                work_area->w,
173                                work_area->h,
174                                work_area->x,
175                                work_area->y,
176                                buffer_->text);
177 #endif
178 }
179
180
181 void BufferView::resize()
182 {
183         // This will resize the buffer. (Asger)
184         if (buffer_)
185                 resizeCurrentBuffer();
186 }
187
188
189 static bool lgb_hack = false;
190
191 void BufferView::redraw()
192 {
193         lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
194         lgb_hack = true;
195         fl_redraw_object(work_area);
196         fl_redraw_object(scrollbar);
197         fl_redraw_object(button_down);
198         fl_redraw_object(button_up);
199         lgb_hack = false;
200 }
201
202
203 void BufferView::fitCursor()
204 {
205         if (screen) screen->FitCursor();
206 }
207
208
209 void BufferView::update()
210 {
211         if (screen) screen->Update();
212 }
213
214
215 void BufferView::updateScrollbar()
216 {
217         /* If the text is smaller than the working area, the scrollbar
218          * maximum must be the working area height. No scrolling will 
219          * be possible */
220
221         if (!buffer_) {
222                 fl_set_slider_value(scrollbar, 0);
223                 fl_set_slider_size(scrollbar, scrollbar->h);
224                 return;
225         }
226         
227         static long max2 = 0;
228         static long height2 = 0;
229
230         long cbth = 0;
231         long cbsf = 0;
232
233 #ifdef MOVE_TEXT
234         if (text)
235                 cbth = text->height;
236 #else
237         if (buffer_->text)
238                 cbth = buffer_->text->height;
239 #endif
240         if (screen)
241                 cbsf = screen->first;
242
243         // check if anything has changed.
244         if (max2 == cbth &&
245             height2 == work_area->h &&
246             current_scrollbar_value == cbsf)
247                 return;       // no
248         
249         max2 = cbth;
250         height2 = work_area->h;
251         current_scrollbar_value = cbsf;
252
253         if (cbth <= height2) { // text is smaller than screen
254                 fl_set_slider_size(scrollbar, scrollbar->h);
255                 return;
256         }
257         
258         long maximum_height = work_area->h * 3/4 + cbth;
259         long value = cbsf;
260
261         // set the scrollbar
262         double hfloat = work_area->h;
263         double maxfloat = maximum_height;
264    
265         fl_set_slider_value(scrollbar, value);
266         fl_set_slider_bounds(scrollbar, 0,
267                              maximum_height - work_area->h);
268 #if FL_REVISION > 85
269 #ifdef MOVE_TEXT
270         double lineh = text->DefaultHeight();
271 #else
272         double lineh = buffer_->text->DefaultHeight();
273 #endif
274         fl_set_slider_increment(scrollbar, work_area->h-lineh, lineh);
275 #endif
276         if (maxfloat > 0){
277                 if ((hfloat / maxfloat) * float(height2) < 3)
278                         fl_set_slider_size(scrollbar,
279                                            3 / float(height2));
280                 else
281                         fl_set_slider_size(scrollbar,
282                                            hfloat / maxfloat);
283         } else
284                 fl_set_slider_size(scrollbar, hfloat);
285         fl_set_slider_precision(scrollbar, 0);
286 }
287
288
289 void BufferView::redoCurrentBuffer()
290 {
291         lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
292 #ifdef MOVE_TEXT
293         if (text) {
294                 resize();
295                 owner_->updateLayoutChoice();
296         }
297 #else
298         if (buffer_ && buffer_->text) {
299                 resize();
300                 owner_->updateLayoutChoice();
301         }
302 #endif
303 }
304
305
306 int BufferView::resizeCurrentBuffer()
307 {
308         lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
309         
310         LyXParagraph * par = 0;
311         LyXParagraph * selstartpar = 0;
312         LyXParagraph * selendpar = 0;
313         int pos = 0;
314         int selstartpos = 0;
315         int selendpos = 0;
316         int selection = 0;
317         int mark_set = 0;
318
319         ProhibitInput();
320
321         owner_->getMiniBuffer()->Set(_("Formatting document..."));   
322
323 #ifdef MOVE_TEXT
324         if (text) {
325                 par = text->cursor.par;
326                 pos = text->cursor.pos;
327                 selstartpar = text->sel_start_cursor.par;
328                 selstartpos = text->sel_start_cursor.pos;
329                 selendpar = text->sel_end_cursor.par;
330                 selendpos = text->sel_end_cursor.pos;
331                 selection = text->selection;
332                 mark_set = text->mark_set;
333                 delete text;
334         }
335         text = new LyXText(work_area->w, buffer_);
336 #else
337         if (buffer_->text) {
338                 par = buffer_->text->cursor.par;
339                 pos = buffer_->text->cursor.pos;
340                 selstartpar = buffer_->text->sel_start_cursor.par;
341                 selstartpos = buffer_->text->sel_start_cursor.pos;
342                 selendpar = buffer_->text->sel_end_cursor.par;
343                 selendpos = buffer_->text->sel_end_cursor.pos;
344                 selection = buffer_->text->selection;
345                 mark_set = buffer_->text->mark_set;
346                 delete buffer_->text;
347         }
348         buffer_->text = new LyXText(work_area->w, buffer_);
349 #endif
350
351         updateScreen();
352
353 #ifdef MOVE_TEXT
354         if (par) {
355                 text->selection = true;
356                 /* at this point just
357                  * to avoid the Delete-
358                  * Empty-Paragraph
359                  * Mechanism when
360                  * setting the cursor */
361                 text->mark_set = mark_set;
362                 if (selection) {
363                         text->SetCursor(selstartpar, selstartpos);
364                         text->sel_cursor = text->cursor;
365                         text->SetCursor(selendpar, selendpos);
366                         text->SetSelection();
367                         text->SetCursor(par, pos);
368                 } else {
369                        text->SetCursor(par, pos);
370                         text->sel_cursor = text->cursor;
371                         text->selection = false;
372                 }
373         }
374 #else
375         if (par) {
376                 buffer_->text->selection = true;
377                 /* at this point just
378                  * to avoid the Delete-
379                  * Empty-Paragraph
380                  * Mechanism when
381                  * setting the cursor */
382                 buffer_->text->mark_set = mark_set;
383                 if (selection) {
384                         buffer_->text->SetCursor(selstartpar, selstartpos);
385                         buffer_->text->sel_cursor = buffer_->text->cursor;
386                         buffer_->text->SetCursor(selendpar, selendpos);
387                         buffer_->text->SetSelection();
388                         buffer_->text->SetCursor(par, pos);
389                 } else {
390                         buffer_->text->SetCursor(par, pos);
391                         buffer_->text->sel_cursor = buffer_->text->cursor;
392                         buffer_->text->selection = false;
393                 }
394         }
395 #endif
396         screen->first = screen->TopCursorVisible(); /* this will scroll the
397                                                      * screen such that the
398                                                      * cursor becomes
399                                                      * visible */ 
400         updateScrollbar();
401         redraw();
402         owner_->getMiniBuffer()->Init();
403         AllowInput();
404
405         // Now if the title form still exist kill it
406         TimerCB(0, 0);
407
408         return 0;
409 }
410
411
412 void BufferView::gotoError()
413 {
414         if (!screen)
415                 return;
416    
417         screen->HideCursor();
418         BeforeChange();
419 #ifdef MOVE_TEXT
420         update(-2);
421 #else
422         buffer_->update(-2);
423 #endif
424         LyXCursor tmp;
425
426 #ifdef MOVE_TEXT
427         if (!text->GotoNextError()) {
428                 if (text->cursor.pos 
429                     || text->cursor.par != text->FirstParagraph()) {
430                         tmp = text->cursor;
431                         text->cursor.par = text->FirstParagraph();
432                         text->cursor.pos = 0;
433                         if (!text->GotoNextError()) {
434                                 text->cursor = tmp;
435                                 owner_->getMiniBuffer()->Set(_("No more errors"));
436                                 LyXBell();
437                         }
438                 } else {
439                         owner_->getMiniBuffer()->Set(_("No more errors"));
440                         LyXBell();
441                 }
442         }
443         update(0);
444         text->sel_cursor = text->cursor;
445 #else
446         if (!buffer_->text->GotoNextError()) {
447                 if (buffer_->text->cursor.pos 
448                     || buffer_->text->cursor.par != 
449                     buffer_->text->FirstParagraph()) {
450                         tmp = buffer_->text->cursor;
451                         buffer_->text->cursor.par = 
452                                 buffer_->text->FirstParagraph();
453                         buffer_->text->cursor.pos = 0;
454                         if (!buffer_->text->GotoNextError()) {
455                                 buffer_->text->cursor = tmp;
456                                 owner_->getMiniBuffer()->Set(_("No more errors"));
457                                 LyXBell();
458                         }
459                 } else {
460                         owner_->getMiniBuffer()->Set(_("No more errors"));
461                         LyXBell();
462                 }
463         }
464         buffer_->update(0);
465         buffer_->text->sel_cursor = 
466                 buffer_->text->cursor;
467 #endif
468 }
469
470
471 // Just a bunch of C wrappers around static members of BufferView
472 extern "C" void C_BufferView_UpCB(FL_OBJECT * ob, long buf) {
473         BufferView::UpCB(ob, buf);
474 }
475
476 extern "C" void C_BufferView_DownCB(FL_OBJECT * ob, long buf) {
477         BufferView::DownCB(ob, buf);
478 }
479
480 extern "C" void C_BufferView_ScrollCB(FL_OBJECT * ob, long buf) {
481         BufferView::ScrollCB(ob, buf);
482 }
483
484 extern "C" void C_BufferView_CursorToggleCB(FL_OBJECT * ob, long buf) {
485         BufferView::CursorToggleCB(ob, buf);
486 }
487
488 extern "C" int C_BufferView_work_area_handler(FL_OBJECT * ob, int event,
489                                               FL_Coord, FL_Coord, 
490                                               int key, void * xev) {
491         return BufferView::work_area_handler(ob, event, 0, 0, key, xev);
492 }
493
494
495 void BufferView::create_view(int xpos, int ypos, int width, int height)
496 {
497         FL_OBJECT * obj;
498         const int bw = abs(fl_get_border_width());
499
500         // a hack for the figinsets (Matthias)
501         // This one first, then it will probably be invisible. (Lgb)
502         ::figinset_canvas = figinset_canvas = obj = 
503                 fl_add_canvas(FL_NORMAL_CANVAS,
504                               xpos + 1,
505                               ypos + 1, 1, 1, "");
506         fl_set_object_boxtype(obj, FL_NO_BOX);
507         fl_set_object_resize(obj, FL_RESIZE_ALL);
508         fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
509
510         // a box
511         obj = fl_add_box(FL_BORDER_BOX, xpos, ypos,
512                          width - 15,
513                          height, "");
514         fl_set_object_resize(obj, FL_RESIZE_ALL);
515         fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
516
517         // the free object
518         work_area = obj = fl_add_free(FL_INPUT_FREE,
519                                       xpos +bw, ypos+bw,
520                                       width-15-2*bw /* scrollbarwidth */,
521                                       height-2*bw, "",
522                                       C_BufferView_work_area_handler);
523         obj->wantkey = FL_KEY_TAB;
524         obj->u_vdata = this; /* This is how we pass the BufferView
525                                        to the work_area_handler. */
526         fl_set_object_boxtype(obj, FL_DOWN_BOX);
527         fl_set_object_resize(obj, FL_RESIZE_ALL);
528         fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
529
530         //
531         // THE SCROLLBAR
532         //
533
534         // up - scrollbar button
535 #if FL_REVISION > 85
536         fl_set_border_width(-1);
537 #else
538         fl_set_border_width(-2); // to get visible feedback
539 #endif
540         button_up = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
541                                               width-15+4*bw,
542                                               ypos,
543                                               15, 15, "");
544         fl_set_object_boxtype(obj, FL_UP_BOX);
545         fl_set_object_color(obj, FL_MCOL, FL_BLUE);
546         fl_set_object_resize(obj, FL_RESIZE_ALL);
547         fl_set_object_gravity(obj, NorthEastGravity, NorthEastGravity);
548         fl_set_object_callback(obj, C_BufferView_UpCB, 0);
549         obj->u_vdata = this;
550         fl_set_pixmapbutton_data(obj, const_cast<char**>(up_xpm));
551
552 #if FL_REVISION > 85
553         // Remove the blue feedback rectangle
554         fl_set_pixmapbutton_focus_outline(obj, 0);
555 #endif  
556
557         // the scrollbar slider
558         fl_set_border_width(-bw);
559         scrollbar = obj = fl_add_slider(FL_VERT_SLIDER,
560                                         width-15+4*bw,
561                                         ypos + 15,
562                                         15, height-30, "");
563         fl_set_object_color(obj, FL_COL1, FL_MCOL);
564         fl_set_object_boxtype(obj, FL_UP_BOX);
565         fl_set_object_resize(obj, FL_RESIZE_ALL);
566         fl_set_object_gravity(obj, NorthEastGravity, SouthEastGravity);
567         fl_set_object_callback(obj, C_BufferView_ScrollCB, 0);
568         obj->u_vdata = this;
569         
570         // down - scrollbar button
571 #if FL_REVISION > 85
572         fl_set_border_width(-1);
573 #else
574         fl_set_border_width(-2); // to get visible feedback
575 #endif
576         button_down = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
577                                                       width-15+4*bw,
578                                                       ypos + height-15,
579                                                       15, 15, "");
580         fl_set_object_boxtype(obj, FL_UP_BOX);
581         fl_set_object_color(obj, FL_MCOL, FL_BLUE);
582         fl_set_object_resize(obj, FL_RESIZE_ALL);
583         fl_set_object_gravity(obj, SouthEastGravity, SouthEastGravity);
584         fl_set_object_callback(obj, C_BufferView_DownCB, 0);
585         obj->u_vdata = this;
586         fl_set_pixmapbutton_data(obj, const_cast<char**>(down_xpm));
587         fl_set_border_width(-bw);
588
589 #if FL_REVISION >85
590         // Remove the blue feedback rectangle
591         fl_set_pixmapbutton_focus_outline(obj, 0);
592 #endif  
593
594         //
595         // TIMERS
596         //
597         
598         // timer_cursor
599         timer_cursor = obj = fl_add_timer(FL_HIDDEN_TIMER,
600                                           0, 0, 0, 0, "Timer");
601         fl_set_object_callback(obj, C_BufferView_CursorToggleCB, 0);
602         obj->u_vdata = this;
603 }
604
605
606 // Callback for scrollbar up button
607 void BufferView::UpCB(FL_OBJECT * ob, long)
608 {
609         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
610         
611         if (view->buffer_ == 0) return;
612
613         XEvent const * ev2;
614         static long time = 0;
615         ev2 = fl_last_event();
616         if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
617                 time = 0;
618         int button = fl_get_button_numb(ob);
619         switch (button) {
620         case 3:
621                 view->ScrollUpOnePage(time++); break;
622         case 2:
623                 view->ScrollDownOnePage(time++); break;
624         default:
625                 view->ScrollUp(time++); break;
626         }
627 }
628
629
630 static
631 void waitForX()
632 {
633 #if 0
634         static Window w = 0;
635         static Atom a = 0;
636         if (!a)
637                 a = XInternAtom(fl_display, "WAIT_FOR_X", False);
638         if (w == 0) {
639                 int mask;
640                 XSetWindowAttributes attr;
641                 mask = CWOverrideRedirect;
642                 attr.override_redirect = 1;
643                 w = XCreateWindow(fl_display, fl_root,
644                                   0, 0, 1, 1, 0, CopyFromParent,
645                                   InputOnly, CopyFromParent, mask, &attr);
646                 XSelectInput(fl_display, w, PropertyChangeMask);
647                 XMapWindow(fl_display, w);
648         }
649         static XEvent ev;
650         XChangeProperty(fl_display, w, a, a, 8,
651                         PropModeAppend, reinterpret_cast<unsigned char*>(""), 0);
652         XWindowEvent(fl_display, w, PropertyChangeMask, &ev);
653 #endif
654         XSync(fl_get_display(), 0);
655 }
656
657
658 // Callback for scrollbar slider
659 void BufferView::ScrollCB(FL_OBJECT * ob, long)
660 {
661         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
662         extern bool cursor_follows_scrollbar;
663         
664         if (view->buffer_ == 0) return;
665
666         view->current_scrollbar_value = long(fl_get_slider_value(ob));
667         if (view->current_scrollbar_value < 0)
668                 view->current_scrollbar_value = 0;
669    
670         if (!view->screen)
671                 return;
672
673         view->screen->Draw(view->current_scrollbar_value);
674
675         if (cursor_follows_scrollbar) {
676 #ifdef MOVE_TEXT
677                 LyXText * vbt = view->text;
678 #else
679                 LyXText * vbt = view->buffer_->text;
680 #endif
681                 int height = vbt->DefaultHeight();
682                 
683                 if (vbt->cursor.y < view->screen->first + height) {
684                         vbt->SetCursorFromCoordinates(0,
685                                                       view->screen->first +
686                                                       height);
687                 }
688                 else if (vbt->cursor.y >
689                          view->screen->first + view->work_area->h - height) {
690                         vbt->SetCursorFromCoordinates(0,
691                                                       view->screen->first +
692                                                       view->work_area->h  -
693                                                       height);
694                 }
695         }
696         waitForX();
697 }
698
699
700 // Callback for scrollbar down button
701 void BufferView::DownCB(FL_OBJECT * ob, long)
702 {
703         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
704
705         if (view->buffer_ == 0) return;
706         
707         XEvent const * ev2;
708         static long time = 0;
709         ev2 = fl_last_event();
710         if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
711                 time = 0;
712         int button = fl_get_button_numb(ob);
713         switch (button) {
714         case 2:
715                 view->ScrollUpOnePage(time++); break;
716         case 3:
717                 view->ScrollDownOnePage(time++); break;
718         default:
719                 view->ScrollDown(time++); break;
720         }
721 }
722
723
724 int BufferView::ScrollUp(long time)
725 {
726         if (buffer_ == 0) return 0;
727         if (!screen)
728                 return 0;
729    
730         double value= fl_get_slider_value(scrollbar);
731    
732         if (value == 0)
733                 return 0;
734
735 #ifdef MOVE_TEXT
736         float add_value =  (text->DefaultHeight()
737                             + float(time) * float(time) * 0.125);
738    
739         if (add_value > work_area->h)
740                 add_value = float(work_area->h -
741                                   text->DefaultHeight());
742 #else
743         float add_value =  (buffer_->text->DefaultHeight()
744                             + float(time) * float(time) * 0.125);
745    
746         if (add_value > work_area->h)
747                 add_value = float(work_area->h -
748                                   buffer_->text->DefaultHeight());
749 #endif
750    
751         value -= add_value;
752
753         if (value < 0)
754                 value = 0;
755    
756         fl_set_slider_value(scrollbar, value);
757    
758         ScrollCB(scrollbar, 0); 
759         return 0;
760 }
761
762
763 int BufferView::ScrollDown(long time)
764 {
765         if (buffer_ == 0) return 0;
766         if (!screen)
767                 return 0;
768    
769         double value= fl_get_slider_value(scrollbar);
770         double min, max;
771         fl_get_slider_bounds(scrollbar, &min, &max);
772
773         if (value == max)
774                 return 0;
775
776 #ifdef MOVE_TEXT
777         float add_value =  (text->DefaultHeight()
778                             + float(time) * float(time) * 0.125);
779    
780         if (add_value > work_area->h)
781                 add_value = float(work_area->h -
782                                   text->DefaultHeight());
783 #else
784         float add_value =  (buffer_->text->DefaultHeight()
785                             + float(time) * float(time) * 0.125);
786    
787         if (add_value > work_area->h)
788                 add_value = float(work_area->h -
789                                   buffer_->text->DefaultHeight());
790 #endif
791    
792         value += add_value;
793    
794         if (value > max)
795                 value = max;
796    
797         fl_set_slider_value(scrollbar, value);
798    
799         ScrollCB(scrollbar, 0); 
800         return 0;
801 }
802
803
804 void BufferView::ScrollUpOnePage(long /*time*/)
805 {
806         if (buffer_ == 0) return;
807         if (!screen)
808                 return;
809    
810         long y = screen->first;
811
812         if (!y) return;
813 #ifdef MOVE_TEXT
814         Row * row = text->GetRowNearY(y);
815 #else
816         Row * row = buffer_->text->GetRowNearY(y);
817 #endif
818         y = y - work_area->h + row->height;
819         
820         fl_set_slider_value(scrollbar, y);
821    
822         ScrollCB(scrollbar, 0); 
823 }
824
825
826 void BufferView::ScrollDownOnePage(long /*time*/)
827 {
828         if (buffer_ == 0) return;
829         if (!screen)
830                 return;
831    
832         double min, max;
833         fl_get_slider_bounds(scrollbar, &min, &max);
834         long y = screen->first;
835
836 #ifdef MOVE_TEXT
837         if (y > text->height - work_area->h)
838                 return;
839    
840         y += work_area->h;
841         text->GetRowNearY(y);
842 #else
843         if (y > buffer_->text->height - work_area->h)
844                 return;
845    
846         y += work_area->h;
847         buffer_->text->GetRowNearY(y);
848 #endif
849         fl_set_slider_value(scrollbar, y);
850    
851         ScrollCB(scrollbar, 0); 
852 }
853
854
855 int BufferView::work_area_handler(FL_OBJECT * ob, int event,
856                                   FL_Coord, FL_Coord ,
857                                   int /*key*/, void *xev)
858 {
859         static int x_old = -1;
860         static int y_old = -1;
861         static long scrollbar_value_old = -1;
862         
863         XEvent * ev = static_cast<XEvent*>(xev);
864         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
865
866         // If we don't have a view yet; return
867         if (!view || quitting) return 0;
868
869         switch (event){   
870         case FL_DRAW:
871                 view->workAreaExpose(); 
872                 break;
873         case FL_PUSH:
874                 view->WorkAreaButtonPress(ob, 0, 0, 0, ev, 0);
875                 break; 
876         case FL_RELEASE:
877                 view->WorkAreaButtonRelease(ob, 0, 0, 0, ev, 0);
878                 break;
879         case FL_MOUSE:
880                 if (ev->xmotion.x != x_old || 
881                     ev->xmotion.y != y_old ||
882                     view->current_scrollbar_value != scrollbar_value_old) {
883                         x_old = ev->xmotion.x;
884                         y_old = ev->xmotion.y;
885                         scrollbar_value_old = view->current_scrollbar_value;
886                         view->WorkAreaMotionNotify(ob, 0, 0, 0, ev, 0);
887                 }
888                 break;
889         // Done by the raw callback:
890         //  case FL_KEYBOARD: WorkAreaKeyPress(ob, 0, 0, 0, ev, 0); break;
891         case FL_FOCUS:
892                 if (!view->owner_->getMiniBuffer()->shows_no_match)
893                         view->owner_->getMiniBuffer()->Init();
894                 view->owner_->getMiniBuffer()->shows_no_match = false;
895                 view->work_area_focus = true;
896                 fl_set_timer(view->timer_cursor, 0.4);
897                 break;
898         case FL_UNFOCUS:
899                 view->owner_->getMiniBuffer()->ExecCommand();
900                 view->work_area_focus = false;
901                 break;
902         case FL_ENTER:
903                 SetXtermCursor(view->owner_->getForm()->window);
904                 // reset the timer
905                 view->lyx_focus = true;
906                 fl_set_timer(view->timer_cursor, 0.4);
907                 break;
908         case FL_LEAVE: 
909                 if (!input_prohibited)
910                         XUndefineCursor(fl_display,
911                                         view->owner_->getForm()->window);
912                 view->lyx_focus = false; // This is not an absolute truth
913                 // but if it is not true, it will be changed within a blink
914                 // of an eye. ... Not good enough... use regulare timeperiod
915                 //fl_set_timer(view->timer_cursor, 0.01); // 0.1 sec blink
916                 fl_set_timer(view->timer_cursor, 0.4); // 0.4 sec blink
917                 break;
918         case FL_DBLCLICK: 
919                 // select a word 
920                 if (view->buffer_ && !view->buffer_->the_locking_inset) {
921                         if (view->screen && ev->xbutton.button == 1) {
922                                 view->screen->HideCursor();
923                                 view->screen->ToggleSelection();
924 #ifdef MOVE_TEXT
925                                 view->text->SelectWord();
926 #else
927                                 view->buffer_->text->SelectWord();
928 #endif
929                                 view->screen->ToggleSelection(false);
930                                 /* This will fit the cursor on the screen
931                                  * if necessary */
932 #ifdef MOVE_TEXT
933                                 view->update(0);
934 #else
935                                 view->buffer_->update(0);
936 #endif
937                         }
938                 }
939                 break;
940         case FL_TRPLCLICK:
941                 // select a line
942                 if (view->buffer_ && view->screen && ev->xbutton.button == 1) {
943                         view->screen->HideCursor(); 
944                         view->screen->ToggleSelection();
945 #ifdef MOVE_TEXT
946                         view->text->CursorHome();
947                         view->text->sel_cursor = view->text->cursor;
948                         view->text->CursorEnd();
949                         view->text->SetSelection();
950 #else
951                         view->buffer_->text->CursorHome();
952                         view->buffer_->text->sel_cursor = 
953                                 view->buffer_->text->cursor;
954                         view->buffer_->text->CursorEnd();
955                         view->buffer_->text->SetSelection();
956 #endif
957                         view->screen->ToggleSelection(false); 
958                         /* This will fit the cursor on the screen
959                          * if necessary */
960 #ifdef MOVE_TEXT
961                         view->update(0);
962 #else
963                         view->buffer_->update(0);
964 #endif
965                 }
966                 break;
967         case FL_OTHER:
968                 view->WorkAreaSelectionNotify(ob,
969                                               view->owner_->getForm()->window,
970                                               0, 0, ev, 0); 
971                 break;
972         }
973         return 1;
974 }
975
976 int BufferView::WorkAreaMotionNotify(FL_OBJECT *ob, Window,
977                                      int /*w*/, int /*h*/,
978                                      XEvent *ev, void */*d*/)
979 {
980
981         if (buffer_ == 0) return 0;
982         if (!screen) return 0;
983
984         // Check for inset locking
985         if (buffer_->the_locking_inset) {
986 #ifdef MOVE_TEXT
987                 LyXCursor cursor = text->cursor;
988 #else
989                 LyXCursor cursor = buffer_->text->cursor;
990 #endif
991                 buffer_->the_locking_inset->
992                         InsetMotionNotify(ev->xbutton.x - ob->x - cursor.x,
993                                           ev->xbutton.y - ob->y -
994                                           (cursor.y),
995                                           ev->xbutton.state);
996                 return 0;
997         }
998    
999         // Only use motion with button 1
1000         if (!ev->xmotion.state & Button1MotionMask)
1001                 return 0; 
1002    
1003         /* The selection possible is needed, that only motion events are 
1004          * used, where the bottom press event was on the drawing area too */
1005         if (selection_possible) {
1006                 screen->HideCursor();
1007
1008 #ifdef MOVE_TEXT
1009                 text->SetCursorFromCoordinates(ev->xbutton.x - ob->x,
1010                                                ev->xbutton.y - ob->y +
1011                                                screen->first);
1012       
1013                 if (!text->selection)
1014                         update(-3); // Maybe an empty line was deleted
1015       
1016                 text->SetSelection();
1017 #else
1018                 buffer_->text->
1019                         SetCursorFromCoordinates(ev->xbutton.x - ob->x,
1020                                                  ev->xbutton.y - ob->y +
1021                                                  screen->first);
1022       
1023                 if (!buffer_->text->selection)
1024                     buffer_->update(-3); // Maybe an empty line was deleted
1025       
1026                 buffer_->text->SetSelection();
1027 #endif
1028                 screen->ToggleToggle();
1029                 if (screen->FitCursor())
1030                         updateScrollbar(); 
1031                 screen->ShowCursor();
1032         }
1033         return 0;
1034 }
1035
1036
1037 extern int bibitemMaxWidth(LyXFont const &);
1038
1039 #ifdef MOVE_TEXT
1040 // Single-click on work area
1041 int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
1042                         int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1043 {
1044         last_click_x = -1;
1045         last_click_y = -1;
1046
1047         if (buffer_ == 0) return 0;
1048         if (!screen) return 0;
1049
1050         int const x = ev->xbutton.x - ob->x;
1051         int const y = ev->xbutton.y - ob->y;
1052         // If we hit an inset, we have the inset coordinates in these
1053         // and inset_hit points to the inset.  If we do not hit an
1054         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1055         int inset_x = x;
1056         int inset_y = y;
1057         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1058
1059         // ok ok, this is a hack.
1060         int button = ev->xbutton.button;
1061         if (button == 4 || button == 5) goto wheel;
1062
1063         {
1064                 
1065         if (buffer_->the_locking_inset) {
1066                 // We are in inset locking mode
1067                 
1068                 /* Check whether the inset was hit. If not reset mode,
1069                    otherwise give the event to the inset */
1070                 if (inset_hit != 0) {
1071                         buffer_->the_locking_inset->
1072                                 InsetButtonPress(inset_x, inset_y, button);
1073                         return 0;
1074                 } else {
1075                         UnlockInset(buffer_->the_locking_inset);
1076                 }
1077         }
1078         
1079         selection_possible = true;
1080         screen->HideCursor();
1081         
1082         // Right button mouse click on a table
1083         if (button == 3 &&
1084             (text->cursor.par->table ||
1085              text->MouseHitInTable(x, y + screen->first))) {
1086                 // Set the cursor to the press-position
1087                 text->SetCursorFromCoordinates(x, y + screen->first);
1088                 bool doit = true;
1089                 
1090                 // Only show the table popup if the hit is in the table, too
1091                 if (!text->HitInTable(text->cursor.row, x))
1092                         doit = false;
1093                 
1094                 // Hit above or below the table?
1095                 if (doit) {
1096                         if (!text->selection) {
1097                                 screen->ToggleSelection();
1098                                 text->ClearSelection();
1099                                 text->FullRebreak();
1100                                 screen->Update();
1101                                 updateScrollbar();
1102                         }
1103                         // Popup table popup when on a table.
1104                         // This is obviously temporary, since we should be
1105                         // able to 
1106                         // popup various context-sensitive-menus with the
1107                         // the right mouse. So this should be done more
1108                         // general in the future. Matthias.
1109                         selection_possible = false;
1110                         owner_->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
1111                                                        "true");
1112                         return 0;
1113                 }
1114         }
1115         
1116         int screen_first = screen->first;
1117         
1118         // Middle button press pastes if we have a selection
1119         bool paste_internally = false;
1120         if (button == 2  // && !buffer_->the_locking_inset
1121             && text->selection) {
1122                 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
1123                 paste_internally = true;
1124         }
1125         
1126         // Clear the selection
1127         screen->ToggleSelection();
1128         text->ClearSelection();
1129         text->FullRebreak();
1130         screen->Update();
1131         updateScrollbar();
1132                 
1133         // Single left click in math inset?
1134         if (inset_hit != 0 && inset_hit->Editable() == 2) {
1135                 // Highly editable inset, like math
1136                 selection_possible = false;
1137                 owner_->updateLayoutChoice();
1138                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1139                 inset_hit->Edit(inset_x, inset_y);
1140                 return 0;
1141         } 
1142
1143         // Right click on a footnote flag opens float menu
1144         if (button == 3) { 
1145                 selection_possible = false;
1146                 return 0;
1147         }
1148         
1149         text->SetCursorFromCoordinates(x, y + screen_first);
1150         text->FinishUndo();
1151         text->sel_cursor = text->cursor;
1152         text->cursor.x_fix = text->cursor.x;
1153         
1154         owner_->updateLayoutChoice();
1155         if (screen->FitCursor()){
1156                 updateScrollbar();
1157                 selection_possible = false;
1158         }
1159
1160         // Insert primary selection with middle mouse
1161         // if there is a local selection in the current buffer, insert this
1162         if (button == 2) { //  && !buffer_->the_locking_inset){
1163                 if (paste_internally)
1164                         owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
1165                 else
1166                         owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
1167                                                        "paragraph");
1168                 selection_possible = false;
1169                 return 0;
1170         }
1171         }
1172         goto out;
1173  wheel: {
1174         // I am not quite sure if this is the correct place to put this,
1175         // but it will not cause any harm.
1176         // Patch from Mark Huang (markman@mit.edu) to make LyX recognise
1177         // button 4 and 5. This enables LyX use use the scrollwhell on
1178         // certain mice for something useful. (Lgb)
1179         // Added wheel acceleration detection code. (Rvdk)
1180         static Time lastTime = 0;
1181         int diff = ev->xbutton.time - lastTime;
1182         int scroll = int(1.0 + (4.0/(abs(diff)+1.0))*200.0);
1183         switch (button) {
1184         case 4:
1185                 ScrollUp(scroll);
1186                 break;
1187         case 5:
1188                 ScrollDown(scroll);
1189                 break;
1190         }
1191         lastTime = ev->xbutton.time;
1192         return 0;
1193         }
1194  out:
1195         last_click_x = x;
1196         last_click_y = y;
1197         
1198         return 0;
1199 }
1200 #else
1201 // Single-click on work area
1202 int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
1203                         int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1204 {
1205         last_click_x = -1;
1206         last_click_y = -1;
1207
1208         if (buffer_ == 0) return 0;
1209         if (!screen) return 0;
1210
1211         int const x = ev->xbutton.x - ob->x;
1212         int const y = ev->xbutton.y - ob->y;
1213         // If we hit an inset, we have the inset coordinates in these
1214         // and inset_hit points to the inset.  If we do not hit an
1215         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1216         int inset_x = x;
1217         int inset_y = y;
1218         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1219
1220         // ok ok, this is a hack.
1221         int button = ev->xbutton.button;
1222         if (button == 4 || button == 5) goto wheel;
1223
1224         {
1225                 
1226         if (buffer_->the_locking_inset) {
1227                 // We are in inset locking mode
1228                 
1229                 /* Check whether the inset was hit. If not reset mode,
1230                    otherwise give the event to the inset */
1231                 if (inset_hit != 0) {
1232                         buffer_->the_locking_inset->
1233                                 InsetButtonPress(inset_x, inset_y, button);
1234                         return 0;
1235                 } else {
1236                         UnlockInset(buffer_->the_locking_inset);
1237                 }
1238         }
1239         
1240         selection_possible = true;
1241         screen->HideCursor();
1242         
1243         // Right button mouse click on a table
1244         if (button == 3 &&
1245             (buffer_->text->cursor.par->table ||
1246              buffer_->text->MouseHitInTable(x, y+screen->first))) {
1247                 // Set the cursor to the press-position
1248                 buffer_->text->SetCursorFromCoordinates(x, y + screen->first);
1249                 bool doit = true;
1250                 
1251                 // Only show the table popup if the hit is in the table, too
1252                 if (!buffer_->text->HitInTable(buffer_->text->cursor.row, x))
1253                         doit = false;
1254                 
1255                 // Hit above or below the table?
1256                 if (doit) {
1257                         if (!buffer_->text->selection) {
1258                                 screen->ToggleSelection();
1259                                 buffer_->text->ClearSelection();
1260                                 buffer_->text->FullRebreak();
1261                                 screen->Update();
1262                                 updateScrollbar();
1263                         }
1264                         // Popup table popup when on a table.
1265                         // This is obviously temporary, since we should be
1266                         // able to 
1267                         // popup various context-sensitive-menus with the
1268                         // the right mouse. So this should be done more
1269                         // general in the future. Matthias.
1270                         selection_possible = false;
1271                         owner_->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
1272                                                        "true");
1273                         return 0;
1274                 }
1275         }
1276         
1277         int screen_first = screen->first;
1278         
1279         // Middle button press pastes if we have a selection
1280         bool paste_internally = false;
1281         if (button == 2  // && !buffer_->the_locking_inset
1282             && buffer_->text->selection) {
1283                 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
1284                 paste_internally = true;
1285         }
1286         
1287         // Clear the selection
1288         screen->ToggleSelection();
1289         buffer_->text->ClearSelection();
1290         buffer_->text->FullRebreak();
1291         screen->Update();
1292         updateScrollbar();
1293                 
1294         // Single left click in math inset?
1295         if (inset_hit != 0 && inset_hit->Editable() == 2) {
1296                 // Highly editable inset, like math
1297                 selection_possible = false;
1298                 owner_->updateLayoutChoice();
1299                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1300                 inset_hit->Edit(inset_x, inset_y);
1301                 return 0;
1302         } 
1303
1304         // Right click on a footnote flag opens float menu
1305         if (button == 3) { 
1306                 selection_possible = false;
1307                 return 0;
1308         }
1309         
1310         buffer_->text->SetCursorFromCoordinates(x, y + screen_first);
1311         buffer_->text->FinishUndo();
1312         buffer_->text->sel_cursor = buffer_->text->cursor;
1313         buffer_->text->cursor.x_fix = buffer_->text->cursor.x;
1314         
1315         owner_->updateLayoutChoice();
1316         if (screen->FitCursor()){
1317                 updateScrollbar();
1318                 selection_possible = false;
1319         }
1320
1321         // Insert primary selection with middle mouse
1322         // if there is a local selection in the current buffer, insert this
1323         if (button == 2) { //  && !buffer_->the_locking_inset){
1324                 if (paste_internally)
1325                         owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
1326                 else
1327                         owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
1328                                                        "paragraph");
1329                 selection_possible = false;
1330                 return 0;
1331         }
1332         }
1333         goto out;
1334  wheel: {
1335         // I am not quite sure if this is the correct place to put this,
1336         // but it will not cause any harm.
1337         // Patch from Mark Huang (markman@mit.edu) to make LyX recognise
1338         // button 4 and 5. This enables LyX use use the scrollwhell on
1339         // certain mice for something useful. (Lgb)
1340         // Added wheel acceleration detection code. (Rvdk)
1341         static Time lastTime = 0;
1342         int diff = ev->xbutton.time - lastTime;
1343         int scroll = int(1.0 + (4.0/(abs(diff)+1.0))*200.0);
1344         switch (button) {
1345         case 4:
1346                 ScrollUp(scroll);
1347                 break;
1348         case 5:
1349                 ScrollDown(scroll);
1350                 break;
1351         }
1352         lastTime = ev->xbutton.time;
1353         return 0;
1354         }
1355  out:
1356         last_click_x = x;
1357         last_click_y = y;
1358         
1359         return 0;
1360 }
1361 #endif
1362
1363 #ifdef MOVE_TEXT
1364 int BufferView::WorkAreaButtonRelease(FL_OBJECT * ob, Window ,
1365                           int /*w*/, int /*h*/, XEvent * ev, void * /*d*/)
1366 {
1367         if (buffer_ == 0 || screen == 0) return 0;
1368
1369         int const x = ev->xbutton.x - ob->x;
1370         int const y = ev->xbutton.y - ob->y;
1371
1372         // If we hit an inset, we have the inset coordinates in these
1373         // and inset_hit points to the inset.  If we do not hit an
1374         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1375         int inset_x = x;
1376         int inset_y = y;
1377         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1378
1379         if (buffer_->the_locking_inset) {
1380                 // We are in inset locking mode.
1381
1382                 /* LyX does a kind of work-area grabbing for insets.
1383                    Only a ButtonPress Event outside the inset will 
1384                    force a InsetUnlock. */
1385                 buffer_->the_locking_inset->
1386                         InsetButtonRelease(inset_x, inset_y, 
1387                                            ev->xbutton.button);
1388                 return 0;
1389         }
1390   
1391         selection_possible = false;
1392         if (text->cursor.par->table) {
1393                 int cell = text->
1394                         NumberOfCell(text->cursor.par,
1395                                      text->cursor.pos);
1396                 if (text->cursor.par->table->IsContRow(cell) &&
1397                     text->cursor.par->table->
1398                     CellHasContRow(text->cursor.par->table->
1399                                    GetCellAbove(cell))<0) {
1400                         text->CursorUp();
1401                 }
1402         }
1403         
1404         if (ev->xbutton.button >= 2)
1405                 return 0;
1406
1407         // Make sure that the press was not far from the release
1408         if ((abs(last_click_x - x) >= 5) ||
1409             (abs(last_click_y - y) >= 5)) {
1410                 return 0;
1411         }
1412
1413         // Did we hit an editable inset?
1414         if (inset_hit != 0) {
1415                 // Inset like error, notes and figures
1416                 selection_possible = false;
1417 #ifdef WITH_WARNINGS
1418 #warning fix this proper in 0.13
1419 #endif
1420                 // Following a ref shouldn't issue
1421                 // a push on the undo-stack
1422                 // anylonger, now that we have
1423                 // keybindings for following
1424                 // references and returning from
1425                 // references.  IMHO though, it
1426                 // should be the inset's own business
1427                 // to push or not push on the undo
1428                 // stack. They don't *have* to
1429                 // alter the document...
1430                 // (Joacim)
1431                 // ...or maybe the SetCursorParUndo()
1432                 // below isn't necessary at all anylonger?
1433                 if (inset_hit->LyxCode() == Inset::REF_CODE) {
1434                         text->SetCursorParUndo();
1435                 }
1436
1437                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1438                 inset_hit->Edit(inset_x, inset_y);
1439                 return 0;
1440         }
1441
1442         // check whether we want to open a float
1443         if (text) {
1444                 bool hit = false;
1445                 char c = ' ';
1446                 if (text->cursor.pos <
1447                     text->cursor.par->Last()) {
1448                         c = text->cursor.par->
1449                                 GetChar(text->cursor.pos);
1450                 }
1451                 if (c == LyXParagraph::META_FOOTNOTE
1452                     || c == LyXParagraph::META_MARGIN
1453                     || c == LyXParagraph::META_FIG
1454                     || c == LyXParagraph::META_TAB
1455                     || c == LyXParagraph::META_WIDE_FIG
1456                     || c == LyXParagraph::META_WIDE_TAB
1457                     || c == LyXParagraph::META_ALGORITHM){
1458                         hit = true;
1459                 } else if (text->cursor.pos - 1 >= 0) {
1460                         c = text->cursor.par->
1461                                 GetChar(text->cursor.pos - 1);
1462                         if (c == LyXParagraph::META_FOOTNOTE
1463                             || c == LyXParagraph::META_MARGIN
1464                             || c == LyXParagraph::META_FIG
1465                             || c == LyXParagraph::META_TAB
1466                             || c == LyXParagraph::META_WIDE_FIG 
1467                             || c == LyXParagraph::META_WIDE_TAB
1468                             || c == LyXParagraph::META_ALGORITHM){
1469                                 // We are one step too far to the right
1470                                 text->CursorLeft();
1471                                 hit = true;
1472                         }
1473                 }
1474                 if (hit == true) {
1475                         ToggleFloat();
1476                         selection_possible = false;
1477                         return 0;
1478                 }
1479         }
1480
1481         // Do we want to close a float? (click on the float-label)
1482         if (text->cursor.row->par->footnoteflag == 
1483             LyXParagraph::OPEN_FOOTNOTE
1484             && text->cursor.pos == 0
1485             && text->cursor.row->previous &&
1486             text->cursor.row->previous->par->
1487             footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
1488                 LyXFont font (LyXFont::ALL_SANE);
1489                 font.setSize(LyXFont::SIZE_SMALL);
1490
1491                 int box_x = 20; // LYX_PAPER_MARGIN;
1492                 box_x += font.textWidth("Mwide-figM", 10);
1493
1494                 int screen_first = screen->first;
1495
1496                 if (x < box_x
1497                     && y + screen_first > text->cursor.y -
1498                     text->cursor.row->baseline
1499                     && y + screen_first < text->cursor.y -
1500                     text->cursor.row->baseline
1501                     + font.maxAscent()*1.2 + font.maxDescent()*1.2) {
1502                         ToggleFloat();
1503                         selection_possible = false;
1504                         return 0;
1505                 }
1506         }
1507
1508         // Maybe we want to edit a bibitem ale970302
1509         if (text->cursor.par->bibkey && x < 20 + 
1510             bibitemMaxWidth(textclasslist.TextClass(buffer_->
1511                                         params.textclass).defaultfont())) {
1512                 text->cursor.par->bibkey->Edit(0, 0);
1513         }
1514
1515         return 0;
1516 }
1517 #else
1518 int BufferView::WorkAreaButtonRelease(FL_OBJECT *ob, Window ,
1519                           int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1520 {
1521         if (buffer_ == 0 || screen == 0) return 0;
1522
1523         int const x = ev->xbutton.x - ob->x;
1524         int const y = ev->xbutton.y - ob->y;
1525
1526         // If we hit an inset, we have the inset coordinates in these
1527         // and inset_hit points to the inset.  If we do not hit an
1528         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1529         int inset_x = x;
1530         int inset_y = y;
1531         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1532
1533         if (buffer_->the_locking_inset) {
1534                 // We are in inset locking mode.
1535
1536                 /* LyX does a kind of work-area grabbing for insets.
1537                    Only a ButtonPress Event outside the inset will 
1538                    force a InsetUnlock. */
1539                 buffer_->the_locking_inset->
1540                         InsetButtonRelease(inset_x, inset_y, 
1541                                            ev->xbutton.button);
1542                 return 0;
1543         }
1544   
1545         selection_possible = false;
1546         if (buffer_->text->cursor.par->table) {
1547                 int cell = buffer_->text->
1548                         NumberOfCell(buffer_->text->cursor.par,
1549                                      buffer_->text->cursor.pos);
1550                 if (buffer_->text->cursor.par->table->IsContRow(cell) &&
1551                     buffer_->text->cursor.par->table->
1552                     CellHasContRow(buffer_->text->cursor.par->table->
1553                                    GetCellAbove(cell))<0) {
1554                         buffer_->text->CursorUp();
1555                 }
1556         }
1557         
1558         if (ev->xbutton.button >= 2)
1559                 return 0;
1560
1561         // Make sure that the press was not far from the release
1562         if ((abs(last_click_x - x) >= 5) ||
1563             (abs(last_click_y - y) >= 5)) {
1564                 return 0;
1565         }
1566
1567         // Did we hit an editable inset?
1568         if (inset_hit != 0) {
1569                 // Inset like error, notes and figures
1570                 selection_possible = false;
1571 #ifdef WITH_WARNINGS
1572 #warning fix this proper in 0.13
1573 #endif
1574                 // Following a ref shouldn't issue
1575                 // a push on the undo-stack
1576                 // anylonger, now that we have
1577                 // keybindings for following
1578                 // references and returning from
1579                 // references.  IMHO though, it
1580                 // should be the inset's own business
1581                 // to push or not push on the undo
1582                 // stack. They don't *have* to
1583                 // alter the document...
1584                 // (Joacim)
1585                 // ...or maybe the SetCursorParUndo()
1586                 // below isn't necessary at all anylonger?
1587                 if (inset_hit->LyxCode() == Inset::REF_CODE) {
1588                         buffer_->text->SetCursorParUndo();
1589                 }
1590
1591                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1592                 inset_hit->Edit(inset_x, inset_y);
1593                 return 0;
1594         }
1595
1596         // check whether we want to open a float
1597         if (buffer_->text) {
1598                 bool hit = false;
1599                 char c = ' ';
1600                 if (buffer_->text->cursor.pos <
1601                     buffer_->text->cursor.par->Last()) {
1602                         c = buffer_->text->cursor.par->
1603                                 GetChar(buffer_->text->cursor.pos);
1604                 }
1605                 if (c == LyXParagraph::META_FOOTNOTE
1606                     || c == LyXParagraph::META_MARGIN
1607                     || c == LyXParagraph::META_FIG
1608                     || c == LyXParagraph::META_TAB
1609                     || c == LyXParagraph::META_WIDE_FIG
1610                     || c == LyXParagraph::META_WIDE_TAB
1611                     || c == LyXParagraph::META_ALGORITHM){
1612                         hit = true;
1613                 } else if (buffer_->text->cursor.pos - 1 >= 0) {
1614                         c = buffer_->text->cursor.par->
1615                                 GetChar(buffer_->text->cursor.pos - 1);
1616                         if (c == LyXParagraph::META_FOOTNOTE
1617                             || c == LyXParagraph::META_MARGIN
1618                             || c == LyXParagraph::META_FIG
1619                             || c == LyXParagraph::META_TAB
1620                             || c == LyXParagraph::META_WIDE_FIG 
1621                             || c == LyXParagraph::META_WIDE_TAB
1622                             || c == LyXParagraph::META_ALGORITHM){
1623                                 // We are one step too far to the right
1624                                 buffer_->text->CursorLeft();
1625                                 hit = true;
1626                         }
1627                 }
1628                 if (hit == true) {
1629                         ToggleFloat();
1630                         selection_possible = false;
1631                         return 0;
1632                 }
1633         }
1634
1635         // Do we want to close a float? (click on the float-label)
1636         if (buffer_->text->cursor.row->par->footnoteflag == 
1637             LyXParagraph::OPEN_FOOTNOTE
1638             && buffer_->text->cursor.pos == 0
1639             && buffer_->text->cursor.row->previous &&
1640             buffer_->text->cursor.row->previous->par->
1641             footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
1642                 LyXFont font (LyXFont::ALL_SANE);
1643                 font.setSize(LyXFont::SIZE_SMALL);
1644
1645                 int box_x = 20; // LYX_PAPER_MARGIN;
1646                 box_x += font.textWidth("Mwide-figM", 10);
1647
1648                 int screen_first = screen->first;
1649
1650                 if (x < box_x
1651                     && y + screen_first > buffer_->text->cursor.y -
1652                     buffer_->text->cursor.row->baseline
1653                     && y + screen_first < buffer_->text->cursor.y -
1654                     buffer_->text->cursor.row->baseline
1655                     + font.maxAscent()*1.2 + font.maxDescent()*1.2) {
1656                         ToggleFloat();
1657                         selection_possible = false;
1658                         return 0;
1659                 }
1660         }
1661
1662         // Maybe we want to edit a bibitem ale970302
1663         if (buffer_->text->cursor.par->bibkey && x < 20 + 
1664             bibitemMaxWidth(textclasslist.TextClass(buffer_->
1665                                         params.textclass).defaultfont())) {
1666                 buffer_->text->cursor.par->bibkey->Edit(0, 0);
1667         }
1668
1669         return 0;
1670 }
1671 #endif
1672
1673 /* 
1674  * Returns an inset if inset was hit. 0 otherwise.
1675  * If hit, the coordinates are changed relative to the inset. 
1676  * Otherwise coordinates are not changed, and false is returned.
1677  */
1678 #ifdef MOVE_TEXT
1679 Inset * BufferView::checkInsetHit(int & x, int & y)
1680 {
1681         if (!getScreen())
1682                 return 0;
1683   
1684         int y_tmp = y + getScreen()->first;
1685   
1686         LyXCursor cursor = text->cursor;
1687         if (cursor.pos < cursor.par->Last() 
1688             && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
1689             && cursor.par->GetInset(cursor.pos)
1690             && cursor.par->GetInset(cursor.pos)->Editable()) {
1691
1692                 // Check whether the inset really was hit
1693                 Inset * tmpinset = cursor.par->GetInset(cursor.pos);
1694                 LyXFont font = text->GetFont(cursor.par, cursor.pos);
1695                 if (x > cursor.x
1696                     && x < cursor.x + tmpinset->Width(font) 
1697                     && y_tmp > cursor.y - tmpinset->Ascent(font)
1698                     && y_tmp < cursor.y + tmpinset->Descent(font)) {
1699                         x = x - cursor.x;
1700                         // The origin of an inset is on the baseline
1701                         y = y_tmp - (cursor.y); 
1702                         return tmpinset;
1703                 }
1704         } else if (cursor.pos - 1 >= 0 
1705                    && cursor.par->GetChar(cursor.pos - 1) == LyXParagraph::META_INSET
1706                    && cursor.par->GetInset(cursor.pos - 1)
1707                    && cursor.par->GetInset(cursor.pos - 1)->Editable()) {
1708                 text->CursorLeft();
1709                 Inset * result = checkInsetHit(x, y);
1710                 if (result == 0) {
1711                         text->CursorRight();
1712                         return 0;
1713                 } else {
1714                         return result;
1715                 }
1716         }
1717         return 0;
1718 }
1719 #else
1720 Inset * BufferView::checkInsetHit(int & x, int & y)
1721 {
1722         if (!getScreen())
1723                 return 0;
1724   
1725         int y_tmp = y + getScreen()->first;
1726   
1727         LyXCursor cursor = buffer_->text->cursor;
1728         if (cursor.pos < cursor.par->Last() 
1729             && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
1730             && cursor.par->GetInset(cursor.pos)
1731             && cursor.par->GetInset(cursor.pos)->Editable()) {
1732
1733                 // Check whether the inset really was hit
1734                 Inset * tmpinset = cursor.par->GetInset(cursor.pos);
1735                 LyXFont font = buffer_->text->GetFont(cursor.par, cursor.pos);
1736                 if (x > cursor.x
1737                     && x < cursor.x + tmpinset->Width(font) 
1738                     && y_tmp > cursor.y - tmpinset->Ascent(font)
1739                     && y_tmp < cursor.y + tmpinset->Descent(font)) {
1740                         x = x - cursor.x;
1741                         // The origin of an inset is on the baseline
1742                         y = y_tmp - (cursor.y); 
1743                         return tmpinset;
1744                 }
1745         } else if (cursor.pos - 1 >= 0 
1746                    && cursor.par->GetChar(cursor.pos - 1) == LyXParagraph::META_INSET
1747                    && cursor.par->GetInset(cursor.pos - 1)
1748                    && cursor.par->GetInset(cursor.pos - 1)->Editable()) {
1749                 buffer_->text->CursorLeft();
1750                 Inset * result = checkInsetHit(x, y);
1751                 if (result == 0) {
1752                         buffer_->text->CursorRight();
1753                         return 0;
1754                 } else {
1755                         return result;
1756                 }
1757         }
1758         return 0;
1759 }
1760 #endif
1761
1762 int BufferView::workAreaExpose()
1763 {
1764         if (!work_area || !work_area->form->visible) 
1765                 return 1;
1766
1767         // this is a hack to ensure that we only call this through
1768         // BufferView::redraw().
1769         if (!lgb_hack) {
1770                 redraw();
1771         }
1772         
1773         static int work_area_width = work_area->w;
1774         static int work_area_height = work_area->h;
1775
1776         bool widthChange = work_area->w != work_area_width;
1777         bool heightChange = work_area->h != work_area_height;
1778
1779         // update from work area
1780         work_area_width = work_area->w;
1781         work_area_height = work_area->h;
1782         if (buffer_ != 0) {
1783                 if (widthChange) {
1784                         // All buffers need a resize
1785                         bufferlist.resize();
1786                 } else if (heightChange) {
1787                         // Rebuild image of current screen
1788                         updateScreen();
1789                         // fitCursor() ensures we don't jump back
1790                         // to the start of the document on vertical
1791                         // resize
1792                         fitCursor();
1793
1794                         // The main window size has changed, repaint most stuff
1795                         redraw();
1796                         // ...including the minibuffer
1797                         owner_->getMiniBuffer()->Init();
1798
1799                 } else if (screen) screen->Redraw();
1800         } else {
1801                 // Grey box when we don't have a buffer
1802                 fl_winset(FL_ObjWin(work_area));
1803                 fl_rectangle(1, work_area->x, work_area->y,
1804                              work_area->w, work_area->h, FL_GRAY63);
1805         }
1806
1807         // always make sure that the scrollbar is sane.
1808         updateScrollbar();
1809         owner_->updateLayoutChoice();
1810         return 1;
1811 }
1812
1813
1814 // Callback for cursor timer
1815 void BufferView::CursorToggleCB(FL_OBJECT * ob, long)
1816 {
1817         BufferView *view = static_cast<BufferView*>(ob->u_vdata);
1818         
1819         /* quite a nice place for asyncron Inset updating, isn't it? */
1820         // actually no! This is run even if no buffer exist... so (Lgb)
1821         if (view && !view->buffer_) {
1822                 goto set_timer_and_return;
1823         }
1824
1825         // NOTE:
1826         // On my quest to solve the gs rendre hangups I am now
1827         // disabling the SIGHUP completely, and will do a wait
1828         // now and then instead. If the guess that xforms somehow
1829         // destroys something is true, this is likely (hopefully)
1830         // to solve the problem...at least I hope so. Lgb
1831
1832         // ...Ok this seems to work...at least it does not make things
1833         // worse so far. However I still see gs processes that hangs.
1834         // I would really like to know _why_ they are hanging. Anyway
1835         // the solution without the SIGCHLD handler seems to be easier
1836         // to debug.
1837
1838         // When attaching gdb to a a running gs that hangs it shows
1839         // that it is waiting for input(?) Is it possible for us to
1840         // provide that input somehow? Or figure what it is expecing
1841         // to read?
1842
1843         // One solution is to, after some time, look if there are some
1844         // old gs processes still running and if there are: kill them
1845         // and re render.
1846
1847         // Another solution is to provide the user an option to rerender
1848         // a picture. This would, for the picture in question, check if
1849         // there is a gs running for it, if so kill it, and start a new
1850         // rendering process.
1851
1852         // these comments posted to lyx@via
1853         {
1854         int status = 1;
1855         int pid = waitpid((pid_t)0, &status, WNOHANG);
1856         if (pid == -1) // error find out what is wrong
1857                 ; // ignore it for now.
1858         else if (pid > 0)
1859                 sigchldhandler(pid, &status);
1860         }
1861         if (InsetUpdateList) 
1862                 UpdateInsetUpdateList();
1863
1864         if (view && !view->screen){
1865                 goto set_timer_and_return;
1866         }
1867
1868         if (view->lyx_focus && view->work_area_focus) {
1869                 if (!view->buffer_->the_locking_inset){
1870                         view->screen->CursorToggle();
1871                 } else {
1872                         view->buffer_->the_locking_inset->
1873                                 ToggleInsetCursor();
1874                 }
1875                 goto set_timer_and_return;
1876         } else {
1877                 // Make sure that the cursor is visible.
1878                 if (!view->buffer_->the_locking_inset){
1879                         view->screen->ShowCursor();
1880                 } else {
1881                         if (!view->buffer_->the_locking_inset->isCursorVisible())
1882                                 view->buffer_->the_locking_inset->
1883                                         ToggleInsetCursor();
1884                 }
1885
1886                 // This is only run when work_area_focus or lyx_focus is false.
1887                 Window tmpwin;
1888                 int tmp;
1889                 XGetInputFocus(fl_display, &tmpwin, &tmp);
1890                 if (lyxerr.debugging()) {
1891                         lyxerr << "tmpwin: " << tmpwin
1892                                << "\nwindow: " << view->owner_->getForm()->window
1893                                << "\nwork_area_focus: " << view->work_area_focus
1894                                << "\nlyx_focus      : " << view->lyx_focus
1895                                << endl;
1896                 }
1897                 if (tmpwin != view->owner_->getForm()->window) {
1898                         view->lyx_focus = false;
1899                         goto skip_timer;
1900                 } else {
1901                         view->lyx_focus = true;
1902                         if (!view->work_area_focus)
1903                                 goto skip_timer;
1904                         else
1905                                 goto set_timer_and_return;
1906                 }
1907         }
1908
1909   set_timer_and_return:
1910         fl_set_timer(ob, 0.4);
1911   skip_timer:
1912         return;
1913 }
1914
1915
1916 int BufferView::WorkAreaSelectionNotify(FL_OBJECT *, Window win,
1917                             int /*w*/, int /*h*/, XEvent *event, void */*d*/)
1918 {
1919         if (buffer_ == 0) return 0;
1920         if (event->type != SelectionNotify)
1921                 return 0;
1922
1923         Atom tmpatom;
1924         unsigned long ul1;
1925         unsigned long ul2;
1926         unsigned char * uc = 0;
1927         int tmpint;
1928         screen->HideCursor();
1929         BeforeChange();
1930         if (event->xselection.type == XA_STRING
1931             && event->xselection.property) {
1932     
1933                 if (XGetWindowProperty(
1934                         fl_display            /* display */,
1935                         win /* w */,
1936                         event->xselection.property        /* property */,
1937                         0                /* long_offset */,
1938                         0                /* long_length */,
1939                         false                /* delete */,
1940                         XA_STRING                /* req_type */,
1941                         &tmpatom               /* actual_type_return */,
1942                         &tmpint                /* actual_format_return */,
1943                         &ul1      /* nitems_return */,
1944                         &ul2      /* bytes_after_return */,
1945                         &uc     /* prop_return */
1946                         ) != Success) {
1947                         return 0;
1948                 }
1949                 XFlush(fl_display);
1950
1951                 if (uc){
1952                         free(uc);
1953                         uc = 0;
1954                 }
1955
1956                 if (XGetWindowProperty(
1957                         fl_display           /* display */,
1958                         win              /* w */,
1959                         event->xselection.property           /* property */,
1960                         0                /* long_offset */,
1961                         ul2/4+1                /* long_length */,
1962                         True                /* delete */,
1963                         XA_STRING                /* req_type */,
1964                         &tmpatom               /* actual_type_return */,
1965                         &tmpint                /* actual_format_return */,
1966                         &ul1      /* nitems_return */,
1967                         &ul2      /* bytes_after_return */,
1968                         &uc     /* prop_return */
1969                         ) != Success) {
1970                         return 0;
1971                 }
1972                 XFlush(fl_display);
1973         
1974                 if (uc){
1975 #ifdef MOVE_TEXT
1976                         if (!ascii_type) {
1977                                 text->InsertStringA(reinterpret_cast<char*>(uc));
1978                         } else {
1979                                 text->InsertStringB(reinterpret_cast<char*>(uc));
1980                         }
1981 #else
1982                         if (!ascii_type) {
1983                                 buffer_->text->
1984                                         InsertStringA(reinterpret_cast<char*>(uc));
1985                         } else {
1986                                 buffer_->text->
1987                                         InsertStringB(reinterpret_cast<char*>(uc));
1988                         }
1989 #endif
1990                         free(uc);
1991                         uc = 0;
1992                 }
1993
1994 #ifdef MOVE_TEXT
1995                 update(1);
1996 #else
1997                 buffer_->update(1);
1998 #endif
1999         }
2000         return 0;
2001 }
2002
2003
2004 #ifdef MOVE_TEXT
2005 void BufferView::cursorPrevious()
2006 {
2007         if (!text->cursor.row->previous) return;
2008         
2009         long y = getScreen()->first;
2010         Row * cursorrow = text->cursor.row;
2011         text->SetCursorFromCoordinates(text->cursor.x_fix, y);
2012         text->FinishUndo();
2013         // this is to allow jumping over large insets
2014         if ((cursorrow == text->cursor.row))
2015                 text->CursorUp();
2016         
2017         if (text->cursor.row->height < work_area->h)
2018                 getScreen()->Draw(text->cursor.y
2019                                   - text->cursor.row->baseline
2020                                   + text->cursor.row->height
2021                                   - work_area->h +1 );
2022 }
2023
2024
2025 void BufferView::cursorNext()
2026 {
2027         if (!text->cursor.row->next) return;
2028         
2029         long y = getScreen()->first;
2030         text->GetRowNearY(y);
2031         Row * cursorrow = text->cursor.row;
2032         text->SetCursorFromCoordinates(text->cursor.x_fix, y + work_area->h);
2033         text->FinishUndo();
2034         /* this is to allow jumping over large insets */
2035         if ((cursorrow == text->cursor.row))
2036                 text->CursorDown();
2037         
2038         if (text->cursor.row->height < work_area->h)
2039                 getScreen()->Draw(text->cursor.y
2040                                   - text->cursor.row->baseline);
2041 }
2042 #else
2043 void BufferView::cursorPrevious()
2044 {
2045         if (!buffer()->text->cursor.row->previous) return;
2046         
2047         long y = getScreen()->first;
2048         Row * cursorrow = buffer()->text->cursor.row;
2049         buffer()->text->
2050           SetCursorFromCoordinates(buffer()->text->
2051                                    cursor.x_fix,
2052                                    y);
2053         buffer()->text->FinishUndo();
2054         // this is to allow jumping over large insets
2055         if ((cursorrow == buffer()->text->cursor.row))
2056           buffer()->text->CursorUp();
2057         
2058         if (buffer()->text->cursor.row->height < work_area->h)
2059           getScreen()->Draw(buffer()->text->cursor.y
2060                             - buffer()->text->cursor.row->baseline
2061                             + buffer()->text->cursor.row->height
2062                             - work_area->h +1 );
2063 }
2064
2065
2066 void BufferView::cursorNext()
2067 {
2068         if (!buffer()->text->cursor.row->next) return;
2069         
2070         long y = getScreen()->first;
2071         buffer()->text->GetRowNearY(y);
2072         Row * cursorrow = buffer()->text->cursor.row;
2073         buffer()->text->
2074                 SetCursorFromCoordinates(buffer()->text->
2075                                          cursor.x_fix, 
2076                                          y + work_area->h);
2077         buffer()->text->FinishUndo();
2078         /* this is to allow jumping over large insets */
2079         if ((cursorrow == buffer()->text->cursor.row))
2080           buffer()->text->CursorDown();
2081         
2082         if (buffer()->text->cursor.row->height < work_area->h)
2083           getScreen()->Draw(buffer()->text->cursor.y
2084                             - buffer()->text->cursor.row->baseline);
2085 }
2086 #endif
2087
2088 bool BufferView::available() const
2089 {
2090 #ifdef MOVE_TEXT
2091         if (buffer_ && text) return true;
2092 #else
2093         if (buffer_ && buffer_->text) return true;
2094 #endif
2095         return false;
2096 }
2097
2098
2099 void BufferView::savePosition()
2100 {
2101 #ifdef MOVE_TEXT
2102         backstack.push(buffer()->fileName(),
2103                         text->cursor.x,
2104                         text->cursor.y);
2105 #else
2106         backstack.push(buffer()->getFileName(),
2107                         buffer()->text->cursor.x,
2108                         buffer()->text->cursor.y);
2109 #endif
2110 }
2111
2112
2113 void BufferView::restorePosition()
2114 {
2115         if (backstack.empty()) return;
2116         
2117         int  x, y;
2118         string fname = backstack.pop(&x, &y);
2119         
2120         BeforeChange();
2121         Buffer * b = (bufferlist.exists(fname)) ? bufferlist.getBuffer(fname):
2122                 bufferlist.loadLyXFile(fname); // don't ask, just load it
2123         buffer(b);
2124 #ifdef MOVE_TEXT
2125         text->SetCursorFromCoordinates(x, y);
2126         update(0);
2127 #else
2128         buffer()->text->SetCursorFromCoordinates(x, y);
2129         buffer()->update(0);
2130 #endif
2131
2132
2133
2134 #ifdef MOVE_TEXT
2135 // candidate for move to BufferView
2136 void BufferView::update(signed char f)
2137 {
2138         owner()->updateLayoutChoice();
2139
2140         if (!text->selection && f > -3)
2141                 text->sel_cursor = text->cursor;
2142         
2143         FreeUpdateTimer();
2144         text->FullRebreak();
2145
2146         update();
2147
2148         if (f != 3 && f != -3) {
2149                 fitCursor();
2150                 updateScrollbar();
2151         }
2152
2153         if (f == 1 || f == -1) {
2154                 if (buffer()->isLyxClean()) {
2155                         buffer()->markDirty();
2156                         owner()->getMiniBuffer()->setTimer(4);
2157                 } else {
2158                         buffer()->markDirty();
2159                 }
2160         }
2161 }
2162 #endif