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