2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1995 Matthias Ettrich
8 * Copyright 1995-1999 The LyX Team.
10 * ====================================================== */
20 #include "support/lstrings.h"
23 #pragma implementation
26 #include "commandtags.h"
27 #include "BufferView.h"
28 #include "bufferlist.h"
31 #include "insets/lyxinset.h"
32 #include "minibuffer.h"
33 #include "lyxscreen.h"
38 #include "lyx_gui_misc.h"
39 #include "BackStack.h"
45 extern BufferList bufferlist;
46 void sigchldhandler(pid_t pid, int *status);
48 extern void SetXtermCursor(Window win);
49 extern bool input_prohibited;
50 extern bool selection_possible;
51 extern void BeforeChange();
52 extern char ascii_type;
53 extern int UnlockInset(UpdatableInset* inset);
54 extern void ToggleFloat();
55 extern void MenuPasteSelection(char at);
56 extern InsetUpdateStruct *InsetUpdateList;
57 extern void UpdateInsetUpdateList();
58 extern void FreeUpdateTimer();
60 // This is _very_ temporary
61 FL_OBJECT * figinset_canvas;
63 BufferView::BufferView(LyXView *o, int xpos, int ypos,
64 int width, int height)
78 current_scrollbar_value = 0;
79 create_view(xpos, ypos, width, height);
80 // Activate the timer for the cursor
81 fl_set_timer(timer_cursor, 0.4);
82 fl_set_focus_object(owner_->getForm(), work_area);
83 work_area_focus = true;
88 BufferView::~BufferView()
96 void BufferView::buffer(Buffer *b)
98 lyxerr[Debug::INFO] << "Setting buffer in BufferView" << endl;
100 buffer_->InsetSleep();
101 buffer_->delUser(this);
106 // Set current buffer
109 if (bufferlist.getState() == BufferList::CLOSING) return;
116 // If we are closing the buffer, use the first buffer as current
118 buffer_ = bufferlist.first();
122 lyxerr[Debug::INFO] << " Buffer addr: " << buffer_ << endl;
123 buffer_->addUser(this);
124 owner_->getMenus()->showMenus();
125 // If we don't have a text object for this, we make one
128 resizeCurrentBuffer();
134 if (buffer_->text == 0)
135 resizeCurrentBuffer();
141 screen->first = screen->TopCursorVisible();
143 updateAllVisibleBufferRelatedPopups();
144 buffer_->InsetWakeup();
146 lyxerr[Debug::INFO] << " No Buffer!" << endl;
147 owner_->getMenus()->hideMenus();
149 fl_redraw_object(work_area);
151 // should update layoutchoice even if we don't have a buffer.
152 owner_->updateLayoutChoice();
153 owner_->getMiniBuffer()->Init();
154 owner_->updateWindowTitle();
158 void BufferView::updateScreen()
160 // Regenerate the screen.
164 screen = new LyXScreen(FL_ObjWin(work_area),
171 screen = new LyXScreen(FL_ObjWin(work_area),
181 void BufferView::resize()
183 // This will resize the buffer. (Asger)
185 resizeCurrentBuffer();
189 static bool lgb_hack = false;
191 void BufferView::redraw()
193 lyxerr[Debug::INFO] << "BufferView::redraw()" << endl;
195 fl_redraw_object(work_area);
196 fl_redraw_object(scrollbar);
197 fl_redraw_object(button_down);
198 fl_redraw_object(button_up);
203 void BufferView::fitCursor()
205 if (screen) screen->FitCursor();
209 void BufferView::update()
211 if (screen) screen->Update();
215 void BufferView::updateScrollbar()
217 /* If the text is smaller than the working area, the scrollbar
218 * maximum must be the working area height. No scrolling will
222 fl_set_slider_value(scrollbar, 0);
223 fl_set_slider_size(scrollbar, scrollbar->h);
227 static long max2 = 0;
228 static long height2 = 0;
238 cbth = buffer_->text->height;
241 cbsf = screen->first;
243 // check if anything has changed.
245 height2 == work_area->h &&
246 current_scrollbar_value == cbsf)
250 height2 = work_area->h;
251 current_scrollbar_value = cbsf;
253 if (cbth <= height2) { // text is smaller than screen
254 fl_set_slider_size(scrollbar, scrollbar->h);
258 long maximum_height = work_area->h * 3/4 + cbth;
262 double hfloat = work_area->h;
263 double maxfloat = maximum_height;
265 fl_set_slider_value(scrollbar, value);
266 fl_set_slider_bounds(scrollbar, 0,
267 maximum_height - work_area->h);
270 double lineh = text->DefaultHeight();
272 double lineh = buffer_->text->DefaultHeight();
274 fl_set_slider_increment(scrollbar, work_area->h-lineh, lineh);
277 if ((hfloat / maxfloat) * float(height2) < 3)
278 fl_set_slider_size(scrollbar,
281 fl_set_slider_size(scrollbar,
284 fl_set_slider_size(scrollbar, hfloat);
285 fl_set_slider_precision(scrollbar, 0);
289 void BufferView::redoCurrentBuffer()
291 lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
295 owner_->updateLayoutChoice();
298 if (buffer_ && buffer_->text) {
300 owner_->updateLayoutChoice();
306 int BufferView::resizeCurrentBuffer()
308 lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
310 LyXParagraph * par = 0;
311 LyXParagraph * selstartpar = 0;
312 LyXParagraph * selendpar = 0;
321 owner_->getMiniBuffer()->Set(_("Formatting document..."));
325 par = text->cursor.par;
326 pos = text->cursor.pos;
327 selstartpar = text->sel_start_cursor.par;
328 selstartpos = text->sel_start_cursor.pos;
329 selendpar = text->sel_end_cursor.par;
330 selendpos = text->sel_end_cursor.pos;
331 selection = text->selection;
332 mark_set = text->mark_set;
335 text = new LyXText(work_area->w, buffer_);
338 par = buffer_->text->cursor.par;
339 pos = buffer_->text->cursor.pos;
340 selstartpar = buffer_->text->sel_start_cursor.par;
341 selstartpos = buffer_->text->sel_start_cursor.pos;
342 selendpar = buffer_->text->sel_end_cursor.par;
343 selendpos = buffer_->text->sel_end_cursor.pos;
344 selection = buffer_->text->selection;
345 mark_set = buffer_->text->mark_set;
346 delete buffer_->text;
348 buffer_->text = new LyXText(work_area->w, buffer_);
355 text->selection = true;
356 /* at this point just
357 * to avoid the Delete-
360 * setting the cursor */
361 text->mark_set = mark_set;
363 text->SetCursor(selstartpar, selstartpos);
364 text->sel_cursor = text->cursor;
365 text->SetCursor(selendpar, selendpos);
366 text->SetSelection();
367 text->SetCursor(par, pos);
369 text->SetCursor(par, pos);
370 text->sel_cursor = text->cursor;
371 text->selection = false;
376 buffer_->text->selection = true;
377 /* at this point just
378 * to avoid the Delete-
381 * setting the cursor */
382 buffer_->text->mark_set = mark_set;
384 buffer_->text->SetCursor(selstartpar, selstartpos);
385 buffer_->text->sel_cursor = buffer_->text->cursor;
386 buffer_->text->SetCursor(selendpar, selendpos);
387 buffer_->text->SetSelection();
388 buffer_->text->SetCursor(par, pos);
390 buffer_->text->SetCursor(par, pos);
391 buffer_->text->sel_cursor = buffer_->text->cursor;
392 buffer_->text->selection = false;
396 screen->first = screen->TopCursorVisible(); /* this will scroll the
397 * screen such that the
402 owner_->getMiniBuffer()->Init();
405 // Now if the title form still exist kill it
412 void BufferView::gotoError()
417 screen->HideCursor();
427 if (!text->GotoNextError()) {
429 || text->cursor.par != text->FirstParagraph()) {
431 text->cursor.par = text->FirstParagraph();
432 text->cursor.pos = 0;
433 if (!text->GotoNextError()) {
435 owner_->getMiniBuffer()->Set(_("No more errors"));
439 owner_->getMiniBuffer()->Set(_("No more errors"));
444 text->sel_cursor = text->cursor;
446 if (!buffer_->text->GotoNextError()) {
447 if (buffer_->text->cursor.pos
448 || buffer_->text->cursor.par !=
449 buffer_->text->FirstParagraph()) {
450 tmp = buffer_->text->cursor;
451 buffer_->text->cursor.par =
452 buffer_->text->FirstParagraph();
453 buffer_->text->cursor.pos = 0;
454 if (!buffer_->text->GotoNextError()) {
455 buffer_->text->cursor = tmp;
456 owner_->getMiniBuffer()->Set(_("No more errors"));
460 owner_->getMiniBuffer()->Set(_("No more errors"));
465 buffer_->text->sel_cursor =
466 buffer_->text->cursor;
471 // Just a bunch of C wrappers around static members of BufferView
472 extern "C" void C_BufferView_UpCB(FL_OBJECT * ob, long buf) {
473 BufferView::UpCB(ob, buf);
476 extern "C" void C_BufferView_DownCB(FL_OBJECT * ob, long buf) {
477 BufferView::DownCB(ob, buf);
480 extern "C" void C_BufferView_ScrollCB(FL_OBJECT * ob, long buf) {
481 BufferView::ScrollCB(ob, buf);
484 extern "C" void C_BufferView_CursorToggleCB(FL_OBJECT * ob, long buf) {
485 BufferView::CursorToggleCB(ob, buf);
488 extern "C" int C_BufferView_work_area_handler(FL_OBJECT * ob, int event,
490 int key, void * xev) {
491 return BufferView::work_area_handler(ob, event, 0, 0, key, xev);
495 void BufferView::create_view(int xpos, int ypos, int width, int height)
498 const int bw = abs(fl_get_border_width());
500 // a hack for the figinsets (Matthias)
501 // This one first, then it will probably be invisible. (Lgb)
502 ::figinset_canvas = figinset_canvas = obj =
503 fl_add_canvas(FL_NORMAL_CANVAS,
506 fl_set_object_boxtype(obj, FL_NO_BOX);
507 fl_set_object_resize(obj, FL_RESIZE_ALL);
508 fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
511 obj = fl_add_box(FL_BORDER_BOX, xpos, ypos,
514 fl_set_object_resize(obj, FL_RESIZE_ALL);
515 fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
518 work_area = obj = fl_add_free(FL_INPUT_FREE,
520 width-15-2*bw /* scrollbarwidth */,
522 C_BufferView_work_area_handler);
523 obj->wantkey = FL_KEY_TAB;
524 obj->u_vdata = this; /* This is how we pass the BufferView
525 to the work_area_handler. */
526 fl_set_object_boxtype(obj, FL_DOWN_BOX);
527 fl_set_object_resize(obj, FL_RESIZE_ALL);
528 fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
534 // up - scrollbar button
536 fl_set_border_width(-1);
538 fl_set_border_width(-2); // to get visible feedback
540 button_up = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
544 fl_set_object_boxtype(obj, FL_UP_BOX);
545 fl_set_object_color(obj, FL_MCOL, FL_BLUE);
546 fl_set_object_resize(obj, FL_RESIZE_ALL);
547 fl_set_object_gravity(obj, NorthEastGravity, NorthEastGravity);
548 fl_set_object_callback(obj, C_BufferView_UpCB, 0);
550 fl_set_pixmapbutton_data(obj, const_cast<char**>(up_xpm));
553 // Remove the blue feedback rectangle
554 fl_set_pixmapbutton_focus_outline(obj, 0);
557 // the scrollbar slider
558 fl_set_border_width(-bw);
559 scrollbar = obj = fl_add_slider(FL_VERT_SLIDER,
563 fl_set_object_color(obj, FL_COL1, FL_MCOL);
564 fl_set_object_boxtype(obj, FL_UP_BOX);
565 fl_set_object_resize(obj, FL_RESIZE_ALL);
566 fl_set_object_gravity(obj, NorthEastGravity, SouthEastGravity);
567 fl_set_object_callback(obj, C_BufferView_ScrollCB, 0);
570 // down - scrollbar button
572 fl_set_border_width(-1);
574 fl_set_border_width(-2); // to get visible feedback
576 button_down = obj = fl_add_pixmapbutton(FL_TOUCH_BUTTON,
580 fl_set_object_boxtype(obj, FL_UP_BOX);
581 fl_set_object_color(obj, FL_MCOL, FL_BLUE);
582 fl_set_object_resize(obj, FL_RESIZE_ALL);
583 fl_set_object_gravity(obj, SouthEastGravity, SouthEastGravity);
584 fl_set_object_callback(obj, C_BufferView_DownCB, 0);
586 fl_set_pixmapbutton_data(obj, const_cast<char**>(down_xpm));
587 fl_set_border_width(-bw);
590 // Remove the blue feedback rectangle
591 fl_set_pixmapbutton_focus_outline(obj, 0);
599 timer_cursor = obj = fl_add_timer(FL_HIDDEN_TIMER,
600 0, 0, 0, 0, "Timer");
601 fl_set_object_callback(obj, C_BufferView_CursorToggleCB, 0);
606 // Callback for scrollbar up button
607 void BufferView::UpCB(FL_OBJECT * ob, long)
609 BufferView * view = static_cast<BufferView*>(ob->u_vdata);
611 if (view->buffer_ == 0) return;
614 static long time = 0;
615 ev2 = fl_last_event();
616 if (ev2->type == ButtonPress || ev2->type == ButtonRelease)
618 int button = fl_get_button_numb(ob);
621 view->ScrollUpOnePage(time++); break;
623 view->ScrollDownOnePage(time++); break;
625 view->ScrollUp(time++); break;
637 a = XInternAtom(fl_display, "WAIT_FOR_X", False);
640 XSetWindowAttributes attr;
641 mask = CWOverrideRedirect;
642 attr.override_redirect = 1;
643 w = XCreateWindow(fl_display, fl_root,
644 0, 0, 1, 1, 0, CopyFromParent,
645 InputOnly, CopyFromParent, mask, &attr);
646 XSelectInput(fl_display, w, PropertyChangeMask);
647 XMapWindow(fl_display, w);
650 XChangeProperty(fl_display, w, a, a, 8,
651 PropModeAppend, reinterpret_cast<unsigned char*>(""), 0);
652 XWindowEvent(fl_display, w, PropertyChangeMask, &ev);
654 XSync(fl_get_display(), 0);
658 // Callback for scrollbar slider
659 void BufferView::ScrollCB(FL_OBJECT * ob, long)
661 BufferView * view = static_cast<BufferView*>(ob->u_vdata);
662 extern bool cursor_follows_scrollbar;
664 if (view->buffer_ == 0) return;
666 view->current_scrollbar_value = long(fl_get_slider_value(ob));
667 if (view->current_scrollbar_value < 0)
668 view->current_scrollbar_value = 0;
673 view->screen->Draw(view->current_scrollbar_value);
675 if (cursor_follows_scrollbar) {
677 LyXText * vbt = view->text;
679 LyXText * vbt = view->buffer_->text;
681 int height = vbt->DefaultHeight();
683 if (vbt->cursor.y < view->screen->first + height) {
684 vbt->SetCursorFromCoordinates(0,
685 view->screen->first +
688 else if (vbt->cursor.y >
689 view->screen->first + view->work_area->h - height) {
690 vbt->SetCursorFromCoordinates(0,
691 view->screen->first +
700 // Callback for scrollbar down button
701 void BufferView::DownCB(FL_OBJECT * ob, long)
703 BufferView * view = static_cast<BufferView*>(ob->u_vdata);
705 if (view->buffer_ == 0) return;
708 static long time = 0;
709 ev2 = fl_last_event();
710 if (ev2->type == ButtonPress || ev2->type == ButtonRelease)
712 int button = fl_get_button_numb(ob);
715 view->ScrollUpOnePage(time++); break;
717 view->ScrollDownOnePage(time++); break;
719 view->ScrollDown(time++); break;
724 int BufferView::ScrollUp(long time)
726 if (buffer_ == 0) return 0;
730 double value= fl_get_slider_value(scrollbar);
736 float add_value = (text->DefaultHeight()
737 + float(time) * float(time) * 0.125);
739 if (add_value > work_area->h)
740 add_value = float(work_area->h -
741 text->DefaultHeight());
743 float add_value = (buffer_->text->DefaultHeight()
744 + float(time) * float(time) * 0.125);
746 if (add_value > work_area->h)
747 add_value = float(work_area->h -
748 buffer_->text->DefaultHeight());
756 fl_set_slider_value(scrollbar, value);
758 ScrollCB(scrollbar, 0);
763 int BufferView::ScrollDown(long time)
765 if (buffer_ == 0) return 0;
769 double value= fl_get_slider_value(scrollbar);
771 fl_get_slider_bounds(scrollbar, &min, &max);
777 float add_value = (text->DefaultHeight()
778 + float(time) * float(time) * 0.125);
780 if (add_value > work_area->h)
781 add_value = float(work_area->h -
782 text->DefaultHeight());
784 float add_value = (buffer_->text->DefaultHeight()
785 + float(time) * float(time) * 0.125);
787 if (add_value > work_area->h)
788 add_value = float(work_area->h -
789 buffer_->text->DefaultHeight());
797 fl_set_slider_value(scrollbar, value);
799 ScrollCB(scrollbar, 0);
804 void BufferView::ScrollUpOnePage(long /*time*/)
806 if (buffer_ == 0) return;
810 long y = screen->first;
814 Row * row = text->GetRowNearY(y);
816 Row * row = buffer_->text->GetRowNearY(y);
818 y = y - work_area->h + row->height;
820 fl_set_slider_value(scrollbar, y);
822 ScrollCB(scrollbar, 0);
826 void BufferView::ScrollDownOnePage(long /*time*/)
828 if (buffer_ == 0) return;
833 fl_get_slider_bounds(scrollbar, &min, &max);
834 long y = screen->first;
837 if (y > text->height - work_area->h)
841 text->GetRowNearY(y);
843 if (y > buffer_->text->height - work_area->h)
847 buffer_->text->GetRowNearY(y);
849 fl_set_slider_value(scrollbar, y);
851 ScrollCB(scrollbar, 0);
855 int BufferView::work_area_handler(FL_OBJECT * ob, int event,
857 int /*key*/, void *xev)
859 static int x_old = -1;
860 static int y_old = -1;
861 static long scrollbar_value_old = -1;
863 XEvent * ev = static_cast<XEvent*>(xev);
864 BufferView * view = static_cast<BufferView*>(ob->u_vdata);
866 // If we don't have a view yet; return
867 if (!view || quitting) return 0;
871 view->workAreaExpose();
874 view->WorkAreaButtonPress(ob, 0, 0, 0, ev, 0);
877 view->WorkAreaButtonRelease(ob, 0, 0, 0, ev, 0);
880 if (ev->xmotion.x != x_old ||
881 ev->xmotion.y != y_old ||
882 view->current_scrollbar_value != scrollbar_value_old) {
883 x_old = ev->xmotion.x;
884 y_old = ev->xmotion.y;
885 scrollbar_value_old = view->current_scrollbar_value;
886 view->WorkAreaMotionNotify(ob, 0, 0, 0, ev, 0);
889 // Done by the raw callback:
890 // case FL_KEYBOARD: WorkAreaKeyPress(ob, 0, 0, 0, ev, 0); break;
892 if (!view->owner_->getMiniBuffer()->shows_no_match)
893 view->owner_->getMiniBuffer()->Init();
894 view->owner_->getMiniBuffer()->shows_no_match = false;
895 view->work_area_focus = true;
896 fl_set_timer(view->timer_cursor, 0.4);
899 view->owner_->getMiniBuffer()->ExecCommand();
900 view->work_area_focus = false;
903 SetXtermCursor(view->owner_->getForm()->window);
905 view->lyx_focus = true;
906 fl_set_timer(view->timer_cursor, 0.4);
909 if (!input_prohibited)
910 XUndefineCursor(fl_display,
911 view->owner_->getForm()->window);
912 view->lyx_focus = false; // This is not an absolute truth
913 // but if it is not true, it will be changed within a blink
914 // of an eye. ... Not good enough... use regulare timeperiod
915 //fl_set_timer(view->timer_cursor, 0.01); // 0.1 sec blink
916 fl_set_timer(view->timer_cursor, 0.4); // 0.4 sec blink
920 if (view->buffer_ && !view->buffer_->the_locking_inset) {
921 if (view->screen && ev->xbutton.button == 1) {
922 view->screen->HideCursor();
923 view->screen->ToggleSelection();
925 view->text->SelectWord();
927 view->buffer_->text->SelectWord();
929 view->screen->ToggleSelection(false);
930 /* This will fit the cursor on the screen
935 view->buffer_->update(0);
942 if (view->buffer_ && view->screen && ev->xbutton.button == 1) {
943 view->screen->HideCursor();
944 view->screen->ToggleSelection();
946 view->text->CursorHome();
947 view->text->sel_cursor = view->text->cursor;
948 view->text->CursorEnd();
949 view->text->SetSelection();
951 view->buffer_->text->CursorHome();
952 view->buffer_->text->sel_cursor =
953 view->buffer_->text->cursor;
954 view->buffer_->text->CursorEnd();
955 view->buffer_->text->SetSelection();
957 view->screen->ToggleSelection(false);
958 /* This will fit the cursor on the screen
963 view->buffer_->update(0);
968 view->WorkAreaSelectionNotify(ob,
969 view->owner_->getForm()->window,
976 int BufferView::WorkAreaMotionNotify(FL_OBJECT *ob, Window,
977 int /*w*/, int /*h*/,
978 XEvent *ev, void */*d*/)
981 if (buffer_ == 0) return 0;
982 if (!screen) return 0;
984 // Check for inset locking
985 if (buffer_->the_locking_inset) {
987 LyXCursor cursor = text->cursor;
989 LyXCursor cursor = buffer_->text->cursor;
991 buffer_->the_locking_inset->
992 InsetMotionNotify(ev->xbutton.x - ob->x - cursor.x,
993 ev->xbutton.y - ob->y -
999 // Only use motion with button 1
1000 if (!ev->xmotion.state & Button1MotionMask)
1003 /* The selection possible is needed, that only motion events are
1004 * used, where the bottom press event was on the drawing area too */
1005 if (selection_possible) {
1006 screen->HideCursor();
1009 text->SetCursorFromCoordinates(ev->xbutton.x - ob->x,
1010 ev->xbutton.y - ob->y +
1013 if (!text->selection)
1014 update(-3); // Maybe an empty line was deleted
1016 text->SetSelection();
1019 SetCursorFromCoordinates(ev->xbutton.x - ob->x,
1020 ev->xbutton.y - ob->y +
1023 if (!buffer_->text->selection)
1024 buffer_->update(-3); // Maybe an empty line was deleted
1026 buffer_->text->SetSelection();
1028 screen->ToggleToggle();
1029 if (screen->FitCursor())
1031 screen->ShowCursor();
1037 extern int bibitemMaxWidth(LyXFont const &);
1040 // Single-click on work area
1041 int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
1042 int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1047 if (buffer_ == 0) return 0;
1048 if (!screen) return 0;
1050 int const x = ev->xbutton.x - ob->x;
1051 int const y = ev->xbutton.y - ob->y;
1052 // If we hit an inset, we have the inset coordinates in these
1053 // and inset_hit points to the inset. If we do not hit an
1054 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1057 Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1059 // ok ok, this is a hack.
1060 int button = ev->xbutton.button;
1061 if (button == 4 || button == 5) goto wheel;
1065 if (buffer_->the_locking_inset) {
1066 // We are in inset locking mode
1068 /* Check whether the inset was hit. If not reset mode,
1069 otherwise give the event to the inset */
1070 if (inset_hit != 0) {
1071 buffer_->the_locking_inset->
1072 InsetButtonPress(inset_x, inset_y, button);
1075 UnlockInset(buffer_->the_locking_inset);
1079 selection_possible = true;
1080 screen->HideCursor();
1082 // Right button mouse click on a table
1084 (text->cursor.par->table ||
1085 text->MouseHitInTable(x, y + screen->first))) {
1086 // Set the cursor to the press-position
1087 text->SetCursorFromCoordinates(x, y + screen->first);
1090 // Only show the table popup if the hit is in the table, too
1091 if (!text->HitInTable(text->cursor.row, x))
1094 // Hit above or below the table?
1096 if (!text->selection) {
1097 screen->ToggleSelection();
1098 text->ClearSelection();
1099 text->FullRebreak();
1103 // Popup table popup when on a table.
1104 // This is obviously temporary, since we should be
1106 // popup various context-sensitive-menus with the
1107 // the right mouse. So this should be done more
1108 // general in the future. Matthias.
1109 selection_possible = false;
1110 owner_->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
1116 int screen_first = screen->first;
1118 // Middle button press pastes if we have a selection
1119 bool paste_internally = false;
1120 if (button == 2 // && !buffer_->the_locking_inset
1121 && text->selection) {
1122 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
1123 paste_internally = true;
1126 // Clear the selection
1127 screen->ToggleSelection();
1128 text->ClearSelection();
1129 text->FullRebreak();
1133 // Single left click in math inset?
1134 if (inset_hit != 0 && inset_hit->Editable() == 2) {
1135 // Highly editable inset, like math
1136 selection_possible = false;
1137 owner_->updateLayoutChoice();
1138 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1139 inset_hit->Edit(inset_x, inset_y);
1143 // Right click on a footnote flag opens float menu
1145 selection_possible = false;
1149 text->SetCursorFromCoordinates(x, y + screen_first);
1151 text->sel_cursor = text->cursor;
1152 text->cursor.x_fix = text->cursor.x;
1154 owner_->updateLayoutChoice();
1155 if (screen->FitCursor()){
1157 selection_possible = false;
1160 // Insert primary selection with middle mouse
1161 // if there is a local selection in the current buffer, insert this
1162 if (button == 2) { // && !buffer_->the_locking_inset){
1163 if (paste_internally)
1164 owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
1166 owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
1168 selection_possible = false;
1174 // I am not quite sure if this is the correct place to put this,
1175 // but it will not cause any harm.
1176 // Patch from Mark Huang (markman@mit.edu) to make LyX recognise
1177 // button 4 and 5. This enables LyX use use the scrollwhell on
1178 // certain mice for something useful. (Lgb)
1179 // Added wheel acceleration detection code. (Rvdk)
1180 static Time lastTime = 0;
1181 int diff = ev->xbutton.time - lastTime;
1182 int scroll = int(1.0 + (4.0/(abs(diff)+1.0))*200.0);
1191 lastTime = ev->xbutton.time;
1201 // Single-click on work area
1202 int BufferView::WorkAreaButtonPress(FL_OBJECT *ob, Window,
1203 int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1208 if (buffer_ == 0) return 0;
1209 if (!screen) return 0;
1211 int const x = ev->xbutton.x - ob->x;
1212 int const y = ev->xbutton.y - ob->y;
1213 // If we hit an inset, we have the inset coordinates in these
1214 // and inset_hit points to the inset. If we do not hit an
1215 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1218 Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1220 // ok ok, this is a hack.
1221 int button = ev->xbutton.button;
1222 if (button == 4 || button == 5) goto wheel;
1226 if (buffer_->the_locking_inset) {
1227 // We are in inset locking mode
1229 /* Check whether the inset was hit. If not reset mode,
1230 otherwise give the event to the inset */
1231 if (inset_hit != 0) {
1232 buffer_->the_locking_inset->
1233 InsetButtonPress(inset_x, inset_y, button);
1236 UnlockInset(buffer_->the_locking_inset);
1240 selection_possible = true;
1241 screen->HideCursor();
1243 // Right button mouse click on a table
1245 (buffer_->text->cursor.par->table ||
1246 buffer_->text->MouseHitInTable(x, y+screen->first))) {
1247 // Set the cursor to the press-position
1248 buffer_->text->SetCursorFromCoordinates(x, y + screen->first);
1251 // Only show the table popup if the hit is in the table, too
1252 if (!buffer_->text->HitInTable(buffer_->text->cursor.row, x))
1255 // Hit above or below the table?
1257 if (!buffer_->text->selection) {
1258 screen->ToggleSelection();
1259 buffer_->text->ClearSelection();
1260 buffer_->text->FullRebreak();
1264 // Popup table popup when on a table.
1265 // This is obviously temporary, since we should be
1267 // popup various context-sensitive-menus with the
1268 // the right mouse. So this should be done more
1269 // general in the future. Matthias.
1270 selection_possible = false;
1271 owner_->getLyXFunc()->Dispatch(LFUN_LAYOUT_TABLE,
1277 int screen_first = screen->first;
1279 // Middle button press pastes if we have a selection
1280 bool paste_internally = false;
1281 if (button == 2 // && !buffer_->the_locking_inset
1282 && buffer_->text->selection) {
1283 owner_->getLyXFunc()->Dispatch(LFUN_COPY);
1284 paste_internally = true;
1287 // Clear the selection
1288 screen->ToggleSelection();
1289 buffer_->text->ClearSelection();
1290 buffer_->text->FullRebreak();
1294 // Single left click in math inset?
1295 if (inset_hit != 0 && inset_hit->Editable() == 2) {
1296 // Highly editable inset, like math
1297 selection_possible = false;
1298 owner_->updateLayoutChoice();
1299 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1300 inset_hit->Edit(inset_x, inset_y);
1304 // Right click on a footnote flag opens float menu
1306 selection_possible = false;
1310 buffer_->text->SetCursorFromCoordinates(x, y + screen_first);
1311 buffer_->text->FinishUndo();
1312 buffer_->text->sel_cursor = buffer_->text->cursor;
1313 buffer_->text->cursor.x_fix = buffer_->text->cursor.x;
1315 owner_->updateLayoutChoice();
1316 if (screen->FitCursor()){
1318 selection_possible = false;
1321 // Insert primary selection with middle mouse
1322 // if there is a local selection in the current buffer, insert this
1323 if (button == 2) { // && !buffer_->the_locking_inset){
1324 if (paste_internally)
1325 owner_->getLyXFunc()->Dispatch(LFUN_PASTE);
1327 owner_->getLyXFunc()->Dispatch(LFUN_PASTESELECTION,
1329 selection_possible = false;
1335 // I am not quite sure if this is the correct place to put this,
1336 // but it will not cause any harm.
1337 // Patch from Mark Huang (markman@mit.edu) to make LyX recognise
1338 // button 4 and 5. This enables LyX use use the scrollwhell on
1339 // certain mice for something useful. (Lgb)
1340 // Added wheel acceleration detection code. (Rvdk)
1341 static Time lastTime = 0;
1342 int diff = ev->xbutton.time - lastTime;
1343 int scroll = int(1.0 + (4.0/(abs(diff)+1.0))*200.0);
1352 lastTime = ev->xbutton.time;
1364 int BufferView::WorkAreaButtonRelease(FL_OBJECT * ob, Window ,
1365 int /*w*/, int /*h*/, XEvent * ev, void * /*d*/)
1367 if (buffer_ == 0 || screen == 0) return 0;
1369 int const x = ev->xbutton.x - ob->x;
1370 int const y = ev->xbutton.y - ob->y;
1372 // If we hit an inset, we have the inset coordinates in these
1373 // and inset_hit points to the inset. If we do not hit an
1374 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1377 Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1379 if (buffer_->the_locking_inset) {
1380 // We are in inset locking mode.
1382 /* LyX does a kind of work-area grabbing for insets.
1383 Only a ButtonPress Event outside the inset will
1384 force a InsetUnlock. */
1385 buffer_->the_locking_inset->
1386 InsetButtonRelease(inset_x, inset_y,
1387 ev->xbutton.button);
1391 selection_possible = false;
1392 if (text->cursor.par->table) {
1394 NumberOfCell(text->cursor.par,
1396 if (text->cursor.par->table->IsContRow(cell) &&
1397 text->cursor.par->table->
1398 CellHasContRow(text->cursor.par->table->
1399 GetCellAbove(cell))<0) {
1404 if (ev->xbutton.button >= 2)
1407 // Make sure that the press was not far from the release
1408 if ((abs(last_click_x - x) >= 5) ||
1409 (abs(last_click_y - y) >= 5)) {
1413 // Did we hit an editable inset?
1414 if (inset_hit != 0) {
1415 // Inset like error, notes and figures
1416 selection_possible = false;
1417 #ifdef WITH_WARNINGS
1418 #warning fix this proper in 0.13
1420 // Following a ref shouldn't issue
1421 // a push on the undo-stack
1422 // anylonger, now that we have
1423 // keybindings for following
1424 // references and returning from
1425 // references. IMHO though, it
1426 // should be the inset's own business
1427 // to push or not push on the undo
1428 // stack. They don't *have* to
1429 // alter the document...
1431 // ...or maybe the SetCursorParUndo()
1432 // below isn't necessary at all anylonger?
1433 if (inset_hit->LyxCode() == Inset::REF_CODE) {
1434 text->SetCursorParUndo();
1437 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1438 inset_hit->Edit(inset_x, inset_y);
1442 // check whether we want to open a float
1446 if (text->cursor.pos <
1447 text->cursor.par->Last()) {
1448 c = text->cursor.par->
1449 GetChar(text->cursor.pos);
1451 if (c == LyXParagraph::META_FOOTNOTE
1452 || c == LyXParagraph::META_MARGIN
1453 || c == LyXParagraph::META_FIG
1454 || c == LyXParagraph::META_TAB
1455 || c == LyXParagraph::META_WIDE_FIG
1456 || c == LyXParagraph::META_WIDE_TAB
1457 || c == LyXParagraph::META_ALGORITHM){
1459 } else if (text->cursor.pos - 1 >= 0) {
1460 c = text->cursor.par->
1461 GetChar(text->cursor.pos - 1);
1462 if (c == LyXParagraph::META_FOOTNOTE
1463 || c == LyXParagraph::META_MARGIN
1464 || c == LyXParagraph::META_FIG
1465 || c == LyXParagraph::META_TAB
1466 || c == LyXParagraph::META_WIDE_FIG
1467 || c == LyXParagraph::META_WIDE_TAB
1468 || c == LyXParagraph::META_ALGORITHM){
1469 // We are one step too far to the right
1476 selection_possible = false;
1481 // Do we want to close a float? (click on the float-label)
1482 if (text->cursor.row->par->footnoteflag ==
1483 LyXParagraph::OPEN_FOOTNOTE
1484 && text->cursor.pos == 0
1485 && text->cursor.row->previous &&
1486 text->cursor.row->previous->par->
1487 footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
1488 LyXFont font (LyXFont::ALL_SANE);
1489 font.setSize(LyXFont::SIZE_SMALL);
1491 int box_x = 20; // LYX_PAPER_MARGIN;
1492 box_x += font.textWidth("Mwide-figM", 10);
1494 int screen_first = screen->first;
1497 && y + screen_first > text->cursor.y -
1498 text->cursor.row->baseline
1499 && y + screen_first < text->cursor.y -
1500 text->cursor.row->baseline
1501 + font.maxAscent()*1.2 + font.maxDescent()*1.2) {
1503 selection_possible = false;
1508 // Maybe we want to edit a bibitem ale970302
1509 if (text->cursor.par->bibkey && x < 20 +
1510 bibitemMaxWidth(textclasslist.TextClass(buffer_->
1511 params.textclass).defaultfont())) {
1512 text->cursor.par->bibkey->Edit(0, 0);
1518 int BufferView::WorkAreaButtonRelease(FL_OBJECT *ob, Window ,
1519 int /*w*/, int /*h*/, XEvent *ev, void */*d*/)
1521 if (buffer_ == 0 || screen == 0) return 0;
1523 int const x = ev->xbutton.x - ob->x;
1524 int const y = ev->xbutton.y - ob->y;
1526 // If we hit an inset, we have the inset coordinates in these
1527 // and inset_hit points to the inset. If we do not hit an
1528 // inset, inset_hit is 0, and inset_x == x, inset_y == y.
1531 Inset * inset_hit = checkInsetHit(inset_x, inset_y);
1533 if (buffer_->the_locking_inset) {
1534 // We are in inset locking mode.
1536 /* LyX does a kind of work-area grabbing for insets.
1537 Only a ButtonPress Event outside the inset will
1538 force a InsetUnlock. */
1539 buffer_->the_locking_inset->
1540 InsetButtonRelease(inset_x, inset_y,
1541 ev->xbutton.button);
1545 selection_possible = false;
1546 if (buffer_->text->cursor.par->table) {
1547 int cell = buffer_->text->
1548 NumberOfCell(buffer_->text->cursor.par,
1549 buffer_->text->cursor.pos);
1550 if (buffer_->text->cursor.par->table->IsContRow(cell) &&
1551 buffer_->text->cursor.par->table->
1552 CellHasContRow(buffer_->text->cursor.par->table->
1553 GetCellAbove(cell))<0) {
1554 buffer_->text->CursorUp();
1558 if (ev->xbutton.button >= 2)
1561 // Make sure that the press was not far from the release
1562 if ((abs(last_click_x - x) >= 5) ||
1563 (abs(last_click_y - y) >= 5)) {
1567 // Did we hit an editable inset?
1568 if (inset_hit != 0) {
1569 // Inset like error, notes and figures
1570 selection_possible = false;
1571 #ifdef WITH_WARNINGS
1572 #warning fix this proper in 0.13
1574 // Following a ref shouldn't issue
1575 // a push on the undo-stack
1576 // anylonger, now that we have
1577 // keybindings for following
1578 // references and returning from
1579 // references. IMHO though, it
1580 // should be the inset's own business
1581 // to push or not push on the undo
1582 // stack. They don't *have* to
1583 // alter the document...
1585 // ...or maybe the SetCursorParUndo()
1586 // below isn't necessary at all anylonger?
1587 if (inset_hit->LyxCode() == Inset::REF_CODE) {
1588 buffer_->text->SetCursorParUndo();
1591 owner_->getMiniBuffer()->Set(inset_hit->EditMessage());
1592 inset_hit->Edit(inset_x, inset_y);
1596 // check whether we want to open a float
1597 if (buffer_->text) {
1600 if (buffer_->text->cursor.pos <
1601 buffer_->text->cursor.par->Last()) {
1602 c = buffer_->text->cursor.par->
1603 GetChar(buffer_->text->cursor.pos);
1605 if (c == LyXParagraph::META_FOOTNOTE
1606 || c == LyXParagraph::META_MARGIN
1607 || c == LyXParagraph::META_FIG
1608 || c == LyXParagraph::META_TAB
1609 || c == LyXParagraph::META_WIDE_FIG
1610 || c == LyXParagraph::META_WIDE_TAB
1611 || c == LyXParagraph::META_ALGORITHM){
1613 } else if (buffer_->text->cursor.pos - 1 >= 0) {
1614 c = buffer_->text->cursor.par->
1615 GetChar(buffer_->text->cursor.pos - 1);
1616 if (c == LyXParagraph::META_FOOTNOTE
1617 || c == LyXParagraph::META_MARGIN
1618 || c == LyXParagraph::META_FIG
1619 || c == LyXParagraph::META_TAB
1620 || c == LyXParagraph::META_WIDE_FIG
1621 || c == LyXParagraph::META_WIDE_TAB
1622 || c == LyXParagraph::META_ALGORITHM){
1623 // We are one step too far to the right
1624 buffer_->text->CursorLeft();
1630 selection_possible = false;
1635 // Do we want to close a float? (click on the float-label)
1636 if (buffer_->text->cursor.row->par->footnoteflag ==
1637 LyXParagraph::OPEN_FOOTNOTE
1638 && buffer_->text->cursor.pos == 0
1639 && buffer_->text->cursor.row->previous &&
1640 buffer_->text->cursor.row->previous->par->
1641 footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
1642 LyXFont font (LyXFont::ALL_SANE);
1643 font.setSize(LyXFont::SIZE_SMALL);
1645 int box_x = 20; // LYX_PAPER_MARGIN;
1646 box_x += font.textWidth("Mwide-figM", 10);
1648 int screen_first = screen->first;
1651 && y + screen_first > buffer_->text->cursor.y -
1652 buffer_->text->cursor.row->baseline
1653 && y + screen_first < buffer_->text->cursor.y -
1654 buffer_->text->cursor.row->baseline
1655 + font.maxAscent()*1.2 + font.maxDescent()*1.2) {
1657 selection_possible = false;
1662 // Maybe we want to edit a bibitem ale970302
1663 if (buffer_->text->cursor.par->bibkey && x < 20 +
1664 bibitemMaxWidth(textclasslist.TextClass(buffer_->
1665 params.textclass).defaultfont())) {
1666 buffer_->text->cursor.par->bibkey->Edit(0, 0);
1674 * Returns an inset if inset was hit. 0 otherwise.
1675 * If hit, the coordinates are changed relative to the inset.
1676 * Otherwise coordinates are not changed, and false is returned.
1679 Inset * BufferView::checkInsetHit(int & x, int & y)
1684 int y_tmp = y + getScreen()->first;
1686 LyXCursor cursor = text->cursor;
1687 if (cursor.pos < cursor.par->Last()
1688 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
1689 && cursor.par->GetInset(cursor.pos)
1690 && cursor.par->GetInset(cursor.pos)->Editable()) {
1692 // Check whether the inset really was hit
1693 Inset * tmpinset = cursor.par->GetInset(cursor.pos);
1694 LyXFont font = text->GetFont(cursor.par, cursor.pos);
1696 && x < cursor.x + tmpinset->Width(font)
1697 && y_tmp > cursor.y - tmpinset->Ascent(font)
1698 && y_tmp < cursor.y + tmpinset->Descent(font)) {
1700 // The origin of an inset is on the baseline
1701 y = y_tmp - (cursor.y);
1704 } else if (cursor.pos - 1 >= 0
1705 && cursor.par->GetChar(cursor.pos - 1) == LyXParagraph::META_INSET
1706 && cursor.par->GetInset(cursor.pos - 1)
1707 && cursor.par->GetInset(cursor.pos - 1)->Editable()) {
1709 Inset * result = checkInsetHit(x, y);
1711 text->CursorRight();
1720 Inset * BufferView::checkInsetHit(int & x, int & y)
1725 int y_tmp = y + getScreen()->first;
1727 LyXCursor cursor = buffer_->text->cursor;
1728 if (cursor.pos < cursor.par->Last()
1729 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
1730 && cursor.par->GetInset(cursor.pos)
1731 && cursor.par->GetInset(cursor.pos)->Editable()) {
1733 // Check whether the inset really was hit
1734 Inset * tmpinset = cursor.par->GetInset(cursor.pos);
1735 LyXFont font = buffer_->text->GetFont(cursor.par, cursor.pos);
1737 && x < cursor.x + tmpinset->Width(font)
1738 && y_tmp > cursor.y - tmpinset->Ascent(font)
1739 && y_tmp < cursor.y + tmpinset->Descent(font)) {
1741 // The origin of an inset is on the baseline
1742 y = y_tmp - (cursor.y);
1745 } else if (cursor.pos - 1 >= 0
1746 && cursor.par->GetChar(cursor.pos - 1) == LyXParagraph::META_INSET
1747 && cursor.par->GetInset(cursor.pos - 1)
1748 && cursor.par->GetInset(cursor.pos - 1)->Editable()) {
1749 buffer_->text->CursorLeft();
1750 Inset * result = checkInsetHit(x, y);
1752 buffer_->text->CursorRight();
1762 int BufferView::workAreaExpose()
1764 if (!work_area || !work_area->form->visible)
1767 // this is a hack to ensure that we only call this through
1768 // BufferView::redraw().
1773 static int work_area_width = work_area->w;
1774 static int work_area_height = work_area->h;
1776 bool widthChange = work_area->w != work_area_width;
1777 bool heightChange = work_area->h != work_area_height;
1779 // update from work area
1780 work_area_width = work_area->w;
1781 work_area_height = work_area->h;
1784 // All buffers need a resize
1785 bufferlist.resize();
1786 } else if (heightChange) {
1787 // Rebuild image of current screen
1789 // fitCursor() ensures we don't jump back
1790 // to the start of the document on vertical
1794 // The main window size has changed, repaint most stuff
1796 // ...including the minibuffer
1797 owner_->getMiniBuffer()->Init();
1799 } else if (screen) screen->Redraw();
1801 // Grey box when we don't have a buffer
1802 fl_winset(FL_ObjWin(work_area));
1803 fl_rectangle(1, work_area->x, work_area->y,
1804 work_area->w, work_area->h, FL_GRAY63);
1807 // always make sure that the scrollbar is sane.
1809 owner_->updateLayoutChoice();
1814 // Callback for cursor timer
1815 void BufferView::CursorToggleCB(FL_OBJECT * ob, long)
1817 BufferView *view = static_cast<BufferView*>(ob->u_vdata);
1819 /* quite a nice place for asyncron Inset updating, isn't it? */
1820 // actually no! This is run even if no buffer exist... so (Lgb)
1821 if (view && !view->buffer_) {
1822 goto set_timer_and_return;
1826 // On my quest to solve the gs rendre hangups I am now
1827 // disabling the SIGHUP completely, and will do a wait
1828 // now and then instead. If the guess that xforms somehow
1829 // destroys something is true, this is likely (hopefully)
1830 // to solve the problem...at least I hope so. Lgb
1832 // ...Ok this seems to work...at least it does not make things
1833 // worse so far. However I still see gs processes that hangs.
1834 // I would really like to know _why_ they are hanging. Anyway
1835 // the solution without the SIGCHLD handler seems to be easier
1838 // When attaching gdb to a a running gs that hangs it shows
1839 // that it is waiting for input(?) Is it possible for us to
1840 // provide that input somehow? Or figure what it is expecing
1843 // One solution is to, after some time, look if there are some
1844 // old gs processes still running and if there are: kill them
1847 // Another solution is to provide the user an option to rerender
1848 // a picture. This would, for the picture in question, check if
1849 // there is a gs running for it, if so kill it, and start a new
1850 // rendering process.
1852 // these comments posted to lyx@via
1855 int pid = waitpid((pid_t)0, &status, WNOHANG);
1856 if (pid == -1) // error find out what is wrong
1857 ; // ignore it for now.
1859 sigchldhandler(pid, &status);
1861 if (InsetUpdateList)
1862 UpdateInsetUpdateList();
1864 if (view && !view->screen){
1865 goto set_timer_and_return;
1868 if (view->lyx_focus && view->work_area_focus) {
1869 if (!view->buffer_->the_locking_inset){
1870 view->screen->CursorToggle();
1872 view->buffer_->the_locking_inset->
1873 ToggleInsetCursor();
1875 goto set_timer_and_return;
1877 // Make sure that the cursor is visible.
1878 if (!view->buffer_->the_locking_inset){
1879 view->screen->ShowCursor();
1881 if (!view->buffer_->the_locking_inset->isCursorVisible())
1882 view->buffer_->the_locking_inset->
1883 ToggleInsetCursor();
1886 // This is only run when work_area_focus or lyx_focus is false.
1889 XGetInputFocus(fl_display, &tmpwin, &tmp);
1890 if (lyxerr.debugging()) {
1891 lyxerr << "tmpwin: " << tmpwin
1892 << "\nwindow: " << view->owner_->getForm()->window
1893 << "\nwork_area_focus: " << view->work_area_focus
1894 << "\nlyx_focus : " << view->lyx_focus
1897 if (tmpwin != view->owner_->getForm()->window) {
1898 view->lyx_focus = false;
1901 view->lyx_focus = true;
1902 if (!view->work_area_focus)
1905 goto set_timer_and_return;
1909 set_timer_and_return:
1910 fl_set_timer(ob, 0.4);
1916 int BufferView::WorkAreaSelectionNotify(FL_OBJECT *, Window win,
1917 int /*w*/, int /*h*/, XEvent *event, void */*d*/)
1919 if (buffer_ == 0) return 0;
1920 if (event->type != SelectionNotify)
1926 unsigned char * uc = 0;
1928 screen->HideCursor();
1930 if (event->xselection.type == XA_STRING
1931 && event->xselection.property) {
1933 if (XGetWindowProperty(
1934 fl_display /* display */,
1936 event->xselection.property /* property */,
1937 0 /* long_offset */,
1938 0 /* long_length */,
1940 XA_STRING /* req_type */,
1941 &tmpatom /* actual_type_return */,
1942 &tmpint /* actual_format_return */,
1943 &ul1 /* nitems_return */,
1944 &ul2 /* bytes_after_return */,
1945 &uc /* prop_return */
1956 if (XGetWindowProperty(
1957 fl_display /* display */,
1959 event->xselection.property /* property */,
1960 0 /* long_offset */,
1961 ul2/4+1 /* long_length */,
1963 XA_STRING /* req_type */,
1964 &tmpatom /* actual_type_return */,
1965 &tmpint /* actual_format_return */,
1966 &ul1 /* nitems_return */,
1967 &ul2 /* bytes_after_return */,
1968 &uc /* prop_return */
1977 text->InsertStringA(reinterpret_cast<char*>(uc));
1979 text->InsertStringB(reinterpret_cast<char*>(uc));
1984 InsertStringA(reinterpret_cast<char*>(uc));
1987 InsertStringB(reinterpret_cast<char*>(uc));
2005 void BufferView::cursorPrevious()
2007 if (!text->cursor.row->previous) return;
2009 long y = getScreen()->first;
2010 Row * cursorrow = text->cursor.row;
2011 text->SetCursorFromCoordinates(text->cursor.x_fix, y);
2013 // this is to allow jumping over large insets
2014 if ((cursorrow == text->cursor.row))
2017 if (text->cursor.row->height < work_area->h)
2018 getScreen()->Draw(text->cursor.y
2019 - text->cursor.row->baseline
2020 + text->cursor.row->height
2021 - work_area->h +1 );
2025 void BufferView::cursorNext()
2027 if (!text->cursor.row->next) return;
2029 long y = getScreen()->first;
2030 text->GetRowNearY(y);
2031 Row * cursorrow = text->cursor.row;
2032 text->SetCursorFromCoordinates(text->cursor.x_fix, y + work_area->h);
2034 /* this is to allow jumping over large insets */
2035 if ((cursorrow == text->cursor.row))
2038 if (text->cursor.row->height < work_area->h)
2039 getScreen()->Draw(text->cursor.y
2040 - text->cursor.row->baseline);
2043 void BufferView::cursorPrevious()
2045 if (!buffer()->text->cursor.row->previous) return;
2047 long y = getScreen()->first;
2048 Row * cursorrow = buffer()->text->cursor.row;
2050 SetCursorFromCoordinates(buffer()->text->
2053 buffer()->text->FinishUndo();
2054 // this is to allow jumping over large insets
2055 if ((cursorrow == buffer()->text->cursor.row))
2056 buffer()->text->CursorUp();
2058 if (buffer()->text->cursor.row->height < work_area->h)
2059 getScreen()->Draw(buffer()->text->cursor.y
2060 - buffer()->text->cursor.row->baseline
2061 + buffer()->text->cursor.row->height
2062 - work_area->h +1 );
2066 void BufferView::cursorNext()
2068 if (!buffer()->text->cursor.row->next) return;
2070 long y = getScreen()->first;
2071 buffer()->text->GetRowNearY(y);
2072 Row * cursorrow = buffer()->text->cursor.row;
2074 SetCursorFromCoordinates(buffer()->text->
2077 buffer()->text->FinishUndo();
2078 /* this is to allow jumping over large insets */
2079 if ((cursorrow == buffer()->text->cursor.row))
2080 buffer()->text->CursorDown();
2082 if (buffer()->text->cursor.row->height < work_area->h)
2083 getScreen()->Draw(buffer()->text->cursor.y
2084 - buffer()->text->cursor.row->baseline);
2088 bool BufferView::available() const
2091 if (buffer_ && text) return true;
2093 if (buffer_ && buffer_->text) return true;
2099 void BufferView::savePosition()
2102 backstack.push(buffer()->fileName(),
2106 backstack.push(buffer()->getFileName(),
2107 buffer()->text->cursor.x,
2108 buffer()->text->cursor.y);
2113 void BufferView::restorePosition()
2115 if (backstack.empty()) return;
2118 string fname = backstack.pop(&x, &y);
2121 Buffer * b = (bufferlist.exists(fname)) ? bufferlist.getBuffer(fname):
2122 bufferlist.loadLyXFile(fname); // don't ask, just load it
2125 text->SetCursorFromCoordinates(x, y);
2128 buffer()->text->SetCursorFromCoordinates(x, y);
2129 buffer()->update(0);
2135 // candidate for move to BufferView
2136 void BufferView::update(signed char f)
2138 owner()->updateLayoutChoice();
2140 if (!text->selection && f > -3)
2141 text->sel_cursor = text->cursor;
2144 text->FullRebreak();
2148 if (f != 3 && f != -3) {
2153 if (f == 1 || f == -1) {
2154 if (buffer()->isLyxClean()) {
2155 buffer()->markDirty();
2156 owner()->getMiniBuffer()->setTimer(4);
2158 buffer()->markDirty();