]> git.lyx.org Git - features.git/blob - src/frontends/gtk/GWorkArea.C
a407f549f8251392c810794677dcfc643d5e6b17
[features.git] / src / frontends / gtk / GWorkArea.C
1 /**
2  * \file GWorkArea.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Huang Ying
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12 #include <gtkmm.h>
13 #include <X11/Xft/Xft.h>
14
15 #include "GWorkArea.h"
16 #include "debug.h"
17 #include "funcrequest.h"
18 #include "GView.h"
19 #include "GtkmmX.h"
20 #include "GLyXKeySym.h"
21
22 ColorCache colorCache;
23
24
25 void ColorCache::clear()
26 {
27         MapIt it = cache_.begin();
28         for (; it != cache_.end(); ++it)
29                 delete it->second;
30         cache_.clear();
31         MapIt2 it2 = cache2_.begin();
32         for (; it2 != cache2_.end(); ++it2)
33                 delete it2->second;
34         cache2_.clear();
35 }
36
37
38 XftColor * ColorHandler::getXftColor(LColor::color clr)
39 {
40         XftColor * xclr = colorCache.getXftColor(clr);
41         if (!xclr) {
42                 xclr = new XftColor;
43                 Colormap colormap = GDK_COLORMAP_XCOLORMAP(
44                         owner_.getColormap()->gobj());
45                 Visual * visual = GDK_VISUAL_XVISUAL(
46                         owner_.getColormap()->get_visual()->gobj());
47                 XftColorAllocName(owner_.getDisplay(), visual, colormap,
48                                   lcolor.getX11Name(clr).c_str(), xclr);
49                 colorCache.cacheXftColor(clr, xclr);
50         }
51         return xclr;
52 }
53
54
55 Gdk::Color * ColorHandler::getGdkColor(LColor::color clr)
56 {
57         Gdk::Color * gclr = colorCache.getColor(clr);
58         if (!gclr) {
59                 gclr = new Gdk::Color;
60                 gclr->parse(lcolor.getX11Name(clr));
61                 owner_.getColormap()->alloc_color(*gclr);
62                 colorCache.cacheColor(clr, gclr);
63         }
64         return gclr;
65 }
66
67
68 namespace
69 {
70
71
72 mouse_button::state gtkButtonState(unsigned int state)
73 {
74         mouse_button::state b = mouse_button::none;
75         if (state & GDK_BUTTON1_MASK)
76                 b = mouse_button::button1;
77         else if (state & GDK_BUTTON2_MASK)
78                 b = mouse_button::button2;
79         else if (state & GDK_BUTTON3_MASK)
80                 b = mouse_button::button3;
81         else if (state & GDK_BUTTON3_MASK)
82                 b = mouse_button::button3;
83         else if (state & GDK_BUTTON4_MASK)
84                 b = mouse_button::button4;
85         else if (state & GDK_BUTTON5_MASK)
86                 b = mouse_button::button5;
87         return b;
88 }
89
90
91 key_modifier::state gtkKeyState(guint state)
92 {
93         key_modifier::state k = key_modifier::none;
94         if (state & GDK_CONTROL_MASK)
95                 k |= key_modifier::ctrl;
96         if (state & GDK_SHIFT_MASK)
97                 k |= key_modifier::shift;
98         if (state & GDK_MOD1_MASK)
99                 k |= key_modifier::alt;
100         return k;
101 }
102
103
104 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
105 {
106         area->inputCommit(str);
107 }
108
109
110 }
111
112
113 GWorkArea::GWorkArea(int width, int height)
114         : workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this)
115 {
116         workArea_.set_size_request(width, height);
117         workArea_.set_double_buffered(false);
118         workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
119                              Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
120                              Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
121         workArea_.signal_expose_event().connect(
122                 SigC::slot(*this, &GWorkArea::onExpose));
123         workArea_.signal_configure_event().connect(
124                 SigC::slot(*this, &GWorkArea::onConfigure));
125         workArea_.signal_button_press_event().connect(
126                 SigC::slot(*this, &GWorkArea::onButtonPress));
127         workArea_.signal_button_release_event().connect(
128                 SigC::slot(*this, &GWorkArea::onButtonRelease));
129         workArea_.signal_key_press_event().connect(
130                 SigC::slot(*this, &GWorkArea::onKeyPress));
131         workArea_.signal_motion_notify_event().connect(
132                 SigC::slot(*this, &GWorkArea::onMotionNotify));
133         workArea_.show();
134         vscrollbar_.get_adjustment()->signal_value_changed().connect(
135                 SigC::slot(*this, &GWorkArea::onScroll));
136         vscrollbar_.show();
137         hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
138         hbox_.children().push_back(
139                 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
140         hbox_.show();
141         GView::instance()->getVBox().children().push_back(
142                 Gtk::Box_Helpers::Element(hbox_));
143         workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
144                             Gtk::CAN_FOCUS);
145         workArea_.grab_default();
146         GView::instance()->setGWorkArea(&workArea_);
147         imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
148         g_signal_connect(G_OBJECT(imContext_), "commit",
149                          G_CALLBACK(&inputCommitRelay),
150                          this);
151 }
152
153
154 GWorkArea::~GWorkArea()
155 {
156         g_object_unref(imContext_);
157 }
158
159
160 bool GWorkArea::onExpose(GdkEventExpose * event)
161 {
162         workArea_.get_window()->draw_drawable(
163                 workArea_.get_style()->get_black_gc(),
164                 workAreaPixmap_,
165                 event->area.x, event->area.y,
166                 event->area.x, event->area.y,
167                 event->area.width, event->area.height);
168         return true;
169 }
170
171
172 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
173 {
174         int x, y, width, height, depth;
175         workArea_.get_window()->get_geometry(x, y, width, height, depth);
176         if (draw_)
177                 XftDrawDestroy(draw_);
178         workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
179                                               width, height, depth);
180         Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
181         Colormap colormap = GDK_COLORMAP_XCOLORMAP(
182                 workArea_.get_colormap()->gobj());
183         Visual * visual = GDK_VISUAL_XVISUAL(
184                 workArea_.get_colormap()->get_visual()->gobj());
185         draw_ = XftDrawCreate(getDisplay(), pixmap,
186                               visual, colormap);
187         if (!workAreaGC_) {
188                 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
189                 Gdk::Cursor cursor(Gdk::XTERM);
190                 workArea_.get_window()->set_cursor(cursor);
191                 gtk_im_context_set_client_window(
192                         imContext_, workArea_.get_window()->gobj());
193         }
194         workAreaResize();
195         return true;
196 }
197
198
199 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
200 {
201         Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
202         adjustment->set_lower(0);
203         int workAreaHeight = workHeight();
204         if (!height || height < workAreaHeight) {
205                 adjustment->set_upper(workAreaHeight);
206                 adjustment->set_page_size(workAreaHeight);
207                 adjustment->set_value(0);
208                 adjustment->changed();
209                 return;
210         }
211         adjustment->set_step_increment(line_height);
212         adjustment->set_page_increment(workAreaHeight - line_height);
213         adjustment->set_upper(height);
214         adjustment->set_page_size(workAreaHeight);
215         adjustment->set_value(pos);
216         adjustment->changed();
217 }
218
219
220 void GWorkArea::onScroll()
221 {
222         double val = vscrollbar_.get_adjustment()->get_value();
223         scrollDocView(static_cast<int>(val));
224 }
225
226
227 bool GWorkArea::onButtonPress(GdkEventButton * event)
228 {
229         kb_action ka = LFUN_MOUSE_PRESS;
230         switch (event->type) {
231         case GDK_BUTTON_PRESS:
232                 ka = LFUN_MOUSE_PRESS;
233                 break;
234         case GDK_2BUTTON_PRESS:
235                 ka = LFUN_MOUSE_DOUBLE;
236                 break;
237         case GDK_3BUTTON_PRESS:
238                 ka = LFUN_MOUSE_TRIPLE;
239                 break;
240         default:
241                 break;
242         }
243         dispatch(FuncRequest(ka,
244                              static_cast<int>(event->x),
245                              static_cast<int>(event->y),
246                              static_cast<mouse_button::state>(event->button)));
247         workArea_.grab_focus();
248         return true;
249 }
250
251
252 bool GWorkArea::onButtonRelease(GdkEventButton * event)
253 {
254         dispatch(FuncRequest(LFUN_MOUSE_RELEASE,
255                              static_cast<int>(event->x),
256                              static_cast<int>(event->y),
257                              static_cast<mouse_button::state>(event->button)));
258         return true;
259 }
260
261
262 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
263 {
264         static guint32 timeBefore;
265         Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
266         double step = adjustment->get_step_increment();
267         double value = adjustment->get_value();
268         if (event->x < 0)
269                 value -= step;
270         else if (event->x > workArea_.get_height())
271                 value += step;
272         if (value != adjustment->get_value()) {
273                 if (event->time - timeBefore > 200) {
274                         adjustment->set_value(value);
275                         adjustment->value_changed();
276                 }
277                 timeBefore = event->time;
278         }
279         dispatch(FuncRequest(LFUN_MOUSE_MOTION,
280                              static_cast<int>(event->x),
281                              static_cast<int>(event->y),
282                              gtkButtonState(event->state)));
283         return true;
284 }
285
286
287 void GWorkArea::inputCommit(gchar * str)
288 {
289         inputCache_ = Glib::locale_from_utf8(str);
290 }
291
292
293 bool GWorkArea::onKeyPress(GdkEventKey * event)
294 {
295 #ifdef I18N
296         inputCache_ = "";
297         bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
298         // cope with ascii
299         if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
300             !inputGet) {
301 #endif
302                 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
303                 workAreaKeyPress(LyXKeySymPtr(glk),
304                                  gtkKeyState(event->state));
305 #ifdef I18N
306         } else if (!inputCache_.empty())
307                 workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
308 #endif
309         return true;
310 }
311
312
313 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
314                                guint /*info*/)
315 {
316         selectionRequested();
317 }
318
319
320 void GWorkArea::onClipboardClear()
321 {
322 //      selectionLost();
323 }
324
325
326 void GWorkArea::haveSelection(bool toHave) const
327 {
328         if (toHave) {
329                 Glib::RefPtr<Gtk::Clipboard> clipboard =
330                         Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
331                 std::vector<Gtk::TargetEntry> listTargets;
332                 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
333                 clipboard->set(listTargets,
334                                SigC::slot(const_cast<GWorkArea&>(*this),
335                                           &GWorkArea::onClipboardGet),
336                                SigC::slot(const_cast<GWorkArea&>(*this),
337                                           &GWorkArea::onClipboardClear));
338         }
339 }
340
341
342 string const GWorkArea::getClipboard() const
343 {
344         Glib::RefPtr<Gtk::Clipboard> clipboard =
345                 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
346         return Glib::locale_from_utf8(clipboard->wait_for_text());
347 }
348
349
350 void GWorkArea::putClipboard(string const & str) const
351 {
352         Glib::RefPtr<Gtk::Clipboard> clipboard =
353                 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
354         clipboard->set_text(Glib::locale_to_utf8(str));
355 }