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"
31 using boost::shared_ptr;
40 mouse_button::state gButtonToLyx(guint gdkbutton)
42 // GDK uses int 1,2,3 but lyx uses enums (1,2,4)
45 return mouse_button::button1;
47 return mouse_button::button2;
49 return mouse_button::button3;
51 return mouse_button::button4;
53 return mouse_button::button5;
56 // This shouldn't happen, according to gdk docs
57 lyxerr << "gButtonToLyx: unhandled button index\n";
58 return mouse_button::button1;
63 ColorCache colorCache;
65 Gdk::Color * ColorCache::getColor(LColor_color clr)
67 MapIt it = cache_.find(clr);
68 return it == cache_.end() ? 0 : it->second.get();
72 XftColor * ColorCache::getXftColor(LColor_color clr)
74 MapIt2 it = cache2_.find(clr);
75 return it == cache2_.end() ? 0 : it->second.get();
79 void ColorCache::cacheColor(LColor_color clr, Gdk::Color * gclr)
81 cache_[clr] = shared_ptr<Gdk::Color>(gclr);
85 void ColorCache::cacheXftColor(LColor_color clr, XftColor * xclr)
87 cache2_[clr] = shared_ptr<XftColor>(xclr);
91 void ColorCache::clear()
98 XftColor * ColorHandler::getXftColor(LColor_color clr)
100 XftColor * xclr = colorCache.getXftColor(clr);
103 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
104 owner_.getColormap()->gobj());
105 Visual * visual = GDK_VISUAL_XVISUAL(
106 owner_.getColormap()->get_visual()->gobj());
107 XftColorAllocName(owner_.getDisplay(), visual, colormap,
109 lcolor.getX11Name(clr).c_str())
111 colorCache.cacheXftColor(clr, xclr);
117 Gdk::Color * ColorHandler::getGdkColor(LColor_color clr)
119 Gdk::Color * gclr = colorCache.getColor(clr);
121 gclr = new Gdk::Color;
122 gclr->parse(lcolor.getX11Name(clr));
123 owner_.getColormap()->alloc_color(*gclr);
124 colorCache.cacheColor(clr, gclr);
134 mouse_button::state gtkButtonState(unsigned int state)
136 mouse_button::state b = mouse_button::none;
137 if (state & GDK_BUTTON1_MASK)
138 b = mouse_button::button1;
139 else if (state & GDK_BUTTON2_MASK)
140 b = mouse_button::button2;
141 else if (state & GDK_BUTTON3_MASK)
142 b = mouse_button::button3;
143 else if (state & GDK_BUTTON3_MASK)
144 b = mouse_button::button3;
145 else if (state & GDK_BUTTON4_MASK)
146 b = mouse_button::button4;
147 else if (state & GDK_BUTTON5_MASK)
148 b = mouse_button::button5;
153 key_modifier::state gtkKeyState(guint state)
155 key_modifier::state k = key_modifier::none;
156 if (state & GDK_CONTROL_MASK)
157 k |= key_modifier::ctrl;
158 if (state & GDK_SHIFT_MASK)
159 k |= key_modifier::shift;
160 if (state & GDK_MOD1_MASK)
161 k |= key_modifier::alt;
166 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
168 area->inputCommit(str);
175 GWorkArea::GWorkArea(LyXView & owner, int width, int height)
176 : view_(owner), workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this),
179 workArea_.set_size_request(width, height);
180 workArea_.set_double_buffered(false);
181 workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
182 Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
183 Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
184 workArea_.signal_expose_event().connect(
185 sigc::mem_fun(*this, &GWorkArea::onExpose));
186 workArea_.signal_configure_event().connect(
187 sigc::mem_fun(*this, &GWorkArea::onConfigure));
188 workArea_.signal_button_press_event().connect(
189 sigc::mem_fun(*this, &GWorkArea::onButtonPress));
190 workArea_.signal_button_release_event().connect(
191 sigc::mem_fun(*this, &GWorkArea::onButtonRelease));
192 workArea_.signal_key_press_event().connect(
193 sigc::mem_fun(*this, &GWorkArea::onKeyPress));
194 workArea_.signal_motion_notify_event().connect(
195 sigc::mem_fun(*this, &GWorkArea::onMotionNotify));
197 vscrollbar_.get_adjustment()->signal_value_changed().connect(
198 sigc::mem_fun(*this, &GWorkArea::onScroll));
199 workArea_.signal_scroll_event().connect(
200 sigc::mem_fun(*this, &GWorkArea::onScrollWheel));
202 hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
203 hbox_.children().push_back(
204 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
207 GView & gview = static_cast<GView &>(owner);
208 gview.getBox(GView::Center).children().push_back(
209 Gtk::Box_Helpers::Element(hbox_));
211 workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
213 workArea_.grab_default();
214 gview.setGWorkArea(&workArea_);
215 imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
216 g_signal_connect(G_OBJECT(imContext_), "commit",
217 G_CALLBACK(&inputCommitRelay),
222 GWorkArea::~GWorkArea()
224 g_object_unref(imContext_);
228 Painter & GWorkArea::getPainter()
234 int GWorkArea::workWidth() const
236 return workArea_.get_width();
240 int GWorkArea::workHeight() const
242 return workArea_.get_height();
246 int GWorkArea::xpos() const
252 int GWorkArea::ypos() const
258 Glib::RefPtr<Gdk::Window> GWorkArea::getWindow()
260 return workArea_.get_window();
264 Display * GWorkArea::getDisplay() const
266 return GDK_WINDOW_XDISPLAY(
267 const_cast<GdkWindow*>(workArea_.get_window()->gobj()));
271 Glib::RefPtr<Gdk::Pixmap> GWorkArea::getPixmap()
273 return workAreaPixmap_;
277 Glib::RefPtr<Gdk::GC> GWorkArea::getGC()
283 Glib::RefPtr<Gdk::Colormap> GWorkArea::getColormap()
285 return workArea_.get_colormap();
289 XftDraw * GWorkArea::getXftDraw()
295 ColorHandler & GWorkArea::getColorHandler()
297 return colorHandler_;
301 bool GWorkArea::onExpose(GdkEventExpose * event)
303 workArea_.get_window()->draw_drawable(
304 workArea_.get_style()->get_black_gc(),
306 event->area.x, event->area.y,
307 event->area.x, event->area.y,
308 event->area.width, event->area.height);
313 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
315 int x, y, width, height, depth;
316 workArea_.get_window()->get_geometry(x, y, width, height, depth);
318 XftDrawDestroy(draw_);
319 workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
320 width, height, depth);
321 Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
322 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
323 workArea_.get_colormap()->gobj());
324 Visual * visual = GDK_VISUAL_XVISUAL(
325 workArea_.get_colormap()->get_visual()->gobj());
326 draw_ = XftDrawCreate(getDisplay(), pixmap,
329 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
330 Gdk::Cursor cursor(Gdk::XTERM);
331 workArea_.get_window()->set_cursor(cursor);
332 gtk_im_context_set_client_window(
333 imContext_, workArea_.get_window()->gobj());
335 view_.view()->workAreaResize();
340 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
347 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
348 adjustment->set_lower(0);
349 int workAreaHeight = workHeight();
350 if (!height || height < workAreaHeight) {
351 adjustment->set_upper(workAreaHeight);
352 adjustment->set_page_size(workAreaHeight);
353 adjustment->set_value(0);
354 adjustment->changed();
358 adjustment->set_step_increment(line_height * 3);
359 adjustment->set_page_increment(workAreaHeight - line_height);
360 // Allow the user half a screen of blank at the end
361 // to make scrollbar consistant with centering the cursor
362 adjustment->set_upper(height + workAreaHeight / 4);
363 adjustment->set_page_size(workAreaHeight);
364 adjustment->set_value(pos);
365 adjustment->changed();
370 void GWorkArea::onScroll()
377 double val = vscrollbar_.get_adjustment()->get_value();
378 view_.view()->scrollDocView(static_cast<int>(val));
383 bool GWorkArea::onScrollWheel(GdkEventScroll * event)
385 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
388 if (event->state & GDK_CONTROL_MASK)
389 step = adjustment->get_page_increment();
391 step = adjustment->get_step_increment();
393 if (event->direction == GDK_SCROLL_UP)
396 double target = adjustment->get_value() + step;
397 // Prevent the user getting a whole screen of blank when they
398 // try to scroll past the end of the doc
399 double max = adjustment->get_upper() - workHeight();
403 adjustment->set_value(target);
408 bool GWorkArea::onButtonPress(GdkEventButton * event)
410 kb_action ka = LFUN_MOUSE_PRESS;
411 switch (event->type) {
412 case GDK_BUTTON_PRESS:
413 ka = LFUN_MOUSE_PRESS;
415 case GDK_2BUTTON_PRESS:
416 ka = LFUN_MOUSE_DOUBLE;
418 case GDK_3BUTTON_PRESS:
419 ka = LFUN_MOUSE_TRIPLE;
424 view_.view()->workAreaDispatch(FuncRequest(ka,
425 static_cast<int>(event->x),
426 static_cast<int>(event->y),
427 gButtonToLyx(event->button)));
428 workArea_.grab_focus();
433 bool GWorkArea::onButtonRelease(GdkEventButton * event)
435 view_.view()->workAreaDispatch(FuncRequest(LFUN_MOUSE_RELEASE,
436 static_cast<int>(event->x),
437 static_cast<int>(event->y),
438 gButtonToLyx(event->button)));
443 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
445 static guint32 timeBefore;
446 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
447 double step = adjustment->get_step_increment();
448 double value = adjustment->get_value();
451 else if (event->x > workArea_.get_height())
453 if (value != adjustment->get_value()) {
454 if (event->time - timeBefore > 200) {
455 adjustment->set_value(value);
456 adjustment->value_changed();
458 timeBefore = event->time;
460 view_.view()->workAreaDispatch(FuncRequest(LFUN_MOUSE_MOTION,
461 static_cast<int>(event->x),
462 static_cast<int>(event->y),
463 gtkButtonState(event->state)));
468 void GWorkArea::inputCommit(gchar * str)
470 inputCache_ = Glib::locale_from_utf8(str);
474 bool GWorkArea::onKeyPress(GdkEventKey * event)
478 bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
480 if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
483 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
484 view_.view()->workAreaKeyPress(LyXKeySymPtr(glk),
485 gtkKeyState(event->state));
487 } else if (!inputCache_.empty())
488 workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
494 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
497 view_.view()->selectionRequested();
501 void GWorkArea::onClipboardClear()
507 void GWorkArea::haveSelection(bool toHave)
510 Glib::RefPtr<Gtk::Clipboard> clipboard =
511 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
512 std::vector<Gtk::TargetEntry> listTargets;
513 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
514 clipboard->set(listTargets,
515 sigc::mem_fun(const_cast<GWorkArea&>(*this),
516 &GWorkArea::onClipboardGet),
517 sigc::mem_fun(const_cast<GWorkArea&>(*this),
518 &GWorkArea::onClipboardClear));
523 // ENCODING: Gtk::Clipboard returns UTF-8, we assume that the backend
524 // wants ISO-8859-1 and convert it to that.
525 string const GWorkArea::getClipboard() const
527 Glib::RefPtr<Gtk::Clipboard> clipboard =
528 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
529 return Glib::convert_with_fallback(
530 clipboard->wait_for_text(), "ISO-8859-1", "UTF-8");
534 // ENCODING: we assume that the backend passes us ISO-8859-1 and
535 // convert from that to UTF-8 before passing to GTK
536 void GWorkArea::putClipboard(string const & str)
538 Glib::RefPtr<Gtk::Clipboard> clipboard =
539 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
540 clipboard->set_text(Glib::convert(str, "UTF-8", "ISO-8859-1"));
544 } // namespace frontend