3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 // Too hard to make concept checks work with this file
14 #ifdef _GLIBCXX_CONCEPT_CHECKS
15 #undef _GLIBCXX_CONCEPT_CHECKS
17 #ifdef _GLIBCPP_CONCEPT_CHECKS
18 #undef _GLIBCPP_CONCEPT_CHECKS
21 #include "GWorkArea.h"
24 #include "GLyXKeySym.h"
26 #include "BufferView.h"
28 #include "funcrequest.h"
32 #include "Selection.h"
34 using boost::shared_ptr;
43 mouse_button::state gButtonToLyx(guint gdkbutton)
45 // GDK uses int 1,2,3 but lyx uses enums (1,2,4)
48 return mouse_button::button1;
50 return mouse_button::button2;
52 return mouse_button::button3;
54 return mouse_button::button4;
56 return mouse_button::button5;
59 // This shouldn't happen, according to gdk docs
60 lyxerr << "gButtonToLyx: unhandled button index\n";
61 return mouse_button::button1;
66 ColorCache colorCache;
68 Gdk::Color * ColorCache::getColor(LColor_color clr)
70 MapIt it = cache_.find(clr);
71 return it == cache_.end() ? 0 : it->second.get();
75 XftColor * ColorCache::getXftColor(LColor_color clr)
77 MapIt2 it = cache2_.find(clr);
78 return it == cache2_.end() ? 0 : it->second.get();
82 void ColorCache::cacheColor(LColor_color clr, Gdk::Color * gclr)
84 cache_[clr] = shared_ptr<Gdk::Color>(gclr);
88 void ColorCache::cacheXftColor(LColor_color clr, XftColor * xclr)
90 cache2_[clr] = shared_ptr<XftColor>(xclr);
94 void ColorCache::clear()
101 XftColor * ColorHandler::getXftColor(LColor_color clr)
103 XftColor * xclr = colorCache.getXftColor(clr);
106 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
107 owner_.getColormap()->gobj());
108 Visual * visual = GDK_VISUAL_XVISUAL(
109 owner_.getColormap()->get_visual()->gobj());
110 XftColorAllocName(owner_.getDisplay(), visual, colormap,
112 lcolor.getX11Name(clr).c_str())
114 colorCache.cacheXftColor(clr, xclr);
120 Gdk::Color * ColorHandler::getGdkColor(LColor_color clr)
122 Gdk::Color * gclr = colorCache.getColor(clr);
124 gclr = new Gdk::Color;
125 gclr->parse(lcolor.getX11Name(clr));
126 owner_.getColormap()->alloc_color(*gclr);
127 colorCache.cacheColor(clr, gclr);
137 mouse_button::state gtkButtonState(unsigned int state)
139 mouse_button::state b = mouse_button::none;
140 if (state & GDK_BUTTON1_MASK)
141 b = mouse_button::button1;
142 else if (state & GDK_BUTTON2_MASK)
143 b = mouse_button::button2;
144 else if (state & GDK_BUTTON3_MASK)
145 b = mouse_button::button3;
146 else if (state & GDK_BUTTON3_MASK)
147 b = mouse_button::button3;
148 else if (state & GDK_BUTTON4_MASK)
149 b = mouse_button::button4;
150 else if (state & GDK_BUTTON5_MASK)
151 b = mouse_button::button5;
156 key_modifier::state gtkKeyState(guint state)
158 key_modifier::state k = key_modifier::none;
159 if (state & GDK_CONTROL_MASK)
160 k |= key_modifier::ctrl;
161 if (state & GDK_SHIFT_MASK)
162 k |= key_modifier::shift;
163 if (state & GDK_MOD1_MASK)
164 k |= key_modifier::alt;
169 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
171 area->inputCommit(str);
178 GWorkArea::GWorkArea(LyXView & owner, int width, int height)
179 : view_(owner), workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this),
182 workArea_.set_size_request(width, height);
183 workArea_.set_double_buffered(false);
184 workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
185 Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
186 Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
187 workArea_.signal_expose_event().connect(
188 sigc::mem_fun(*this, &GWorkArea::onExpose));
189 workArea_.signal_configure_event().connect(
190 sigc::mem_fun(*this, &GWorkArea::onConfigure));
191 workArea_.signal_button_press_event().connect(
192 sigc::mem_fun(*this, &GWorkArea::onButtonPress));
193 workArea_.signal_button_release_event().connect(
194 sigc::mem_fun(*this, &GWorkArea::onButtonRelease));
195 workArea_.signal_key_press_event().connect(
196 sigc::mem_fun(*this, &GWorkArea::onKeyPress));
197 workArea_.signal_motion_notify_event().connect(
198 sigc::mem_fun(*this, &GWorkArea::onMotionNotify));
200 vscrollbar_.get_adjustment()->signal_value_changed().connect(
201 sigc::mem_fun(*this, &GWorkArea::onScroll));
202 workArea_.signal_scroll_event().connect(
203 sigc::mem_fun(*this, &GWorkArea::onScrollWheel));
205 hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
206 hbox_.children().push_back(
207 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
210 GView & gview = static_cast<GView &>(owner);
211 gview.getBox(GView::Center).children().push_back(
212 Gtk::Box_Helpers::Element(hbox_));
214 workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
216 workArea_.grab_default();
217 gview.setGWorkArea(&workArea_);
218 imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
219 g_signal_connect(G_OBJECT(imContext_), "commit",
220 G_CALLBACK(&inputCommitRelay),
225 GWorkArea::~GWorkArea()
227 g_object_unref(imContext_);
231 Painter & GWorkArea::getPainter()
237 int GWorkArea::workWidth() const
239 return workArea_.get_width();
243 int GWorkArea::workHeight() const
245 return workArea_.get_height();
249 int GWorkArea::xpos() const
255 int GWorkArea::ypos() const
261 Glib::RefPtr<Gdk::Window> GWorkArea::getWindow()
263 return workArea_.get_window();
267 Display * GWorkArea::getDisplay() const
269 return GDK_WINDOW_XDISPLAY(
270 const_cast<GdkWindow*>(workArea_.get_window()->gobj()));
274 Glib::RefPtr<Gdk::Pixmap> GWorkArea::getPixmap()
276 return workAreaPixmap_;
280 Glib::RefPtr<Gdk::GC> GWorkArea::getGC()
286 Glib::RefPtr<Gdk::Colormap> GWorkArea::getColormap()
288 return workArea_.get_colormap();
292 XftDraw * GWorkArea::getXftDraw()
298 ColorHandler & GWorkArea::getColorHandler()
300 return colorHandler_;
304 bool GWorkArea::onExpose(GdkEventExpose * event)
306 workArea_.get_window()->draw_drawable(
307 workArea_.get_style()->get_black_gc(),
309 event->area.x, event->area.y,
310 event->area.x, event->area.y,
311 event->area.width, event->area.height);
316 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
318 int x, y, width, height, depth;
319 workArea_.get_window()->get_geometry(x, y, width, height, depth);
321 XftDrawDestroy(draw_);
322 workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
323 width, height, depth);
324 Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
325 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
326 workArea_.get_colormap()->gobj());
327 Visual * visual = GDK_VISUAL_XVISUAL(
328 workArea_.get_colormap()->get_visual()->gobj());
329 draw_ = XftDrawCreate(getDisplay(), pixmap,
332 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
333 Gdk::Cursor cursor(Gdk::XTERM);
334 workArea_.get_window()->set_cursor(cursor);
335 gtk_im_context_set_client_window(
336 imContext_, workArea_.get_window()->gobj());
338 view_.workArea()->resizeBufferView();
343 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
350 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
351 adjustment->set_lower(0);
352 int workAreaHeight = workHeight();
353 if (!height || height < workAreaHeight) {
354 adjustment->set_upper(workAreaHeight);
355 adjustment->set_page_size(workAreaHeight);
356 adjustment->set_value(0);
357 adjustment->changed();
361 adjustment->set_step_increment(line_height * 3);
362 adjustment->set_page_increment(workAreaHeight - line_height);
363 // Allow the user half a screen of blank at the end
364 // to make scrollbar consistant with centering the cursor
365 adjustment->set_upper(height + workAreaHeight / 4);
366 adjustment->set_page_size(workAreaHeight);
367 adjustment->set_value(pos);
368 adjustment->changed();
373 void GWorkArea::onScroll()
380 double val = vscrollbar_.get_adjustment()->get_value();
381 view_.workArea()->scrollBufferView(static_cast<int>(val));
386 bool GWorkArea::onScrollWheel(GdkEventScroll * event)
388 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
391 if (event->state & GDK_CONTROL_MASK)
392 step = adjustment->get_page_increment();
394 step = adjustment->get_step_increment();
396 if (event->direction == GDK_SCROLL_UP)
399 double target = adjustment->get_value() + step;
400 // Prevent the user getting a whole screen of blank when they
401 // try to scroll past the end of the doc
402 double max = adjustment->get_upper() - workHeight();
406 adjustment->set_value(target);
411 bool GWorkArea::onButtonPress(GdkEventButton * event)
413 kb_action ka = LFUN_MOUSE_PRESS;
414 switch (event->type) {
415 case GDK_BUTTON_PRESS:
416 ka = LFUN_MOUSE_PRESS;
418 case GDK_2BUTTON_PRESS:
419 ka = LFUN_MOUSE_DOUBLE;
421 case GDK_3BUTTON_PRESS:
422 ka = LFUN_MOUSE_TRIPLE;
427 view_.workArea()->dispatch(FuncRequest(ka,
428 static_cast<int>(event->x),
429 static_cast<int>(event->y),
430 gButtonToLyx(event->button)));
431 workArea_.grab_focus();
436 bool GWorkArea::onButtonRelease(GdkEventButton * event)
438 view_.workArea()->dispatch(FuncRequest(LFUN_MOUSE_RELEASE,
439 static_cast<int>(event->x),
440 static_cast<int>(event->y),
441 gButtonToLyx(event->button)));
446 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
448 static guint32 timeBefore;
449 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
450 double step = adjustment->get_step_increment();
451 double value = adjustment->get_value();
454 else if (event->x > workArea_.get_height())
456 if (value != adjustment->get_value()) {
457 if (event->time - timeBefore > 200) {
458 adjustment->set_value(value);
459 adjustment->value_changed();
461 timeBefore = event->time;
463 view_.workArea()->dispatch(FuncRequest(LFUN_MOUSE_MOTION,
464 static_cast<int>(event->x),
465 static_cast<int>(event->y),
466 gtkButtonState(event->state)));
471 void GWorkArea::inputCommit(gchar * str)
473 inputCache_ = Glib::locale_from_utf8(str);
477 bool GWorkArea::onKeyPress(GdkEventKey * event)
481 // bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
482 // // cope with ascii
483 // if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
486 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
487 view_.workArea()->processKeySym(LyXKeySymPtr(glk),
488 gtkKeyState(event->state));
490 // } else if (!inputCache_.empty())
491 // workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
497 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
500 lyx::docstring const sel = view_.view()->requestSelection();
502 view_.gui().selection().put(sel);
506 void GWorkArea::onClipboardClear()
512 void GWorkArea::haveSelection(bool toHave)
515 Glib::RefPtr<Gtk::Clipboard> clipboard =
516 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
517 std::vector<Gtk::TargetEntry> listTargets;
518 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
519 clipboard->set(listTargets,
520 sigc::mem_fun(const_cast<GWorkArea&>(*this),
521 &GWorkArea::onClipboardGet),
522 sigc::mem_fun(const_cast<GWorkArea&>(*this),
523 &GWorkArea::onClipboardClear));
527 } // namespace frontend