]> git.lyx.org Git - lyx.git/blob - src/BufferView.C
white-space changes, removed definitions.h several enum changes because of this,...
[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-1999 The LyX Team.
9  *
10  * ====================================================== */
11
12 #include <config.h>
13
14 #include <cstdlib>
15 #include <csignal>
16
17 #include <unistd.h>
18 #include <sys/wait.h>
19
20 #include "support/lstrings.h"
21
22 #ifdef __GNUG__
23 #pragma implementation
24 #endif
25
26 #include "commandtags.h"
27 #include "BufferView.h"
28 #include "bufferlist.h"
29 #include "LyXView.h"
30 #include "lyxfunc.h"
31 #include "insets/lyxinset.h"
32 #include "minibuffer.h"
33 #include "lyxscreen.h"
34 #include "up.xpm"
35 #include "down.xpm"
36 #include "debug.h"
37 #include "lyxdraw.h"
38 #include "lyx_gui_misc.h"
39 #include "BackStack.h"
40 #include "lyxtext.h"
41 #include "lyx_cb.h"
42 #include "gettext.h"
43 #include "layout.h"
44
45 extern BufferList bufferlist;
46 void sigchldhandler(pid_t pid, int *status);
47
48 extern void SetXtermCursor(Window win);
49 extern bool input_prohibited;
50 extern bool selection_possible;
51 extern void BeforeChange();
52 extern char ascii_type;
53 extern int UnlockInset(UpdatableInset* inset);
54 extern void ToggleFloat();
55 extern void MenuPasteSelection(char at);
56 extern InsetUpdateStruct *InsetUpdateList;
57 extern void UpdateInsetUpdateList();
58
59 // This is _very_ temporary
60 FL_OBJECT * figinset_canvas;
61
62 BufferView::BufferView(LyXView *o, int xpos, int ypos,
63                        int width, int height)
64         : owner_(o)
65 {
66         buffer_ = 0;
67         
68         screen = 0;
69         work_area = 0;
70         figinset_canvas = 0;
71         scrollbar = 0;
72         button_down = 0;
73         button_up = 0;
74         timer_cursor = 0;
75         current_scrollbar_value = 0;
76         create_view(xpos, ypos, width, height);
77         // Activate the timer for the cursor 
78         fl_set_timer(timer_cursor, 0.4);
79         fl_set_focus_object(owner_->getForm(), work_area);
80         work_area_focus = true;
81         lyx_focus = false;
82 }
83
84
85 void BufferView::buffer(Buffer *b)
86 {
87         lyxerr[Debug::INFO] << "Setting buffer in BufferView" << endl;
88         if (buffer_) {
89                 buffer_->InsetSleep();
90                 buffer_->delUser(this);
91         }
92
93         // Set current buffer
94         buffer_ = b;
95
96         if (bufferlist.getState() == BufferList::CLOSING) return;
97         
98         // Nuke old image
99         if (screen)
100                 delete screen;
101         screen = 0;
102
103         // If we are closing the buffer, use the first buffer as current
104         if (!buffer_) {
105                 buffer_ = bufferlist.first();
106         }
107
108         if (buffer_) {
109                 lyxerr[Debug::INFO] << "  Buffer addr: " << buffer_ << endl;
110                 buffer_->addUser(this);
111                 owner_->getMenus()->showMenus();
112                 // If we don't have a text object for this, we make one
113                 if (buffer_->text == 0)
114                         resizeCurrentBuffer();
115                 else {
116                         updateScreen();
117                         updateScrollbar();
118                 }
119                 screen->first = screen->TopCursorVisible();
120                 redraw();
121                 updateAllVisibleBufferRelatedPopups();
122                 buffer_->InsetWakeup();
123         } else {
124                 lyxerr[Debug::INFO] << "  No Buffer!" << endl;
125                 owner_->getMenus()->hideMenus();
126                 updateScrollbar();
127                 fl_redraw_object(work_area);
128         }
129         // should update layoutchoice even if we don't have a buffer.
130         owner_->updateLayoutChoice();
131         owner_->getMiniBuffer()->Init();
132         owner_->updateWindowTitle();
133 }
134
135
136 void BufferView::updateScreen()
137 {
138         // Regenerate the screen.
139         if (screen)
140                 delete screen;
141         screen = new LyXScreen(FL_ObjWin(work_area),
142                                work_area->w,
143                                work_area->h,
144                                work_area->x,
145                                work_area->y,
146                                buffer_->text);
147 }
148
149
150 void BufferView::resize()
151 {
152         // This will resize the buffer. (Asger)
153         if (buffer_)
154                 resizeCurrentBuffer();
155 }
156
157
158 static bool lgb_hack = false;
159
160 void BufferView::redraw()
161 {
162         lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
163         lgb_hack = true;
164         fl_redraw_object(work_area);
165         fl_redraw_object(scrollbar);
166         fl_redraw_object(button_down);
167         fl_redraw_object(button_up);
168         lgb_hack = false;
169 }
170
171
172 void BufferView::fitCursor()
173 {
174         if (screen) screen->FitCursor();
175 }
176
177
178 void BufferView::update()
179 {
180         if (screen) screen->Update();
181 }
182
183
184 void BufferView::updateScrollbar()
185 {
186         /* If the text is smaller than the working area, the scrollbar
187          * maximum must be the working area height. No scrolling will 
188          * be possible */
189
190         if (!buffer_) {
191                 fl_set_slider_value(scrollbar, 0);
192                 fl_set_slider_size(scrollbar, scrollbar->h);
193                 return;
194         }
195         
196         static long max2 = 0;
197         static long height2 = 0;
198
199         long cbth = 0;
200         long cbsf = 0;
201
202         if (buffer_->text)
203                 cbth = buffer_->text->height;
204         if (screen)
205                 cbsf = screen->first;
206
207         // check if anything has changed.
208         if (max2 == cbth &&
209             height2 == work_area->h &&
210             current_scrollbar_value == cbsf)
211                 return;       // no
212         
213         max2 = cbth;
214         height2 = work_area->h;
215         current_scrollbar_value = cbsf;
216
217         if (cbth <= height2) { // text is smaller than screen
218                 fl_set_slider_size(scrollbar, scrollbar->h);
219                 return;
220         }
221         
222         long maximum_height = work_area->h * 3/4 + cbth;
223         long value = cbsf;
224
225         // set the scrollbar
226         double hfloat = work_area->h;
227         double maxfloat = maximum_height;
228    
229         fl_set_slider_value(scrollbar, value);
230         fl_set_slider_bounds(scrollbar, 0,
231                              maximum_height - work_area->h);
232 #if FL_REVISION > 85
233         double lineh = buffer_->text->DefaultHeight();
234         fl_set_slider_increment(scrollbar, work_area->h-lineh, lineh);
235 #endif
236         if (maxfloat>0){
237                 if ((hfloat/maxfloat) * float(height2) < 3)
238                         fl_set_slider_size(scrollbar,
239                                            3/float(height2));
240                 else
241                         fl_set_slider_size(scrollbar,
242                                            hfloat/maxfloat);
243         } else
244                 fl_set_slider_size(scrollbar, hfloat);
245         fl_set_slider_precision(scrollbar, 0);
246 }
247
248
249 void BufferView::redoCurrentBuffer()
250 {
251         lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
252         if (buffer_ && buffer_->text) {
253                 resize();
254                 owner_->updateLayoutChoice();
255         }
256 }
257
258
259 int BufferView::resizeCurrentBuffer()
260 {
261         lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
262         
263         LyXParagraph * par = 0;
264         LyXParagraph * selstartpar = 0;
265         LyXParagraph * selendpar = 0;
266         int pos = 0;
267         int selstartpos = 0;
268         int selendpos = 0;
269         int selection = 0;
270         int mark_set = 0;
271
272         ProhibitInput();
273
274         owner_->getMiniBuffer()->Set(_("Formatting document..."));   
275
276         if (buffer_->text) {
277                 par = buffer_->text->cursor.par;
278                 pos = buffer_->text->cursor.pos;
279                 selstartpar = buffer_->text->sel_start_cursor.par;
280                 selstartpos = buffer_->text->sel_start_cursor.pos;
281                 selendpar = buffer_->text->sel_end_cursor.par;
282                 selendpos = buffer_->text->sel_end_cursor.pos;
283                 selection = buffer_->text->selection;
284                 mark_set = buffer_->text->mark_set;
285                 delete buffer_->text;
286         }
287         buffer_->text = new LyXText(work_area->w, buffer_);
288
289         updateScreen();
290    
291         if (par) {
292                 buffer_->text->selection = true;
293                 /* at this point just
294                  * to avoid the Delete-
295                  * Empty-Paragraph
296                  * Mechanism when
297                  * setting the cursor */
298                 buffer_->text->mark_set = mark_set;
299                 if (selection) {
300                         buffer_->text->SetCursor(selstartpar, selstartpos);
301                         buffer_->text->sel_cursor = buffer_->text->cursor;
302                         buffer_->text->SetCursor(selendpar, selendpos);
303                         buffer_->text->SetSelection();
304                         buffer_->text->SetCursor(par, pos);
305                 } else {
306                         buffer_->text->SetCursor(par, pos);
307                         buffer_->text->sel_cursor = buffer_->text->cursor;
308                         buffer_->text->selection = false;
309                 }
310         }
311         screen->first = screen->TopCursorVisible(); /* this will scroll the
312                                                      * screen such that the
313                                                      * cursor becomes
314                                                      * visible */ 
315         updateScrollbar();
316         redraw();
317         owner_->getMiniBuffer()->Init();
318         AllowInput();
319
320         // Now if the title form still exist kill it
321         TimerCB(0, 0);
322
323         return 0;
324 }
325
326
327 void BufferView::gotoError()
328 {
329         if (!screen)
330                 return;
331    
332         screen->HideCursor();
333         BeforeChange();
334         buffer_->update(-2);
335         LyXCursor tmp;
336    
337         if (!buffer_->text->GotoNextError()) {
338                 if (buffer_->text->cursor.pos 
339                     || buffer_->text->cursor.par != 
340                     buffer_->text->FirstParagraph()) {
341                         tmp = buffer_->text->cursor;
342                         buffer_->text->cursor.par = 
343                                 buffer_->text->FirstParagraph();
344                         buffer_->text->cursor.pos = 0;
345                         if (!buffer_->text->GotoNextError()) {
346                                 buffer_->text->cursor = tmp;
347                                 owner_->getMiniBuffer()->Set(_("No more errors"));
348                                 LyXBell();
349                         }
350                 } else {
351                         owner_->getMiniBuffer()->Set(_("No more errors"));
352                         LyXBell();
353                 }
354         }
355         buffer_->update(0);
356         buffer_->text->sel_cursor = 
357                 buffer_->text->cursor;
358 }
359
360
361 // Just a bunch of C wrappers around static members of BufferView
362 extern "C" void C_BufferView_UpCB(FL_OBJECT * ob, long buf) {
363         BufferView::UpCB(ob, buf);
364 }
365
366 extern "C" void C_BufferView_DownCB(FL_OBJECT * ob, long buf) {
367         BufferView::DownCB(ob, buf);
368 }
369
370 extern "C" void C_BufferView_ScrollCB(FL_OBJECT * ob, long buf) {
371         BufferView::ScrollCB(ob, buf);
372 }
373
374 extern "C" void C_BufferView_CursorToggleCB(FL_OBJECT * ob, long buf) {
375         BufferView::CursorToggleCB(ob, buf);
376 }
377
378 extern "C" int C_BufferView_work_area_handler(FL_OBJECT * ob, int event,
379                                               FL_Coord, FL_Coord, 
380                                               int key, void * xev) {
381         return BufferView::work_area_handler(ob, event, 0, 0, key, xev);
382 }
383
384
385 void BufferView::create_view(int xpos, int ypos, int width, int height)
386 {
387         FL_OBJECT * obj;
388         const int bw = abs(fl_get_border_width());
389
390         // a hack for the figinsets (Matthias)
391         // This one first, then it will probably be invisible. (Lgb)
392         ::figinset_canvas = figinset_canvas = obj = 
393                 fl_add_canvas(FL_NORMAL_CANVAS,
394                               xpos + 1,
395                               ypos + 1, 1, 1, "");
396         fl_set_object_boxtype(obj, FL_NO_BOX);
397         fl_set_object_resize(obj, FL_RESIZE_ALL);
398         fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
399
400         // a box
401         obj = fl_add_box(FL_BORDER_BOX, xpos, ypos,
402                          width - 15,
403                          height, "");
404         fl_set_object_resize(obj, FL_RESIZE_ALL);
405         fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
406
407         // the free object
408         work_area = obj = fl_add_free(FL_INPUT_FREE,
409                                       xpos +bw, ypos+bw,
410                                       width-15-2*bw /* scrollbarwidth */,
411                                       height-2*bw, "",
412                                       C_BufferView_work_area_handler);
413         obj->wantkey = FL_KEY_TAB;
414         obj->u_vdata = this; /* This is how we pass the BufferView
415                                        to the work_area_handler. */
416         fl_set_object_boxtype(obj, FL_DOWN_BOX);
417         fl_set_object_resize(obj, FL_RESIZE_ALL);
418         fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
419
420         //
421         // THE SCROLLBAR
422         //
423
424         // up - scrollbar button
425 #if FL_REVISION > 85
426         fl_set_border_width(-1);
427 #else
428         fl_set_border_width(-2); // to get visible feedback
429 #endif
430         button_up = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
431                                               width-15+4*bw,
432                                               ypos,
433                                               15, 15, "");
434         fl_set_object_boxtype(obj, FL_UP_BOX);
435         fl_set_object_color(obj, FL_MCOL, FL_BLUE);
436         fl_set_object_resize(obj, FL_RESIZE_ALL);
437         fl_set_object_gravity(obj, NorthEastGravity, NorthEastGravity);
438         fl_set_object_callback(obj, C_BufferView_UpCB, 0);
439         obj->u_vdata = this;
440         fl_set_pixmapbutton_data(obj, up_xpm);
441
442 #if FL_REVISION > 85
443         // Remove the blue feedback rectangle
444         fl_set_pixmapbutton_focus_outline(obj, 0);
445 #endif  
446
447         // the scrollbar slider
448         fl_set_border_width(-bw);
449         scrollbar = obj = fl_add_slider(FL_VERT_SLIDER,
450                                         width-15+4*bw,
451                                         ypos + 15,
452                                         15, height-30, "");
453         fl_set_object_color(obj, FL_COL1, FL_MCOL);
454         fl_set_object_boxtype(obj, FL_UP_BOX);
455         fl_set_object_resize(obj, FL_RESIZE_ALL);
456         fl_set_object_gravity(obj, NorthEastGravity, SouthEastGravity);
457         fl_set_object_callback(obj, C_BufferView_ScrollCB, 0);
458         obj->u_vdata = this;
459         
460         // down - scrollbar button
461 #if FL_REVISION > 85
462         fl_set_border_width(-1);
463 #else
464         fl_set_border_width(-2); // to get visible feedback
465 #endif
466         button_down = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
467                                                       width-15+4*bw,
468                                                       ypos + height-15,
469                                                       15, 15, "");
470         fl_set_object_boxtype(obj, FL_UP_BOX);
471         fl_set_object_color(obj, FL_MCOL, FL_BLUE);
472         fl_set_object_resize(obj, FL_RESIZE_ALL);
473         fl_set_object_gravity(obj, SouthEastGravity, SouthEastGravity);
474         fl_set_object_callback(obj, C_BufferView_DownCB, 0);
475         obj->u_vdata = this;
476         fl_set_pixmapbutton_data(obj, down_xpm);
477         fl_set_border_width(-bw);
478
479 #if FL_REVISION >85
480         // Remove the blue feedback rectangle
481         fl_set_pixmapbutton_focus_outline(obj, 0);
482 #endif  
483
484         //
485         // TIMERS
486         //
487         
488         // timer_cursor
489         timer_cursor = obj = fl_add_timer(FL_HIDDEN_TIMER,
490                                           0, 0, 0, 0, "Timer");
491         fl_set_object_callback(obj, C_BufferView_CursorToggleCB, 0);
492         obj->u_vdata = this;
493 }
494
495
496 // Callback for scrollbar up button
497 void BufferView::UpCB(FL_OBJECT * ob, long)
498 {
499         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
500         
501         if (view->buffer_ == 0) return;
502
503         XEvent const * ev2;
504         static long time = 0;
505         ev2 = fl_last_event();
506         if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
507                 time = 0;
508         int button = fl_get_button_numb(ob);
509         switch (button) {
510         case 3:
511                 view->ScrollUpOnePage(time++); break;
512         case 2:
513                 view->ScrollDownOnePage(time++); break;
514         default:
515                 view->ScrollUp(time++); break;
516         }
517 }
518
519
520 static
521 void waitForX()
522 {
523 #if 0
524         static Window w = 0;
525         static Atom a = 0;
526         if (!a)
527                 a = XInternAtom(fl_display, "WAIT_FOR_X", False);
528         if (w == 0) {
529                 int mask;
530                 XSetWindowAttributes attr;
531                 mask = CWOverrideRedirect;
532                 attr.override_redirect = 1;
533                 w = XCreateWindow(fl_display, fl_root,
534                                   0, 0, 1, 1, 0, CopyFromParent,
535                                   InputOnly, CopyFromParent, mask, &attr);
536                 XSelectInput(fl_display, w, PropertyChangeMask);
537                 XMapWindow(fl_display, w);
538         }
539         static XEvent ev;
540         XChangeProperty(fl_display, w, a, a, 8,
541                         PropModeAppend, reinterpret_cast<unsigned char*>(""), 0);
542         XWindowEvent(fl_display, w, PropertyChangeMask, &ev);
543 #endif
544         XSync(fl_get_display(), 0);
545 }
546
547
548 // Callback for scrollbar slider
549 void BufferView::ScrollCB(FL_OBJECT * ob, long)
550 {
551         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
552         extern bool cursor_follows_scrollbar;
553         
554         if (view->buffer_ == 0) return;
555
556         view->current_scrollbar_value = long(fl_get_slider_value(ob));
557         if (view->current_scrollbar_value < 0)
558                 view->current_scrollbar_value = 0;
559    
560         if (!view->screen)
561                 return;
562
563         view->screen->Draw(view->current_scrollbar_value);
564
565         if (cursor_follows_scrollbar) {
566                 LyXText * vbt = view->buffer_->text;
567                 int height = vbt->DefaultHeight();
568                 
569                 if (vbt->cursor.y < view->screen->first + height) {
570                         vbt->SetCursorFromCoordinates(0,
571                                                       view->screen->first +
572                                                       height);
573                 }
574                 else if (vbt->cursor.y >
575                          view->screen->first + view->work_area->h - height) {
576                         vbt->SetCursorFromCoordinates(0,
577                                                       view->screen->first +
578                                                       view->work_area->h  -
579                                                       height);
580                 }
581         }
582         waitForX();
583 }
584
585
586 // Callback for scrollbar down button
587 void BufferView::DownCB(FL_OBJECT * ob, long)
588 {
589         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
590
591         if (view->buffer_ == 0) return;
592         
593         XEvent const * ev2;
594         static long time = 0;
595         ev2 = fl_last_event();
596         if (ev2->type == ButtonPress || ev2->type == ButtonRelease) 
597                 time = 0;
598         int button = fl_get_button_numb(ob);
599         switch (button) {
600         case 2:
601                 view->ScrollUpOnePage(time++); break;
602         case 3:
603                 view->ScrollDownOnePage(time++); break;
604         default:
605                 view->ScrollDown(time++); break;
606         }
607 }
608
609
610 int BufferView::ScrollUp(long time)
611 {
612         if (buffer_ == 0) return 0;
613         if (!screen)
614                 return 0;
615    
616         double value= fl_get_slider_value(scrollbar);
617    
618         if (value == 0)
619                 return 0;
620    
621         float add_value =  (buffer_->text->DefaultHeight()
622                             + float(time) * float(time) * 0.125);
623    
624         if (add_value > work_area->h)
625                 add_value = float(work_area->h -
626                                   buffer_->text->DefaultHeight());
627    
628         value -= add_value;
629
630         if (value < 0)
631                 value = 0;
632    
633         fl_set_slider_value(scrollbar, value);
634    
635         ScrollCB(scrollbar, 0); 
636         return 0;
637 }
638
639
640 int BufferView::ScrollDown(long time)
641 {
642         if (buffer_ == 0) return 0;
643         if (!screen)
644                 return 0;
645    
646         double value= fl_get_slider_value(scrollbar);
647         double min, max;
648         fl_get_slider_bounds(scrollbar, &min, &max);
649
650         if (value == max)
651                 return 0;
652    
653         float add_value =  (buffer_->text->DefaultHeight()
654                             + float(time) * float(time) * 0.125);
655    
656         if (add_value > work_area->h)
657                 add_value = float(work_area->h -
658                                   buffer_->text->DefaultHeight());
659    
660         value += add_value;
661    
662         if (value > max)
663                 value = max;
664    
665         fl_set_slider_value(scrollbar, value);
666    
667         ScrollCB(scrollbar, 0); 
668         return 0;
669 }
670
671
672 void BufferView::ScrollUpOnePage(long /*time*/)
673 {
674         if (buffer_ == 0) return;
675         if (!screen)
676                 return;
677    
678         long y = screen->first;
679
680         if (!y) return;
681    
682         Row* row = buffer_->text->GetRowNearY(y);
683         y = y - work_area->h + row->height;
684         
685         fl_set_slider_value(scrollbar, y);
686    
687         ScrollCB(scrollbar, 0); 
688 }
689
690
691 void BufferView::ScrollDownOnePage(long /*time*/)
692 {
693         if (buffer_ == 0) return;
694         if (!screen)
695                 return;
696    
697         double min, max;
698         fl_get_slider_bounds(scrollbar, &min, &max);
699         long y = screen->first;
700    
701         if (y > buffer_->text->height - work_area->h)
702                 return;
703    
704         y += work_area->h;
705         buffer_->text->GetRowNearY(y);
706         
707         fl_set_slider_value(scrollbar, y);
708    
709         ScrollCB(scrollbar, 0); 
710 }
711
712
713 int BufferView::work_area_handler(FL_OBJECT * ob, int event,
714                                   FL_Coord, FL_Coord ,
715                                   int /*key*/, void *xev)
716 {
717         static int x_old = -1;
718         static int y_old = -1;
719         static long scrollbar_value_old = -1;
720         
721         XEvent * ev = static_cast<XEvent*>(xev);
722         BufferView * view = static_cast<BufferView*>(ob->u_vdata);
723
724         // If we don't have a view yet; return
725         if (!view || quitting) return 0;
726
727         switch (event){   
728         case FL_DRAW:
729                 view->workAreaExpose(); 
730                 break;
731         case FL_PUSH:
732                 view->WorkAreaButtonPress(ob, 0, 0, 0, ev, 0);
733                 break; 
734         case FL_RELEASE:
735                 view->WorkAreaButtonRelease(ob, 0, 0, 0, ev, 0);
736                 break;
737         case FL_MOUSE:
738                 if (ev->xmotion.x != x_old || 
739                     ev->xmotion.y != y_old ||
740                     view->current_scrollbar_value != scrollbar_value_old) {
741                         x_old = ev->xmotion.x;
742                         y_old = ev->xmotion.y;
743                         scrollbar_value_old = view->current_scrollbar_value;
744                         view->WorkAreaMotionNotify(ob, 0, 0, 0, ev, 0);
745                 }
746                 break;
747         // Done by the raw callback:
748         //  case FL_KEYBOARD: WorkAreaKeyPress(ob, 0, 0, 0, ev, 0); break;
749         case FL_FOCUS:
750                 if (!view->owner_->getMiniBuffer()->shows_no_match)
751                         view->owner_->getMiniBuffer()->Init();
752                 view->owner_->getMiniBuffer()->shows_no_match = false;
753                 view->work_area_focus = true;
754                 fl_set_timer(view->timer_cursor, 0.4);
755                 break;
756         case FL_UNFOCUS:
757                 view->owner_->getMiniBuffer()->ExecCommand();
758                 view->work_area_focus = false;
759                 break;
760         case FL_ENTER:
761                 SetXtermCursor(view->owner_->getForm()->window);
762                 // reset the timer
763                 view->lyx_focus = true;
764                 fl_set_timer(view->timer_cursor, 0.4);
765                 break;
766         case FL_LEAVE: 
767                 if (!input_prohibited)
768                         XUndefineCursor(fl_display,
769                                         view->owner_->getForm()->window);
770                 view->lyx_focus = false; // This is not an absolute truth
771                 // but if it is not true, it will be changed within a blink
772                 // of an eye. ... Not good enough... use regulare timeperiod
773                 //fl_set_timer(view->timer_cursor, 0.01); // 0.1 sec blink
774                 fl_set_timer(view->timer_cursor, 0.4); // 0.4 sec blink
775                 break;
776         case FL_DBLCLICK: 
777                 // select a word 
778                 if (view->buffer_ && !view->buffer_->the_locking_inset) {
779                         if (view->screen && ev->xbutton.button == 1) {
780                                 view->screen->HideCursor();
781                                 view->screen->ToggleSelection(); 
782                                 view->buffer_->text->SelectWord();
783                                 view->screen->ToggleSelection(false);
784                                 /* This will fit the cursor on the screen
785                                  * if necessary */ 
786                                 view->buffer_->update(0); 
787                         }
788                 }
789                 break;
790         case FL_TRPLCLICK:
791                 // select a line
792                 if (view->buffer_ && view->screen && ev->xbutton.button == 1) {
793                         view->screen->HideCursor(); 
794                         view->screen->ToggleSelection(); 
795                         view->buffer_->text->CursorHome();
796                         view->buffer_->text->sel_cursor = 
797                                 view->buffer_->text->cursor;
798                         view->buffer_->text->CursorEnd();
799                         view->buffer_->text->SetSelection();
800                         view->screen->ToggleSelection(false); 
801                         /* This will fit the cursor on the screen
802                          * if necessary */ 
803                         view->buffer_->update(0); 
804                 }
805                 break;
806         case FL_OTHER:
807                 view->WorkAreaSelectionNotify(ob,
808                                               view->owner_->getForm()->window,
809                                               0, 0, ev, 0); 
810                 break;
811         }
812         return 1;
813 }
814
815 int BufferView::WorkAreaMotionNotify(FL_OBJECT *ob, Window,
816                                      int /*w*/, int /*h*/,
817                                      XEvent *ev, void */*d*/)
818 {
819
820         if (buffer_ == 0) return 0;
821         if (!screen) return 0;
822
823         // Check for inset locking
824         if (buffer_->the_locking_inset) {
825                 LyXCursor cursor = buffer_->text->cursor;
826                 buffer_->the_locking_inset->
827                         InsetMotionNotify(ev->xbutton.x - ob->x - cursor.x,
828                                           ev->xbutton.y - ob->y -
829                                           (cursor.y),
830                                           ev->xbutton.state);
831                 return 0;
832         }
833    
834         // Only use motion with button 1
835         if (!ev->xmotion.state & Button1MotionMask)
836                 return 0; 
837    
838         /* The selection possible is needed, that only motion events are 
839          * used, where the bottom press event was on the drawing area too */
840         if (selection_possible) {
841                 screen->HideCursor();
842
843                 buffer_->text->
844                         SetCursorFromCoordinates(ev->xbutton.x - ob->x,
845                                                  ev->xbutton.y - ob->y +
846                                                  screen->first);
847       
848                 if (!buffer_->text->selection)
849                     buffer_->update(-3); // Maybe an empty line was deleted
850       
851                 buffer_->text->SetSelection();
852                 screen->ToggleToggle();
853                 if (screen->FitCursor())
854                         updateScrollbar(); 
855                 screen->ShowCursor();
856         }
857         return 0;
858 }
859
860
861 extern int bibitemMaxWidth(LyXFont const &);
862
863 // Single-click on work area
864 int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
865                         int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
866 {
867         last_click_x = -1;
868         last_click_y = -1;
869
870         if (buffer_ == 0) return 0;
871         if (!screen) return 0;
872
873         int const x = ev->xbutton.x - ob->x;
874         int const y = ev->xbutton.y - ob->y;
875         // If we hit an inset, we have the inset coordinates in these
876         // and inset_hit points to the inset.  If we do not hit an
877         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
878         int inset_x = x;
879         int inset_y = y;
880         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
881
882         // ok ok, this is a hack.
883         int button = ev->xbutton.button;
884         if (button == 4 || button == 5) goto wheel;
885
886         {
887                 
888         if (buffer_->the_locking_inset) {
889                 // We are in inset locking mode
890                 
891                 /* Check whether the inset was hit. If not reset mode,
892                    otherwise give the event to the inset */
893                 if (inset_hit != 0) {
894                         buffer_->the_locking_inset->
895                                 InsetButtonPress(inset_x, inset_y, button);
896                         return 0;
897                 } else {
898                         UnlockInset(buffer_->the_locking_inset);
899                 }
900         }
901         
902         selection_possible = true;
903         screen->HideCursor();
904         
905         // Right button mouse click on a table
906         if (button == 3 &&
907             (buffer_->text->cursor.par->table ||
908              buffer_->text->MouseHitInTable(x, y+screen->first))) {
909                 // Set the cursor to the press-position
910                 buffer_->text->SetCursorFromCoordinates(x, y + screen->first);
911                 bool doit = true;
912                 
913                 // Only show the table popup if the hit is in the table, too
914                 if (!buffer_->text->HitInTable(buffer_->text->cursor.row, x))
915                         doit = false;
916                 
917                 // Hit above or below the table?
918                 if (doit) {
919                         if (!buffer_->text->selection) {
920                                 screen->ToggleSelection();
921                                 buffer_->text->ClearSelection();
922                                 buffer_->text->FullRebreak();
923                                 screen->Update();
924                                 updateScrollbar();
925                         }
926                         // Popup table popup when on a table.
927                         // This is obviously temporary, since we should be
928                         // able to 
929                         // popup various context-sensitive-menus with the
930                         // the right mouse. So this should be done more
931                         // general in the future. Matthias.
932                         selection_possible = false;
933                         owner_->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
934                                                        "true");
935                         return 0;
936                 }
937         }
938         
939         int screen_first = screen->first;
940         
941         // Middle button press pastes if we have a selection
942         bool paste_internally = false;
943         if (button == 2  // && !buffer_->the_locking_inset
944             && buffer_->text->selection) {
945                 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
946                 paste_internally = true;
947         }
948         
949         // Clear the selection
950         screen->ToggleSelection();
951         buffer_->text->ClearSelection();
952         buffer_->text->FullRebreak();
953         screen->Update();
954         updateScrollbar();
955                 
956         // Single left click in math inset?
957         if (inset_hit != 0 && inset_hit->Editable() == 2) {
958                 // Highly editable inset, like math
959                 selection_possible = false;
960                 owner_->updateLayoutChoice();
961                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
962                 inset_hit->Edit(inset_x, inset_y);
963                 return 0;
964         } 
965
966         // Right click on a footnote flag opens float menu
967         if (button == 3) { 
968                 selection_possible = false;
969                 return 0;
970         }
971         
972         buffer_->text->SetCursorFromCoordinates(x, y + screen_first);
973         buffer_->text->FinishUndo();
974         buffer_->text->sel_cursor = buffer_->text->cursor;
975         buffer_->text->cursor.x_fix = buffer_->text->cursor.x;
976         
977         owner_->updateLayoutChoice();
978         if (screen->FitCursor()){
979                 updateScrollbar();
980                 selection_possible = false;
981         }
982
983         // Insert primary selection with middle mouse
984         // if there is a local selection in the current buffer, insert this
985         if (button == 2) { //  && !buffer_->the_locking_inset){
986                 if (paste_internally)
987                         owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
988                 else
989                         owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
990                                                        "paragraph");
991                 selection_possible = false;
992                 return 0;
993         }
994         }
995         goto out;
996  wheel: {
997         // I am not quite sure if this is the correct place to put this,
998         // but it will not cause any harm.
999         // Patch from Mark Huang (markman@mit.edu) to make LyX recognise
1000         // button 4 and 5. This enables LyX use use the scrollwhell on
1001         // certain mice for something useful. (Lgb)
1002         // Added wheel acceleration detection code. (Rvdk)
1003         static Time lastTime = 0;
1004         int diff = ev->xbutton.time - lastTime;
1005         int scroll = int(1.0 + (4.0/(abs(diff)+1.0))*200.0);
1006         switch (button) {
1007         case 4:
1008                 ScrollUp(scroll);
1009                 break;
1010         case 5:
1011                 ScrollDown(scroll);
1012                 break;
1013         }
1014         lastTime = ev->xbutton.time;
1015         return 0;
1016         }
1017  out:
1018         last_click_x = x;
1019         last_click_y = y;
1020         
1021         return 0;
1022 }
1023
1024
1025 int BufferView::WorkAreaButtonRelease(FL_OBJECT *ob, Window ,
1026                           int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1027 {
1028         if (buffer_ == 0 || screen == 0) return 0;
1029
1030         int const x = ev->xbutton.x - ob->x;
1031         int const y = ev->xbutton.y - ob->y;
1032
1033         // If we hit an inset, we have the inset coordinates in these
1034         // and inset_hit points to the inset.  If we do not hit an
1035         // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1036         int inset_x = x;
1037         int inset_y = y;
1038         Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1039
1040         if (buffer_->the_locking_inset) {
1041                 // We are in inset locking mode.
1042
1043                 /* LyX does a kind of work-area grabbing for insets.
1044                    Only a ButtonPress Event outside the inset will 
1045                    force a InsetUnlock. */
1046                 buffer_->the_locking_inset->
1047                         InsetButtonRelease(inset_x, inset_y, 
1048                                            ev->xbutton.button);
1049                 return 0;
1050         }
1051   
1052         selection_possible = false;
1053         if (buffer_->text->cursor.par->table) {
1054                 int cell = buffer_->text->
1055                         NumberOfCell(buffer_->text->cursor.par,
1056                                      buffer_->text->cursor.pos);
1057                 if (buffer_->text->cursor.par->table->IsContRow(cell) &&
1058                     buffer_->text->cursor.par->table->
1059                     CellHasContRow(buffer_->text->cursor.par->table->
1060                                    GetCellAbove(cell))<0) {
1061                         buffer_->text->CursorUp();
1062                 }
1063         }
1064         
1065         if (ev->xbutton.button >= 2)
1066                 return 0;
1067
1068         // Make sure that the press was not far from the release
1069         if ((abs(last_click_x - x) >= 5) ||
1070             (abs(last_click_y - y) >= 5)) {
1071                 return 0;
1072         }
1073
1074         // Did we hit an editable inset?
1075         if (inset_hit != 0) {
1076                 // Inset like error, notes and figures
1077                 selection_possible = false;
1078 #ifdef WITH_WARNINGS
1079 #warning fix this proper in 0.13
1080 #endif
1081                 // Following a ref shouldn't issue
1082                 // a push on the undo-stack
1083                 // anylonger, now that we have
1084                 // keybindings for following
1085                 // references and returning from
1086                 // references.  IMHO though, it
1087                 // should be the inset's own business
1088                 // to push or not push on the undo
1089                 // stack. They don't *have* to
1090                 // alter the document...
1091                 // (Joacim)
1092                 // ...or maybe the SetCursorParUndo()
1093                 // below isn't necessary at all anylonger?
1094                 if (inset_hit->LyxCode() == Inset::REF_CODE) {
1095                         buffer_->text->SetCursorParUndo();
1096                 }
1097
1098                 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1099                 inset_hit->Edit(inset_x, inset_y);
1100                 return 0;
1101         }
1102
1103         // check whether we want to open a float
1104         if (buffer_->text) {
1105                 bool hit = false;
1106                 char c = ' ';
1107                 if (buffer_->text->cursor.pos <
1108                     buffer_->text->cursor.par->Last()) {
1109                         c = buffer_->text->cursor.par->
1110                                 GetChar(buffer_->text->cursor.pos);
1111                 }
1112                 if (c == LyXParagraph::META_FOOTNOTE
1113                     || c == LyXParagraph::META_MARGIN
1114                     || c == LyXParagraph::META_FIG
1115                     || c == LyXParagraph::META_TAB
1116                     || c == LyXParagraph::META_WIDE_FIG
1117                     || c == LyXParagraph::META_WIDE_TAB
1118                     || c == LyXParagraph::META_ALGORITHM){
1119                         hit = true;
1120                 } else if (buffer_->text->cursor.pos - 1 >= 0) {
1121                         c = buffer_->text->cursor.par->
1122                                 GetChar(buffer_->text->cursor.pos - 1);
1123                         if (c == LyXParagraph::META_FOOTNOTE
1124                             || c == LyXParagraph::META_MARGIN
1125                             || c == LyXParagraph::META_FIG
1126                             || c == LyXParagraph::META_TAB
1127                             || c == LyXParagraph::META_WIDE_FIG 
1128                             || c == LyXParagraph::META_WIDE_TAB
1129                             || c == LyXParagraph::META_ALGORITHM){
1130                                 // We are one step too far to the right
1131                                 buffer_->text->CursorLeft();
1132                                 hit = true;
1133                         }
1134                 }
1135                 if (hit == true) {
1136                         ToggleFloat();
1137                         selection_possible = false;
1138                         return 0;
1139                 }
1140         }
1141
1142         // Do we want to close a float? (click on the float-label)
1143         if (buffer_->text->cursor.row->par->footnoteflag == 
1144             LyXParagraph::OPEN_FOOTNOTE
1145             && buffer_->text->cursor.pos == 0
1146             && buffer_->text->cursor.row->previous &&
1147             buffer_->text->cursor.row->previous->par->
1148             footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
1149                 LyXFont font (LyXFont::ALL_SANE);
1150                 font.setSize(LyXFont::SIZE_SMALL);
1151
1152                 int box_x = 20; // LYX_PAPER_MARGIN;
1153                 box_x += font.textWidth("Mwide-figM", 10);
1154
1155                 int screen_first = screen->first;
1156
1157                 if (x < box_x
1158                     && y + screen_first > buffer_->text->cursor.y -
1159                     buffer_->text->cursor.row->baseline
1160                     && y + screen_first < buffer_->text->cursor.y -
1161                     buffer_->text->cursor.row->baseline
1162                     + font.maxAscent()*1.2 + font.maxDescent()*1.2) {
1163                         ToggleFloat();
1164                         selection_possible = false;
1165                         return 0;
1166                 }
1167         }
1168
1169         // Maybe we want to edit a bibitem ale970302
1170         if (buffer_->text->cursor.par->bibkey && x < 20 + 
1171             bibitemMaxWidth(textclasslist.TextClass(buffer_->
1172                                         params.textclass).defaultfont())) {
1173                 buffer_->text->cursor.par->bibkey->Edit(0, 0);
1174         }
1175
1176         return 0;
1177 }
1178
1179
1180 /* 
1181  * Returns an inset if inset was hit. 0 otherwise.
1182  * If hit, the coordinates are changed relative to the inset. 
1183  * Otherwise coordinates are not changed, and false is returned.
1184  */
1185 Inset * BufferView::checkInsetHit(int & x, int & y)
1186 {
1187         if (!getScreen())
1188                 return 0;
1189   
1190         int y_tmp = y + getScreen()->first;
1191   
1192         LyXCursor cursor = buffer_->text->cursor;
1193         if (cursor.pos < cursor.par->Last() 
1194             && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
1195             && cursor.par->GetInset(cursor.pos)
1196             && cursor.par->GetInset(cursor.pos)->Editable()) {
1197
1198                 // Check whether the inset really was hit
1199                 Inset* tmpinset = cursor.par->GetInset(cursor.pos);
1200                 LyXFont font = buffer_->text->GetFont(cursor.par, cursor.pos);
1201                 if (x > cursor.x
1202                     && x < cursor.x + tmpinset->Width(font) 
1203                     && y_tmp > cursor.y - tmpinset->Ascent(font)
1204                     && y_tmp < cursor.y + tmpinset->Descent(font)) {
1205                         x = x - cursor.x;
1206                         // The origin of an inset is on the baseline
1207                         y = y_tmp - (cursor.y); 
1208                         return tmpinset;
1209                 }
1210         } else if (cursor.pos - 1 >= 0 
1211                    && cursor.par->GetChar(cursor.pos - 1) == LyXParagraph::META_INSET
1212                    && cursor.par->GetInset(cursor.pos - 1)
1213                    && cursor.par->GetInset(cursor.pos - 1)->Editable()) {
1214                 buffer_->text->CursorLeft();
1215                 Inset * result = checkInsetHit(x, y);
1216                 if (result == 0) {
1217                         buffer_->text->CursorRight();
1218                         return 0;
1219                 } else {
1220                         return result;
1221                 }
1222         }
1223         return 0;
1224 }
1225
1226
1227 int BufferView::workAreaExpose()
1228 {
1229         if (!work_area || !work_area->form->visible) 
1230                 return 1;
1231
1232         // this is a hack to ensure that we only call this through
1233         // BufferView::redraw().
1234         if (!lgb_hack) {
1235                 redraw();
1236         }
1237         
1238         static int work_area_width = work_area->w;
1239         static int work_area_height = work_area->h;
1240
1241         bool widthChange = work_area->w != work_area_width;
1242         bool heightChange = work_area->h != work_area_height;
1243
1244         // update from work area
1245         work_area_width = work_area->w;
1246         work_area_height = work_area->h;
1247         if (buffer_ != 0) {
1248                 if (widthChange) {
1249                         // All buffers need a resize
1250                         bufferlist.resize();
1251                 } else if (heightChange) {
1252                         // Rebuild image of current screen
1253                         updateScreen();
1254                         // fitCursor() ensures we don't jump back
1255                         // to the start of the document on vertical
1256                         // resize
1257                         fitCursor();
1258
1259                         // The main window size has changed, repaint most stuff
1260                         redraw();
1261                         // ...including the minibuffer
1262                         owner_->getMiniBuffer()->Init();
1263
1264                 } else if (screen) screen->Redraw();
1265         } else {
1266                 // Grey box when we don't have a buffer
1267                 fl_winset(FL_ObjWin(work_area));
1268                 fl_rectangle(1, work_area->x, work_area->y,
1269                              work_area->w, work_area->h, FL_GRAY63);
1270         }
1271
1272         // always make sure that the scrollbar is sane.
1273         updateScrollbar();
1274         owner_->updateLayoutChoice();
1275         return 1;
1276 }
1277
1278
1279 // Callback for cursor timer
1280 void BufferView::CursorToggleCB(FL_OBJECT * ob, long)
1281 {
1282         BufferView *view = static_cast<BufferView*>(ob->u_vdata);
1283         
1284         /* quite a nice place for asyncron Inset updating, isn't it? */
1285         // actually no! This is run even if no buffer exist... so (Lgb)
1286         if (view && !view->buffer_) {
1287                 goto set_timer_and_return;
1288         }
1289
1290         // NOTE:
1291         // On my quest to solve the gs rendre hangups I am now
1292         // disabling the SIGHUP completely, and will do a wait
1293         // now and then instead. If the guess that xforms somehow
1294         // destroys something is true, this is likely (hopefully)
1295         // to solve the problem...at least I hope so. Lgb
1296
1297         // ...Ok this seems to work...at least it does not make things
1298         // worse so far. However I still see gs processes that hangs.
1299         // I would really like to know _why_ they are hanging. Anyway
1300         // the solution without the SIGCHLD handler seems to be easier
1301         // to debug.
1302
1303         // When attaching gdb to a a running gs that hangs it shows
1304         // that it is waiting for input(?) Is it possible for us to
1305         // provide that input somehow? Or figure what it is expecing
1306         // to read?
1307
1308         // One solution is to, after some time, look if there are some
1309         // old gs processes still running and if there are: kill them
1310         // and re render.
1311
1312         // Another solution is to provide the user an option to rerender
1313         // a picture. This would, for the picture in question, check if
1314         // there is a gs running for it, if so kill it, and start a new
1315         // rendering process.
1316
1317         // these comments posted to lyx@via
1318         {
1319         int status = 1;
1320         int pid = waitpid((pid_t)0, &status, WNOHANG);
1321         if (pid == -1) // error find out what is wrong
1322                 ; // ignore it for now.
1323         else if (pid > 0)
1324                 sigchldhandler(pid, &status);
1325         }
1326         if (InsetUpdateList) 
1327                 UpdateInsetUpdateList();
1328
1329         if (view && !view->screen){
1330                 goto set_timer_and_return;
1331         }
1332
1333         if (view->lyx_focus && view->work_area_focus) {
1334                 if (!view->buffer_->the_locking_inset){
1335                         view->screen->CursorToggle();
1336                 } else {
1337                         view->buffer_->the_locking_inset->
1338                                 ToggleInsetCursor();
1339                 }
1340                 goto set_timer_and_return;
1341         } else {
1342                 // Make sure that the cursor is visible.
1343                 if (!view->buffer_->the_locking_inset){
1344                         view->screen->ShowCursor();
1345                 } else {
1346                         if (!view->buffer_->the_locking_inset->isCursorVisible())
1347                                 view->buffer_->the_locking_inset->
1348                                         ToggleInsetCursor();
1349                 }
1350
1351                 // This is only run when work_area_focus or lyx_focus is false.
1352                 Window tmpwin;
1353                 int tmp;
1354                 XGetInputFocus(fl_display, &tmpwin, &tmp);
1355                 if (lyxerr.debugging()) {
1356                         lyxerr << "tmpwin: " << tmpwin
1357                                << "\nwindow: " << view->owner_->getForm()->window
1358                                << "\nwork_area_focus: " << view->work_area_focus
1359                                << "\nlyx_focus      : " << view->lyx_focus
1360                                << endl;
1361                 }
1362                 if (tmpwin != view->owner_->getForm()->window) {
1363                         view->lyx_focus = false;
1364                         goto skip_timer;
1365                 } else {
1366                         view->lyx_focus = true;
1367                         if (!view->work_area_focus)
1368                                 goto skip_timer;
1369                         else
1370                                 goto set_timer_and_return;
1371                 }
1372         }
1373
1374   set_timer_and_return:
1375         fl_set_timer(ob, 0.4);
1376   skip_timer:
1377         return;
1378 }
1379
1380
1381 int BufferView::WorkAreaSelectionNotify(FL_OBJECT *, Window win,
1382                             int /*w*/, int /*h*/, XEvent *event, void */*d*/)
1383 {
1384         if (buffer_ == 0) return 0;
1385         if (event->type != SelectionNotify)
1386                 return 0;
1387
1388         Atom tmpatom;
1389         unsigned long ul1;
1390         unsigned long ul2;
1391         unsigned char * uc = 0;
1392         int tmpint;
1393         screen->HideCursor();
1394         BeforeChange();
1395         if (event->xselection.type == XA_STRING
1396             && event->xselection.property) {
1397     
1398                 if (XGetWindowProperty(
1399                         fl_display            /* display */,
1400                         win /* w */,
1401                         event->xselection.property        /* property */,
1402                         0                /* long_offset */,
1403                         0                /* long_length */,
1404                         false                /* delete */,
1405                         XA_STRING                /* req_type */,
1406                         &tmpatom               /* actual_type_return */,
1407                         &tmpint                /* actual_format_return */,
1408                         &ul1      /* nitems_return */,
1409                         &ul2      /* bytes_after_return */,
1410                         &uc     /* prop_return */
1411                         ) != Success) {
1412                         return 0;
1413                 }
1414                 XFlush(fl_display);
1415
1416                 if (uc){
1417                         free(uc);
1418                         uc = 0;
1419                 }
1420
1421                 if (XGetWindowProperty(
1422                         fl_display           /* display */,
1423                         win              /* w */,
1424                         event->xselection.property           /* property */,
1425                         0                /* long_offset */,
1426                         ul2/4+1                /* long_length */,
1427                         True                /* delete */,
1428                         XA_STRING                /* req_type */,
1429                         &tmpatom               /* actual_type_return */,
1430                         &tmpint                /* actual_format_return */,
1431                         &ul1      /* nitems_return */,
1432                         &ul2      /* bytes_after_return */,
1433                         &uc     /* prop_return */
1434                         ) != Success) {
1435                         return 0;
1436                 }
1437                 XFlush(fl_display);
1438         
1439                 if (uc){
1440                         if (!ascii_type) {
1441                                 buffer_->text->
1442                                         InsertStringA(reinterpret_cast<char*>(uc));
1443                         } else {
1444                                 buffer_->text->
1445                                         InsertStringB(reinterpret_cast<char*>(uc));
1446                         }
1447                         free(uc);
1448                         uc = 0;
1449                 }
1450     
1451                 buffer_->update(1);
1452         }
1453         return 0;
1454 }
1455
1456
1457 void BufferView::cursorPrevious()
1458 {
1459         if (!buffer()->text->cursor.row->previous) return;
1460         
1461         long y = getScreen()->first;
1462         Row * cursorrow = buffer()->text->cursor.row;
1463         buffer()->text->
1464           SetCursorFromCoordinates(buffer()->text->
1465                                    cursor.x_fix,
1466                                    y);
1467         buffer()->text->FinishUndo();
1468         // this is to allow jumping over large insets
1469         if ((cursorrow == buffer()->text->cursor.row))
1470           buffer()->text->CursorUp();
1471         
1472         if (buffer()->text->cursor.row->height < work_area->h)
1473           getScreen()->Draw(buffer()->text->cursor.y
1474                             - buffer()->text->cursor.row->baseline
1475                             + buffer()->text->cursor.row->height
1476                             - work_area->h +1 );
1477 }
1478
1479
1480 void BufferView::cursorNext()
1481 {
1482         if (!buffer()->text->cursor.row->next) return;
1483         
1484         long y = getScreen()->first;
1485         buffer()->text->GetRowNearY(y);
1486         Row * cursorrow = buffer()->text->cursor.row;
1487         buffer()->text->
1488                 SetCursorFromCoordinates(buffer()->text->
1489                                          cursor.x_fix, 
1490                                          y + work_area->h);
1491         buffer()->text->FinishUndo();
1492         /* this is to allow jumping over large insets */
1493         if ((cursorrow == buffer()->text->cursor.row))
1494           buffer()->text->CursorDown();
1495         
1496         if (buffer()->text->cursor.row->height < work_area->h)
1497           getScreen()->Draw(buffer()->text->cursor.y
1498                             - buffer()->text->cursor.row->baseline);
1499 }
1500
1501
1502 bool BufferView::available() const
1503 {
1504         if (buffer_ && buffer_->text) return true;
1505         return false;
1506 }
1507
1508
1509 void BufferView::savePosition()
1510 {
1511         backstack.push(buffer()->getFileName(),
1512                         buffer()->text->cursor.x,
1513                         buffer()->text->cursor.y);
1514 }
1515
1516
1517 void BufferView::restorePosition()
1518 {
1519         if (backstack.empty()) return;
1520         
1521         int  x, y;
1522         string fname = backstack.pop(&x, &y);
1523         
1524         BeforeChange();
1525         Buffer * b = (bufferlist.exists(fname)) ? bufferlist.getBuffer(fname):
1526                 bufferlist.loadLyXFile(fname); // don't ask, just load it
1527         buffer(b);
1528         buffer()->text->SetCursorFromCoordinates(x, y);
1529         buffer()->update(0);
1530