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 #include <X11/Xft/Xft.h>
15 #include "GWorkArea.h"
18 #include "GLyXKeySym.h"
21 #include "funcrequest.h"
27 ColorCache colorCache;
30 ColorCache::~ColorCache()
36 Gdk::Color * ColorCache::getColor(LColor_color clr)
38 MapIt it = cache_.find(clr);
39 return it == cache_.end() ? 0 : it->second;
43 XftColor * ColorCache::getXftColor(LColor_color clr)
45 MapIt2 it = cache2_.find(clr);
46 return it == cache2_.end() ? 0 : it->second;
50 void ColorCache::cacheColor(LColor_color clr, Gdk::Color * gclr)
56 void ColorCache::cacheXftColor(LColor_color clr, XftColor * xclr)
62 void ColorCache::clear()
64 MapIt it = cache_.begin();
65 for (; it != cache_.end(); ++it)
68 MapIt2 it2 = cache2_.begin();
69 for (; it2 != cache2_.end(); ++it2)
75 XftColor * ColorHandler::getXftColor(LColor_color clr)
77 XftColor * xclr = colorCache.getXftColor(clr);
80 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
81 owner_.getColormap()->gobj());
82 Visual * visual = GDK_VISUAL_XVISUAL(
83 owner_.getColormap()->get_visual()->gobj());
84 XftColorAllocName(owner_.getDisplay(), visual, colormap,
85 lcolor.getX11Name(clr).c_str(), xclr);
86 colorCache.cacheXftColor(clr, xclr);
92 Gdk::Color * ColorHandler::getGdkColor(LColor_color clr)
94 Gdk::Color * gclr = colorCache.getColor(clr);
96 gclr = new Gdk::Color;
97 gclr->parse(lcolor.getX11Name(clr));
98 owner_.getColormap()->alloc_color(*gclr);
99 colorCache.cacheColor(clr, gclr);
109 mouse_button::state gtkButtonState(unsigned int state)
111 mouse_button::state b = mouse_button::none;
112 if (state & GDK_BUTTON1_MASK)
113 b = mouse_button::button1;
114 else if (state & GDK_BUTTON2_MASK)
115 b = mouse_button::button2;
116 else if (state & GDK_BUTTON3_MASK)
117 b = mouse_button::button3;
118 else if (state & GDK_BUTTON3_MASK)
119 b = mouse_button::button3;
120 else if (state & GDK_BUTTON4_MASK)
121 b = mouse_button::button4;
122 else if (state & GDK_BUTTON5_MASK)
123 b = mouse_button::button5;
128 key_modifier::state gtkKeyState(guint state)
130 key_modifier::state k = key_modifier::none;
131 if (state & GDK_CONTROL_MASK)
132 k |= key_modifier::ctrl;
133 if (state & GDK_SHIFT_MASK)
134 k |= key_modifier::shift;
135 if (state & GDK_MOD1_MASK)
136 k |= key_modifier::alt;
141 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
143 area->inputCommit(str);
150 GWorkArea::GWorkArea(int width, int height)
151 : workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this)
153 workArea_.set_size_request(width, height);
154 workArea_.set_double_buffered(false);
155 workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
156 Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
157 Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
158 workArea_.signal_expose_event().connect(
159 SigC::slot(*this, &GWorkArea::onExpose));
160 workArea_.signal_configure_event().connect(
161 SigC::slot(*this, &GWorkArea::onConfigure));
162 workArea_.signal_button_press_event().connect(
163 SigC::slot(*this, &GWorkArea::onButtonPress));
164 workArea_.signal_button_release_event().connect(
165 SigC::slot(*this, &GWorkArea::onButtonRelease));
166 workArea_.signal_key_press_event().connect(
167 SigC::slot(*this, &GWorkArea::onKeyPress));
168 workArea_.signal_motion_notify_event().connect(
169 SigC::slot(*this, &GWorkArea::onMotionNotify));
171 vscrollbar_.get_adjustment()->signal_value_changed().connect(
172 SigC::slot(*this, &GWorkArea::onScroll));
174 hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
175 hbox_.children().push_back(
176 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
178 GView::instance()->getVBox().children().push_back(
179 Gtk::Box_Helpers::Element(hbox_));
180 workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
182 workArea_.grab_default();
183 GView::instance()->setGWorkArea(&workArea_);
184 imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
185 g_signal_connect(G_OBJECT(imContext_), "commit",
186 G_CALLBACK(&inputCommitRelay),
191 GWorkArea::~GWorkArea()
193 g_object_unref(imContext_);
197 Painter & GWorkArea::getPainter()
203 int GWorkArea::workWidth() const
205 return workArea_.get_width();
209 int GWorkArea::workHeight() const
211 return workArea_.get_height();
215 int GWorkArea::xpos() const
221 int GWorkArea::ypos() const
227 Glib::RefPtr<Gdk::Window> GWorkArea::getWindow()
229 return workArea_.get_window();
233 Display * GWorkArea::getDisplay() const
235 return GDK_WINDOW_XDISPLAY(
236 const_cast<GdkWindow*>(workArea_.get_window()->gobj()));
240 Glib::RefPtr<Gdk::Pixmap> GWorkArea::getPixmap()
242 return workAreaPixmap_;
246 Glib::RefPtr<Gdk::GC> GWorkArea::getGC()
252 Glib::RefPtr<Gdk::Colormap> GWorkArea::getColormap()
254 return workArea_.get_colormap();
258 XftDraw * GWorkArea::getXftDraw()
264 ColorHandler & GWorkArea::getColorHandler()
266 return colorHandler_;
270 bool GWorkArea::onExpose(GdkEventExpose * event)
272 workArea_.get_window()->draw_drawable(
273 workArea_.get_style()->get_black_gc(),
275 event->area.x, event->area.y,
276 event->area.x, event->area.y,
277 event->area.width, event->area.height);
282 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
284 int x, y, width, height, depth;
285 workArea_.get_window()->get_geometry(x, y, width, height, depth);
287 XftDrawDestroy(draw_);
288 workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
289 width, height, depth);
290 Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
291 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
292 workArea_.get_colormap()->gobj());
293 Visual * visual = GDK_VISUAL_XVISUAL(
294 workArea_.get_colormap()->get_visual()->gobj());
295 draw_ = XftDrawCreate(getDisplay(), pixmap,
298 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
299 Gdk::Cursor cursor(Gdk::XTERM);
300 workArea_.get_window()->set_cursor(cursor);
301 gtk_im_context_set_client_window(
302 imContext_, workArea_.get_window()->gobj());
309 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
311 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
312 adjustment->set_lower(0);
313 int workAreaHeight = workHeight();
314 if (!height || height < workAreaHeight) {
315 adjustment->set_upper(workAreaHeight);
316 adjustment->set_page_size(workAreaHeight);
317 adjustment->set_value(0);
318 adjustment->changed();
321 adjustment->set_step_increment(line_height);
322 adjustment->set_page_increment(workAreaHeight - line_height);
323 adjustment->set_upper(height);
324 adjustment->set_page_size(workAreaHeight);
325 adjustment->set_value(pos);
326 adjustment->changed();
330 void GWorkArea::onScroll()
332 double val = vscrollbar_.get_adjustment()->get_value();
333 scrollDocView(static_cast<int>(val));
337 bool GWorkArea::onButtonPress(GdkEventButton * event)
339 kb_action ka = LFUN_MOUSE_PRESS;
340 switch (event->type) {
341 case GDK_BUTTON_PRESS:
342 ka = LFUN_MOUSE_PRESS;
344 case GDK_2BUTTON_PRESS:
345 ka = LFUN_MOUSE_DOUBLE;
347 case GDK_3BUTTON_PRESS:
348 ka = LFUN_MOUSE_TRIPLE;
353 dispatch(FuncRequest(ka,
354 static_cast<int>(event->x),
355 static_cast<int>(event->y),
356 static_cast<mouse_button::state>(event->button)));
357 workArea_.grab_focus();
362 bool GWorkArea::onButtonRelease(GdkEventButton * event)
364 dispatch(FuncRequest(LFUN_MOUSE_RELEASE,
365 static_cast<int>(event->x),
366 static_cast<int>(event->y),
367 static_cast<mouse_button::state>(event->button)));
372 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
374 static guint32 timeBefore;
375 Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
376 double step = adjustment->get_step_increment();
377 double value = adjustment->get_value();
380 else if (event->x > workArea_.get_height())
382 if (value != adjustment->get_value()) {
383 if (event->time - timeBefore > 200) {
384 adjustment->set_value(value);
385 adjustment->value_changed();
387 timeBefore = event->time;
389 dispatch(FuncRequest(LFUN_MOUSE_MOTION,
390 static_cast<int>(event->x),
391 static_cast<int>(event->y),
392 gtkButtonState(event->state)));
397 void GWorkArea::inputCommit(gchar * str)
399 inputCache_ = Glib::locale_from_utf8(str);
403 bool GWorkArea::onKeyPress(GdkEventKey * event)
407 bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
409 if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
412 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
413 workAreaKeyPress(LyXKeySymPtr(glk),
414 gtkKeyState(event->state));
416 } else if (!inputCache_.empty())
417 workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
423 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
426 selectionRequested();
430 void GWorkArea::onClipboardClear()
436 void GWorkArea::haveSelection(bool toHave) const
439 Glib::RefPtr<Gtk::Clipboard> clipboard =
440 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
441 std::vector<Gtk::TargetEntry> listTargets;
442 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
443 clipboard->set(listTargets,
444 SigC::slot(const_cast<GWorkArea&>(*this),
445 &GWorkArea::onClipboardGet),
446 SigC::slot(const_cast<GWorkArea&>(*this),
447 &GWorkArea::onClipboardClear));
452 string const GWorkArea::getClipboard() const
454 Glib::RefPtr<Gtk::Clipboard> clipboard =
455 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
456 return Glib::locale_from_utf8(clipboard->wait_for_text());
460 void GWorkArea::putClipboard(string const & str) const
462 Glib::RefPtr<Gtk::Clipboard> clipboard =
463 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
464 clipboard->set_text(Glib::locale_to_utf8(str));