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