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 _GLIBCPP_CONCEPT_CHECKS
15 #undef _GLIBCPP_CONCEPT_CHECKS
18 #include "GWorkArea.h"
21 #include "GLyXKeySym.h"
24 #include "funcrequest.h"
27 using boost::shared_ptr;
36 mouse_button::state gButtonToLyx(guint gdkbutton)
38 // GDK uses int 1,2,3 but lyx uses enums (1,2,4)
41 return mouse_button::button1;
43 return mouse_button::button2;
45 return mouse_button::button3;
47 return mouse_button::button4;
49 return mouse_button::button5;
52 // This shouldn't happen, according to gdk docs
53 lyxerr << "gButtonToLyx: unhandled button index\n";
54 return mouse_button::button1;
59 ColorCache colorCache;
61 Gdk::Color * ColorCache::getColor(LColor_color clr)
63 MapIt it = cache_.find(clr);
64 return it == cache_.end() ? 0 : it->second.get();
68 XftColor * ColorCache::getXftColor(LColor_color clr)
70 MapIt2 it = cache2_.find(clr);
71 return it == cache2_.end() ? 0 : it->second.get();
75 void ColorCache::cacheColor(LColor_color clr, Gdk::Color * gclr)
77 cache_[clr] = shared_ptr<Gdk::Color>(gclr);
81 void ColorCache::cacheXftColor(LColor_color clr, XftColor * xclr)
83 cache2_[clr] = shared_ptr<XftColor>(xclr);
87 void ColorCache::clear()
94 XftColor * ColorHandler::getXftColor(LColor_color clr)
96 XftColor * xclr = colorCache.getXftColor(clr);
99 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
100 owner_.getColormap()->gobj());
101 Visual * visual = GDK_VISUAL_XVISUAL(
102 owner_.getColormap()->get_visual()->gobj());
103 XftColorAllocName(owner_.getDisplay(), visual, colormap,
105 lcolor.getX11Name(clr).c_str())
107 colorCache.cacheXftColor(clr, xclr);
113 Gdk::Color * ColorHandler::getGdkColor(LColor_color clr)
115 Gdk::Color * gclr = colorCache.getColor(clr);
117 gclr = new Gdk::Color;
118 gclr->parse(lcolor.getX11Name(clr));
119 owner_.getColormap()->alloc_color(*gclr);
120 colorCache.cacheColor(clr, gclr);
130 mouse_button::state gtkButtonState(unsigned int state)
132 mouse_button::state b = mouse_button::none;
133 if (state & GDK_BUTTON1_MASK)
134 b = mouse_button::button1;
135 else if (state & GDK_BUTTON2_MASK)
136 b = mouse_button::button2;
137 else if (state & GDK_BUTTON3_MASK)
138 b = mouse_button::button3;
139 else if (state & GDK_BUTTON3_MASK)
140 b = mouse_button::button3;
141 else if (state & GDK_BUTTON4_MASK)
142 b = mouse_button::button4;
143 else if (state & GDK_BUTTON5_MASK)
144 b = mouse_button::button5;
149 key_modifier::state gtkKeyState(guint state)
151 key_modifier::state k = key_modifier::none;
152 if (state & GDK_CONTROL_MASK)
153 k |= key_modifier::ctrl;
154 if (state & GDK_SHIFT_MASK)
155 k |= key_modifier::shift;
156 if (state & GDK_MOD1_MASK)
157 k |= key_modifier::alt;
162 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
164 area->inputCommit(str);
171 GWorkArea::GWorkArea(LyXView & owner, int width, int height)
172 : workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this)
174 workArea_.set_size_request(width, height);
175 workArea_.set_double_buffered(false);
176 workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
177 Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
178 Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
179 workArea_.signal_expose_event().connect(
180 sigc::mem_fun(*this, &GWorkArea::onExpose));
181 workArea_.signal_configure_event().connect(
182 sigc::mem_fun(*this, &GWorkArea::onConfigure));
183 workArea_.signal_button_press_event().connect(
184 sigc::mem_fun(*this, &GWorkArea::onButtonPress));
185 workArea_.signal_button_release_event().connect(
186 sigc::mem_fun(*this, &GWorkArea::onButtonRelease));
187 workArea_.signal_key_press_event().connect(
188 sigc::mem_fun(*this, &GWorkArea::onKeyPress));
189 workArea_.signal_motion_notify_event().connect(
190 sigc::mem_fun(*this, &GWorkArea::onMotionNotify));
192 vscrollbar_.get_adjustment()->signal_value_changed().connect(
193 sigc::mem_fun(*this, &GWorkArea::onScroll));
194 workArea_.signal_scroll_event().connect(
195 sigc::mem_fun(*this, &GWorkArea::onScrollWheel));
197 hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
198 hbox_.children().push_back(
199 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
202 GView & gview = static_cast<GView &>(owner);
203 gview.getBox(GView::Center).children().push_back(
204 Gtk::Box_Helpers::Element(hbox_));
206 workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
208 workArea_.grab_default();
209 gview.setGWorkArea(&workArea_);
210 imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
211 g_signal_connect(G_OBJECT(imContext_), "commit",
212 G_CALLBACK(&inputCommitRelay),
217 GWorkArea::~GWorkArea()
219 g_object_unref(imContext_);
223 Painter & GWorkArea::getPainter()
229 int GWorkArea::workWidth() const
231 return workArea_.get_width();
235 int GWorkArea::workHeight() const
237 return workArea_.get_height();
241 int GWorkArea::xpos() const
247 int GWorkArea::ypos() const
253 Glib::RefPtr<Gdk::Window> GWorkArea::getWindow()
255 return workArea_.get_window();
259 Display * GWorkArea::getDisplay() const
261 return GDK_WINDOW_XDISPLAY(
262 const_cast<GdkWindow*>(workArea_.get_window()->gobj()));
266 Glib::RefPtr<Gdk::Pixmap> GWorkArea::getPixmap()
268 return workAreaPixmap_;
272 Glib::RefPtr<Gdk::GC> GWorkArea::getGC()
278 Glib::RefPtr<Gdk::Colormap> GWorkArea::getColormap()
280 return workArea_.get_colormap();
284 XftDraw * GWorkArea::getXftDraw()
290 ColorHandler & GWorkArea::getColorHandler()
292 return colorHandler_;
296 bool GWorkArea::onExpose(GdkEventExpose * event)
298 workArea_.get_window()->draw_drawable(
299 workArea_.get_style()->get_black_gc(),
301 event->area.x, event->area.y,
302 event->area.x, event->area.y,
303 event->area.width, event->area.height);
308 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
310 int x, y, width, height, depth;
311 workArea_.get_window()->get_geometry(x, y, width, height, depth);
313 XftDrawDestroy(draw_);
314 workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
315 width, height, depth);
316 Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
317 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
318 workArea_.get_colormap()->gobj());
319 Visual * visual = GDK_VISUAL_XVISUAL(
320 workArea_.get_colormap()->get_visual()->gobj());
321 draw_ = XftDrawCreate(getDisplay(), pixmap,
324 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
325 Gdk::Cursor cursor(Gdk::XTERM);
326 workArea_.get_window()->set_cursor(cursor);
327 gtk_im_context_set_client_window(
328 imContext_, workArea_.get_window()->gobj());
335 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
337 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
338 adjustment->set_lower(0);
339 int workAreaHeight = workHeight();
340 if (!height || height < workAreaHeight) {
341 adjustment->set_upper(workAreaHeight);
342 adjustment->set_page_size(workAreaHeight);
343 adjustment->set_value(0);
344 adjustment->changed();
347 adjustment->set_step_increment(line_height * 3);
348 adjustment->set_page_increment(workAreaHeight - line_height);
349 // Allow the user half a screen of blank at the end
350 // to make scrollbar consistant with centering the cursor
351 adjustment->set_upper(height + workAreaHeight / 2);
352 adjustment->set_page_size(workAreaHeight);
353 adjustment->set_value(pos);
354 adjustment->changed();
358 void GWorkArea::onScroll()
360 double val = vscrollbar_.get_adjustment()->get_value();
361 scrollDocView(static_cast<int>(val));
365 bool GWorkArea::onScrollWheel(GdkEventScroll * event)
367 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
370 if (event->state & GDK_CONTROL_MASK)
371 step = adjustment->get_page_increment();
373 step = adjustment->get_step_increment();
375 if (event->direction == GDK_SCROLL_UP)
378 double target = adjustment->get_value() + step;
379 // Prevent the user getting a whole screen of blank when they
380 // try to scroll past the end of the doc
381 double max = adjustment->get_upper() - workHeight();
385 adjustment->set_value(target);
390 bool GWorkArea::onButtonPress(GdkEventButton * event)
392 kb_action ka = LFUN_MOUSE_PRESS;
393 switch (event->type) {
394 case GDK_BUTTON_PRESS:
395 ka = LFUN_MOUSE_PRESS;
397 case GDK_2BUTTON_PRESS:
398 ka = LFUN_MOUSE_DOUBLE;
400 case GDK_3BUTTON_PRESS:
401 ka = LFUN_MOUSE_TRIPLE;
406 dispatch(FuncRequest(ka,
407 static_cast<int>(event->x),
408 static_cast<int>(event->y),
409 gButtonToLyx(event->button)));
410 workArea_.grab_focus();
415 bool GWorkArea::onButtonRelease(GdkEventButton * event)
417 dispatch(FuncRequest(LFUN_MOUSE_RELEASE,
418 static_cast<int>(event->x),
419 static_cast<int>(event->y),
420 gButtonToLyx(event->button)));
425 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
427 static guint32 timeBefore;
428 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
429 double step = adjustment->get_step_increment();
430 double value = adjustment->get_value();
433 else if (event->x > workArea_.get_height())
435 if (value != adjustment->get_value()) {
436 if (event->time - timeBefore > 200) {
437 adjustment->set_value(value);
438 adjustment->value_changed();
440 timeBefore = event->time;
442 dispatch(FuncRequest(LFUN_MOUSE_MOTION,
443 static_cast<int>(event->x),
444 static_cast<int>(event->y),
445 gtkButtonState(event->state)));
450 void GWorkArea::inputCommit(gchar * str)
452 inputCache_ = Glib::locale_from_utf8(str);
456 bool GWorkArea::onKeyPress(GdkEventKey * event)
460 bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
462 if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
465 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
466 workAreaKeyPress(LyXKeySymPtr(glk),
467 gtkKeyState(event->state));
469 } else if (!inputCache_.empty())
470 workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
476 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
479 selectionRequested();
483 void GWorkArea::onClipboardClear()
489 void GWorkArea::haveSelection(bool toHave) const
492 Glib::RefPtr<Gtk::Clipboard> clipboard =
493 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
494 std::vector<Gtk::TargetEntry> listTargets;
495 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
496 clipboard->set(listTargets,
497 sigc::mem_fun(const_cast<GWorkArea&>(*this),
498 &GWorkArea::onClipboardGet),
499 sigc::mem_fun(const_cast<GWorkArea&>(*this),
500 &GWorkArea::onClipboardClear));
505 string const GWorkArea::getClipboard() const
507 Glib::RefPtr<Gtk::Clipboard> clipboard =
508 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
509 return Glib::locale_from_utf8(clipboard->wait_for_text());
513 void GWorkArea::putClipboard(string const & str) const
515 Glib::RefPtr<Gtk::Clipboard> clipboard =
516 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
517 clipboard->set_text(Glib::locale_to_utf8(str));
520 } // namespace frontend