X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FWorkArea.C;h=232e2e1651cf2f64688d471dcb43fdf8fb990d55;hb=98c966c64594611e469313314abd1e59524adb4a;hp=85268e6d23e0aae9716e19bfc38615b03cd47323;hpb=85f8bf7445db373d95bad64faede475e0f6f9049;p=lyx.git diff --git a/src/WorkArea.C b/src/WorkArea.C index 85268e6d23..232e2e1651 100644 --- a/src/WorkArea.C +++ b/src/WorkArea.C @@ -1,89 +1,96 @@ /* This file is part of * ====================================================== - * + * * LyX, The Document Processor - * + * * Copyright 1995 Matthias Ettrich - * Copyright 1995-2000 The LyX Team. + * Copyright 1995-2001 The LyX Team. * * ====================================================== */ #include -#include -#include + #ifdef __GNUG__ #pragma implementation #endif #include "WorkArea.h" #include "debug.h" -#include "support/lstrings.h" -#include "BufferView.h" #include "LyXView.h" -#include "lyxfunc.h" +#include "lyxrc.h" // lyxrc.show_banner +#include "version.h" // lyx_version -#if FL_REVISION < 89 +#if FL_REVISION < 89 || (FL_REVISION == 89 && FL_FIXLEVEL < 5) #include "lyxlookup.h" #endif -using std::endl; +#include "support/filetools.h" // LibFileSearch +#include "support/lstrings.h" +#include "support/LAssert.h" -FL_OBJECT * figinset_canvas; +#include +#include -// needed to make the c++ compiler find the correct version of abs. -// This is at least true for g++. -//using std::abs; +// xforms doesn't define this (but it should be in ). +extern "C" +FL_APPEVENT_CB fl_set_preemptive_callback(Window, FL_APPEVENT_CB, void *); -static inline +using std::endl; +using std::abs; +using std::hex; + +namespace { + +inline void waitForX() { XSync(fl_get_display(), 0); } +} // anon namespace + extern "C" { -// Just a bunch of C wrappers around static members of WorkArea + // Just a bunch of C wrappers around static members of WorkArea + static void C_WorkArea_scroll_cb(FL_OBJECT * ob, long buf) - { + { WorkArea::scroll_cb(ob, buf); - } + } + + static int C_WorkArea_work_area_handler(FL_OBJECT * ob, int event, - FL_Coord, FL_Coord, - int key, void * xev) - { + FL_Coord, FL_Coord, + int key, void * xev) + { return WorkArea::work_area_handler(ob, event, 0, 0, key, xev); - } -} + } + static + int C_WorkAreaEventCB(FL_FORM * form, void * xev) { + WorkArea * wa = static_cast(form->u_vdata); + return wa->event_cb(static_cast(xev)); + } +} -WorkArea::WorkArea(BufferView * o, int xpos, int ypos, int width, int height) - : owner_(o), workareapixmap(0), painter_(*this) +WorkArea::WorkArea(int xpos, int ypos, int width, int height) + : splash_(0), splash_text_(0), workareapixmap(0), painter_(*this) { fl_freeze_all_forms(); - figinset_canvas = 0; - - if (lyxerr.debugging(Debug::GUI)) + if (lyxerr.debugging(Debug::WORKAREA)) lyxerr << "Creating work area: +" << xpos << '+' << ypos << ' ' << width << 'x' << height << endl; // FL_OBJECT * obj; - const int bw = int(std::abs(float(fl_get_border_width()))); + int const bw = int(abs(fl_get_border_width())); - // We really want to get rid of figinset_canvas. - ::figinset_canvas = figinset_canvas = obj = - fl_add_canvas(FL_NORMAL_CANVAS, - xpos + 1, ypos + 1, 1, 1, ""); - fl_set_object_boxtype(obj, FL_NO_BOX); - fl_set_object_resize(obj, FL_RESIZE_ALL); - fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity); - // a box - if (lyxerr.debugging(Debug::GUI)) + if (lyxerr.debugging(Debug::WORKAREA)) lyxerr << "\tbackground box: +" << xpos << '+' << ypos << ' ' << width - 15 << 'x' << height << endl; @@ -94,6 +101,37 @@ WorkArea::WorkArea(BufferView * o, int xpos, int ypos, int width, int height) fl_set_object_resize(obj, FL_RESIZE_ALL); fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity); + // Add a splash screen to the centre of the work area + string const splash_file = (lyxrc.show_banner) ? + LibFileSearch("images", "banner", "xpm") : string(); + + if (!splash_file.empty()) { + int const splash_w = 425; + int const splash_h = 290; + int const splash_x = xpos + (width - 15 - splash_w) / 2; + int const splash_y = ypos + (height - splash_h) / 2; + splash_ = obj = + fl_add_pixmapbutton(FL_NORMAL_BUTTON, + splash_x, splash_y, + splash_w, splash_h, ""); + fl_set_pixmapbutton_file(obj, splash_file.c_str()); + fl_set_pixmapbutton_focus_outline(obj, 3); + fl_set_object_boxtype(obj, FL_NO_BOX); + + int const text_x = splash_x + 260; + int const text_y = splash_y + 255; + splash_text_ = obj = + fl_add_text(FL_NORMAL_TEXT, text_x, text_y, 160, 16, + lyx_version); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_mapcolor(FL_FREE_COL2, 0x2b, 0x47, 0x82); + fl_mapcolor(FL_FREE_COL3, 0xe1, 0xd2, 0x9b); + fl_set_object_color(obj, FL_FREE_COL2, FL_FREE_COL2); + fl_set_object_lcol(obj, FL_FREE_COL3); + fl_set_object_lalign(obj, FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + fl_set_object_lstyle(obj, FL_BOLD_STYLE); + } + // // THE SCROLLBAR // @@ -106,6 +144,7 @@ WorkArea::WorkArea(BufferView * o, int xpos, int ypos, int width, int height) fl_set_object_gravity(obj, NorthEastGravity, SouthEastGravity); obj->u_vdata = this; fl_set_object_callback(obj, C_WorkArea_scroll_cb, 0); + setScrollbarBounds(0.0, 0.0); /// /// The free object @@ -115,12 +154,12 @@ WorkArea::WorkArea(BufferView * o, int xpos, int ypos, int width, int height) // We add this object as late as possible to avoit problems // with drawing. - if (lyxerr.debugging(Debug::GUI)) + if (lyxerr.debugging(Debug::WORKAREA)) lyxerr << "\tfree object: +" << xpos + bw << '+' << ypos + bw << ' ' << width - 15 - 2 * bw << 'x' << height - 2 * bw << endl; - + work_area = obj = fl_add_free(FL_ALL_FREE, xpos + bw, ypos + bw, width - 15 - 2 * bw, // scrollbarwidth @@ -133,6 +172,10 @@ WorkArea::WorkArea(BufferView * o, int xpos, int ypos, int width, int height) fl_set_object_resize(obj, FL_RESIZE_ALL); fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity); + /// X selection hook - xforms gets it wrong + fl_current_form->u_vdata = this; + fl_register_raw_callback(fl_current_form, FL_ALL_EVENT, C_WorkAreaEventCB); + fl_unfreeze_all_forms(); } @@ -156,24 +199,18 @@ bool WorkArea::belowMouse() const if (x > ulx && y > uly && x < ulx + h && y < uly + w) return true; return false; - - - //lyxerr << "Mouse: (" << x << ", " << y <<") button = " << button << endl; - //lyxerr << "Workarea: (" << work_area->x + work_area->form->x << ", " << work_area->y + work_area->form->y << ", " << work_area->w << ", " << work_area->h << ")" << endl; - //lyxerr << "Below mouse: " << work_area->belowmouse << endl; - //return work_area->belowmouse; } void WorkArea::resize(int xpos, int ypos, int width, int height) { fl_freeze_all_forms(); - - const int bw = int(std::abs(float(fl_get_border_width()))); + + int const bw = int(abs(fl_get_border_width())); // a box fl_set_object_geometry(backgroundbox, xpos, ypos, width - 15, height); - + // // THE SCROLLBAR // @@ -189,43 +226,69 @@ void WorkArea::resize(int xpos, int ypos, int width, int height) height - 2 * bw); fl_unfreeze_all_forms(); +} + + +namespace { +void destroy_object(FL_OBJECT * obj) +{ + if (!obj) + return; + if (obj->visible) { + fl_hide_object(obj); + } + fl_delete_object(obj); + fl_free_object(obj); } +} // namespace anon void WorkArea::createPixmap(int width, int height) { + // Three calls to createPixmap are needed to draw the initial view + // of LyX. Any more and the splash is destroyed. + static int counter = 0; + if (++counter == 4) { + destroy_object(splash_); + splash_ = 0; + destroy_object(splash_text_); + splash_text_ = 0; + } + static int cur_width = -1; static int cur_height = -1; if (cur_width == width && cur_height == height && workareapixmap) return; - + cur_width = width; cur_height = height; if (workareapixmap) XFreePixmap(fl_get_display(), workareapixmap); - if (lyxerr.debugging(Debug::GUI)) + if (lyxerr.debugging(Debug::WORKAREA)) lyxerr << "Creating pixmap (" << width << 'x' << height << ")" << endl; - + workareapixmap = XCreatePixmap(fl_get_display(), RootWindow(fl_get_display(), 0), width, - height, + height, fl_get_visual_depth()); - if (lyxerr.debugging(Debug::GUI)) + if (lyxerr.debugging(Debug::WORKAREA)) lyxerr << "\tpixmap=" << workareapixmap << endl; } void WorkArea::greyOut() const { - fl_winset(FL_ObjWin(work_area)); - fl_rectangle(1, work_area->x, work_area->y, - work_area->w, work_area->h, FL_GRAY63); + if (!splash_) { + fl_winset(FL_ObjWin(work_area)); + fl_rectangle(1, work_area->x, work_area->y, + work_area->w, work_area->h, FL_GRAY63); + } } @@ -261,13 +324,11 @@ void WorkArea::scroll_cb(FL_OBJECT * ob, long) // If we really want the accellerating scroll we can do that // from here. IMHO that is a waste of effort since we already // have other ways to move fast around in the document. (Lgb) - area->owner_->scrollCB(fl_get_scrollbar_value(ob)); + area->scrollCB(fl_get_scrollbar_value(ob)); waitForX(); } -bool Lgb_bug_find_hack = false; - int WorkArea::work_area_handler(FL_OBJECT * ob, int event, FL_Coord, FL_Coord , int key, void * xev) @@ -275,36 +336,34 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, static int x_old = -1; static int y_old = -1; static long scrollbar_value_old = -1; - + XEvent * ev = static_cast(xev); WorkArea * area = static_cast(ob->u_vdata); if (!area) return 1; - - switch (event){ + + switch (event) { case FL_DRAW: if (!area->work_area || !area->work_area->form->visible) return 1; - lyxerr[Debug::GUI] << "Workarea event: DRAW" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: DRAW" << endl; area->createPixmap(area->workWidth(), area->height()); - Lgb_bug_find_hack = true; area->workAreaExpose(); - Lgb_bug_find_hack = false; break; case FL_PUSH: - if (!ev) break; + if (!ev || ev->xbutton.button == 0) break; // Should really have used xbutton.state - lyxerr[Debug::GUI] << "Workarea event: PUSH" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: PUSH" << endl; area->workAreaButtonPress(ev->xbutton.x - ob->x, ev->xbutton.y - ob->y, ev->xbutton.button); //area->workAreaKeyPress(XK_Pointer_Button1, ev->xbutton.state); - break; + break; case FL_RELEASE: - if (!ev) break; + if (!ev || ev->xbutton.button == 0) break; // Should really have used xbutton.state - lyxerr[Debug::GUI] << "Workarea event: RELEASE" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: RELEASE" << endl; area->workAreaButtonRelease(ev->xbutton.x - ob->x, ev->xbutton.y - ob->y, ev->xbutton.button); @@ -319,7 +378,7 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, ev->xmotion.y != y_old || fl_get_scrollbar_value(area->scrollbar) != scrollbar_value_old ) { - lyxerr[Debug::GUI] << "Workarea event: MOUSE" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: MOUSE" << endl; area->workAreaMotionNotify(ev->xmotion.x - ob->x, ev->xmotion.y - ob->y, ev->xbutton.state); @@ -331,13 +390,13 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, case FL_KEYPRESS: #endif { - lyxerr[Debug::KEY] << "Workarea event: KEYBOARD" << endl; - + lyxerr[Debug::WORKAREA] << "Workarea event: KEYBOARD" << endl; + KeySym keysym = 0; char dummy[1]; XKeyEvent * xke = reinterpret_cast(ev); -#if FL_REVISION < 89 - // XForms < 0.89 does not have compose support +#if FL_REVISION < 89 || (FL_REVISION == 89 && FL_FIXLEVEL < 5) + // XForms < 0.89.5 does not have compose support // so we are using our own compose support LyXLookupString(ev, dummy, 1, &keysym); #else @@ -346,16 +405,16 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, if (lyxerr.debugging(Debug::KEY)) { char const * tmp = XKeysymToString(key); char const * tmp2 = XKeysymToString(keysym); - string stm = (tmp ? tmp : ""); - string stm2 = (tmp2 ? tmp2 : ""); - - lyxerr << "WorkArea: Key is `" << stm << "' [" + string const stm = (tmp ? tmp : ""); + string const stm2 = (tmp2 ? tmp2 : ""); + + lyxerr[Debug::KEY] << "WorkArea: Key is `" << stm << "' [" << key << "]" << endl; - lyxerr << "WorkArea: Keysym is `" << stm2 << "' [" + lyxerr[Debug::KEY] << "WorkArea: Keysym is `" << stm2 << "' [" << keysym << "]" << endl; } -#if FL_REVISION < 89 +#if FL_REVISION < 89 || (FL_REVISION == 89 && FL_FIXLEVEL < 5) if (keysym == NoSymbol) { lyxerr[Debug::KEY] << "Empty kdb action (probably composing)" @@ -372,34 +431,43 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, if (!key) { // We migth have to add more keysyms here also, // we will do that as the issues arise. (Lgb) - if (keysym == XK_space) + if (keysym == XK_space) { ret_key = keysym; - else + lyxerr[Debug::KEY] << "Using keysym [A]" + << endl; + } else break; } else { // It seems that this was a bit optimistic... // With this hacking things seems to be better (Lgb) - if (static_cast(key) == key - && !iscntrl(key)) - ret_key = key; - else + //if (!iscntrl(key)) { + // ret_key = key; + // lyxerr[Debug::KEY] + // << "Using key [B]\n" + // << "Uchar[" + // << static_cast(key) + // << endl; + //} else { ret_key = (keysym ? keysym : key); + lyxerr[Debug::KEY] << "Using keysym [B]" + << endl; + //} } - -#endif - unsigned int ret_state = xke->state; + +#endif + unsigned int const ret_state = xke->state; // If you have a better way to handle "wild-output" of // characters after the key has been released than the one // below, please contact me. (Lgb) - static Time last_time_pressed = 0; - static unsigned int last_key_pressed = 0; - static unsigned int last_state_pressed = 0; + static Time last_time_pressed; + static unsigned int last_key_pressed; + static unsigned int last_state_pressed; lyxerr[Debug::KEY] << "Workarea Diff: " << xke->time - last_time_pressed << endl; - if (xke->time - last_time_pressed < 35 // should perhaps be tunable - && xke->state == last_state_pressed + if (xke->time - last_time_pressed < 25 // should perhaps be tunable + && ret_state == last_state_pressed && xke->keycode == last_key_pressed) { lyxerr[Debug::KEY] << "Workarea: Purging X events." << endl; @@ -417,102 +485,140 @@ int WorkArea::work_area_handler(FL_OBJECT * ob, int event, } last_time_pressed = xke->time; last_key_pressed = xke->keycode; - last_state_pressed = xke->state; - + last_state_pressed = ret_state; + area->workAreaKeyPress(ret_key, ret_state); } break; #if FL_REVISION >= 89 case FL_KEYRELEASE: - lyxerr << "Workarea event: KEYRELEASE" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: KEYRELEASE" << endl; break; #endif case FL_FOCUS: - lyxerr[Debug::GUI] << "Workarea event: FOCUS" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: FOCUS" << endl; area->workAreaFocus(); break; case FL_UNFOCUS: - lyxerr[Debug::GUI] << "Workarea event: UNFOCUS" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: UNFOCUS" << endl; area->workAreaUnfocus(); break; case FL_ENTER: - lyxerr[Debug::GUI] << "Workarea event: ENTER" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: ENTER" << endl; area->workAreaEnter(); break; case FL_LEAVE: - lyxerr[Debug::GUI] << "Workarea event: LEAVE" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: LEAVE" << endl; area->workAreaLeave(); break; case FL_DBLCLICK: if (!ev) break; - lyxerr[Debug::GUI] << "Workarea event: DBLCLICK" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: DBLCLICK" << endl; area->workAreaDoubleClick(ev->xbutton.x - ob->x, ev->xbutton.y - ob->y, ev->xbutton.button); break; case FL_TRPLCLICK: if (!ev) break; - lyxerr[Debug::GUI] << "Workarea event: TRPLCLICK" << endl; + lyxerr[Debug::WORKAREA] << "Workarea event: TRPLCLICK" << endl; area->workAreaTripleClick(ev->xbutton.x - ob->x, ev->xbutton.y - ob->y, ev->xbutton.button); break; case FL_OTHER: if (!ev) break; - lyxerr[Debug::GUI] << "Workarea event: OTHER" << endl; - + lyxerr[Debug::WORKAREA] << "Workarea event: OTHER" << endl; break; } - + return 1; } -static string clipboard_selection; -static bool clipboard_read = false; +namespace { + +string clipboard_selection; +bool clipboard_read = false; extern "C" { + static -int request_clipboard_cb(FL_OBJECT * /*ob*/, long /*type*/, - void const * data, long size) + int request_clipboard_cb(FL_OBJECT * /*ob*/, long /*type*/, + void const * data, long size) + { + clipboard_selection.erase(); + + if (size > 0) + clipboard_selection.reserve(size); + for (int i = 0; i < size; ++i) + clipboard_selection += + static_cast(data)[i]; + clipboard_read = true; + return 0; + } + +} + +} // namespace anon + + +int WorkArea::event_cb(XEvent * xev) +{ + int ret = 0; + switch (xev->type) { + case SelectionRequest: + lyxerr[Debug::GUI] << "X requested selection." << endl; + selectionRequested.emit(); +// ret = 1; + break; + case SelectionClear: + lyxerr[Debug::GUI] << "Lost selection." << endl; + selectionLost.emit(); +// ret = 1; + break; + } + return ret; +} + + +void WorkArea::haveSelection(bool yes) const { - clipboard_selection.erase(); - - if (size > 0) - clipboard_selection.reserve(size); - for (int i = 0; i < size; ++i) - clipboard_selection += static_cast(data)[i]; - clipboard_read = true; - return 0; + if (!yes) { + XSetSelectionOwner(fl_get_display(), XA_PRIMARY, None, CurrentTime); + return; + } + + XSetSelectionOwner(fl_get_display(), XA_PRIMARY, FL_ObjWin(work_area), CurrentTime); } -} // extern "C" -string const WorkArea::getClipboard() const +string const WorkArea::getClipboard() const { clipboard_read = false; - + if (fl_request_clipboard(work_area, 0, request_clipboard_cb) == -1) return string(); XEvent ev; - + while (!clipboard_read) { if (fl_check_forms() == FL_EVENT) { - lyxerr << "LyX: This shouldn't happen..." << endl; fl_XNextEvent(&ev); + lyxerr << "Received unhandled X11 event" << endl; + lyxerr << "Type: 0x" << hex << ev.xany.type << + " Target: 0x" << hex << ev.xany.window << endl; } } return clipboard_selection; } - + void WorkArea::putClipboard(string const & s) const { static string hold; hold = s; - - fl_stuff_clipboard(work_area, 0, hold.c_str(), hold.size(), 0); + + fl_stuff_clipboard(work_area, 0, hold.data(), hold.size(), 0); }