]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GWorkArea.C
gtk_patch_2003_10_30
[lyx.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 using std::string;
25
26
27 ColorCache colorCache;
28
29
30 ColorCache::~ColorCache()
31 {
32         clear();
33 }
34
35
36 Gdk::Color * ColorCache::getColor(LColor_color clr)
37 {
38         MapIt it = cache_.find(clr);
39         return it == cache_.end() ? 0 : it->second;
40 }
41
42
43 XftColor * ColorCache::getXftColor(LColor_color clr)
44 {
45         MapIt2 it = cache2_.find(clr);
46         return it == cache2_.end() ? 0 : it->second;
47 }
48
49
50 void ColorCache::cacheColor(LColor_color clr, Gdk::Color * gclr)
51 {
52         cache_[clr] = gclr;
53 }
54
55
56 void ColorCache::cacheXftColor(LColor_color clr, XftColor * xclr)
57 {
58         cache2_[clr] = xclr;
59 }
60
61
62 void ColorCache::clear()
63 {
64         MapIt it = cache_.begin();
65         for (; it != cache_.end(); ++it)
66                 delete it->second;
67         cache_.clear();
68         MapIt2 it2 = cache2_.begin();
69         for (; it2 != cache2_.end(); ++it2)
70                 delete it2->second;
71         cache2_.clear();
72 }
73
74
75 XftColor * ColorHandler::getXftColor(LColor_color clr)
76 {
77         XftColor * xclr = colorCache.getXftColor(clr);
78         if (!xclr) {
79                 xclr = new XftColor;
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                                   const_cast<char*>(
86                                           lcolor.getX11Name(clr).c_str())
87                                   , xclr);
88                 colorCache.cacheXftColor(clr, xclr);
89         }
90         return xclr;
91 }
92
93
94 Gdk::Color * ColorHandler::getGdkColor(LColor_color clr)
95 {
96         Gdk::Color * gclr = colorCache.getColor(clr);
97         if (!gclr) {
98                 gclr = new Gdk::Color;
99                 gclr->parse(lcolor.getX11Name(clr));
100                 owner_.getColormap()->alloc_color(*gclr);
101                 colorCache.cacheColor(clr, gclr);
102         }
103         return gclr;
104 }
105
106
107 namespace
108 {
109
110
111 mouse_button::state gtkButtonState(unsigned int state)
112 {
113         mouse_button::state b = mouse_button::none;
114         if (state & GDK_BUTTON1_MASK)
115                 b = mouse_button::button1;
116         else if (state & GDK_BUTTON2_MASK)
117                 b = mouse_button::button2;
118         else if (state & GDK_BUTTON3_MASK)
119                 b = mouse_button::button3;
120         else if (state & GDK_BUTTON3_MASK)
121                 b = mouse_button::button3;
122         else if (state & GDK_BUTTON4_MASK)
123                 b = mouse_button::button4;
124         else if (state & GDK_BUTTON5_MASK)
125                 b = mouse_button::button5;
126         return b;
127 }
128
129
130 key_modifier::state gtkKeyState(guint state)
131 {
132         key_modifier::state k = key_modifier::none;
133         if (state & GDK_CONTROL_MASK)
134                 k |= key_modifier::ctrl;
135         if (state & GDK_SHIFT_MASK)
136                 k |= key_modifier::shift;
137         if (state & GDK_MOD1_MASK)
138                 k |= key_modifier::alt;
139         return k;
140 }
141
142
143 void inputCommitRelay(GtkIMContext */*imcontext*/, gchar * str, GWorkArea * area)
144 {
145         area->inputCommit(str);
146 }
147
148
149 }
150
151
152 GWorkArea::GWorkArea(int width, int height)
153         : workAreaPixmap_(0), painter_(*this), draw_(0), colorHandler_(*this)
154 {
155         workArea_.set_size_request(width, height);
156         workArea_.set_double_buffered(false);
157         workArea_.add_events(Gdk::STRUCTURE_MASK | Gdk::EXPOSURE_MASK |
158                              Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK |
159                              Gdk::KEY_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK);
160         workArea_.signal_expose_event().connect(
161                 SigC::slot(*this, &GWorkArea::onExpose));
162         workArea_.signal_configure_event().connect(
163                 SigC::slot(*this, &GWorkArea::onConfigure));
164         workArea_.signal_button_press_event().connect(
165                 SigC::slot(*this, &GWorkArea::onButtonPress));
166         workArea_.signal_button_release_event().connect(
167                 SigC::slot(*this, &GWorkArea::onButtonRelease));
168         workArea_.signal_key_press_event().connect(
169                 SigC::slot(*this, &GWorkArea::onKeyPress));
170         workArea_.signal_motion_notify_event().connect(
171                 SigC::slot(*this, &GWorkArea::onMotionNotify));
172         workArea_.show();
173         vscrollbar_.get_adjustment()->signal_value_changed().connect(
174                 SigC::slot(*this, &GWorkArea::onScroll));
175         vscrollbar_.show();
176         hbox_.children().push_back(Gtk::Box_Helpers::Element(workArea_));
177         hbox_.children().push_back(
178                 Gtk::Box_Helpers::Element(vscrollbar_,Gtk::PACK_SHRINK));
179         hbox_.show();
180         GView::instance()->getVBox().children().push_back(
181                 Gtk::Box_Helpers::Element(hbox_));
182         workArea_.set_flags(workArea_.get_flags() | Gtk::CAN_DEFAULT |
183                             Gtk::CAN_FOCUS);
184         workArea_.grab_default();
185         GView::instance()->setGWorkArea(&workArea_);
186         imContext_ = GTK_IM_CONTEXT(gtk_im_multicontext_new());
187         g_signal_connect(G_OBJECT(imContext_), "commit",
188                          G_CALLBACK(&inputCommitRelay),
189                          this);
190 }
191
192
193 GWorkArea::~GWorkArea()
194 {
195         g_object_unref(imContext_);
196 }
197
198
199 Painter & GWorkArea::getPainter()
200 {
201         return painter_;
202 }
203
204
205 int GWorkArea::workWidth() const
206 {
207         return workArea_.get_width();
208 }
209
210
211 int GWorkArea::workHeight() const
212 {
213         return workArea_.get_height();
214 }
215
216
217 int GWorkArea::xpos() const
218 {
219         return 0;
220 }
221
222
223 int GWorkArea::ypos() const
224 {
225         return 0;
226 }
227
228
229 Glib::RefPtr<Gdk::Window> GWorkArea::getWindow()
230 {
231         return workArea_.get_window();
232 }
233
234
235 Display * GWorkArea::getDisplay() const
236 {
237         return GDK_WINDOW_XDISPLAY(
238                 const_cast<GdkWindow*>(workArea_.get_window()->gobj()));
239 }
240
241
242 Glib::RefPtr<Gdk::Pixmap> GWorkArea::getPixmap()
243 {
244         return workAreaPixmap_;
245 }
246
247
248 Glib::RefPtr<Gdk::GC> GWorkArea::getGC()
249 {
250         return workAreaGC_;
251 }
252
253
254 Glib::RefPtr<Gdk::Colormap> GWorkArea::getColormap()
255 {
256         return workArea_.get_colormap();
257 }
258
259
260 XftDraw * GWorkArea::getXftDraw()
261 {
262         return draw_;
263 }
264
265
266 ColorHandler & GWorkArea::getColorHandler()
267 {
268         return colorHandler_;
269 }
270
271
272 bool GWorkArea::onExpose(GdkEventExpose * event)
273 {
274         workArea_.get_window()->draw_drawable(
275                 workArea_.get_style()->get_black_gc(),
276                 workAreaPixmap_,
277                 event->area.x, event->area.y,
278                 event->area.x, event->area.y,
279                 event->area.width, event->area.height);
280         return true;
281 }
282
283
284 bool GWorkArea::onConfigure(GdkEventConfigure * /*event*/)
285 {
286         int x, y, width, height, depth;
287         workArea_.get_window()->get_geometry(x, y, width, height, depth);
288         if (draw_)
289                 XftDrawDestroy(draw_);
290         workAreaPixmap_ = Gdk::Pixmap::create(workArea_.get_window(),
291                                               width, height, depth);
292         Pixmap pixmap = GDK_PIXMAP_XID(workAreaPixmap_->gobj());
293         Colormap colormap = GDK_COLORMAP_XCOLORMAP(
294                 workArea_.get_colormap()->gobj());
295         Visual * visual = GDK_VISUAL_XVISUAL(
296                 workArea_.get_colormap()->get_visual()->gobj());
297         draw_ = XftDrawCreate(getDisplay(), pixmap,
298                               visual, colormap);
299         if (!workAreaGC_) {
300                 workAreaGC_ = Gdk::GC::create(workArea_.get_window());
301                 Gdk::Cursor cursor(Gdk::XTERM);
302                 workArea_.get_window()->set_cursor(cursor);
303                 gtk_im_context_set_client_window(
304                         imContext_, workArea_.get_window()->gobj());
305         }
306         workAreaResize();
307         return true;
308 }
309
310
311 void GWorkArea::setScrollbarParams(int height, int pos, int line_height)
312 {
313         Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
314         adjustment->set_lower(0);
315         int workAreaHeight = workHeight();
316         if (!height || height < workAreaHeight) {
317                 adjustment->set_upper(workAreaHeight);
318                 adjustment->set_page_size(workAreaHeight);
319                 adjustment->set_value(0);
320                 adjustment->changed();
321                 return;
322         }
323         adjustment->set_step_increment(line_height);
324         adjustment->set_page_increment(workAreaHeight - line_height);
325         adjustment->set_upper(height);
326         adjustment->set_page_size(workAreaHeight);
327         adjustment->set_value(pos);
328         adjustment->changed();
329 }
330
331
332 void GWorkArea::onScroll()
333 {
334         double val = vscrollbar_.get_adjustment()->get_value();
335         scrollDocView(static_cast<int>(val));
336 }
337
338
339 bool GWorkArea::onButtonPress(GdkEventButton * event)
340 {
341         kb_action ka = LFUN_MOUSE_PRESS;
342         switch (event->type) {
343         case GDK_BUTTON_PRESS:
344                 ka = LFUN_MOUSE_PRESS;
345                 break;
346         case GDK_2BUTTON_PRESS:
347                 ka = LFUN_MOUSE_DOUBLE;
348                 break;
349         case GDK_3BUTTON_PRESS:
350                 ka = LFUN_MOUSE_TRIPLE;
351                 break;
352         default:
353                 break;
354         }
355         dispatch(FuncRequest(ka,
356                              static_cast<int>(event->x),
357                              static_cast<int>(event->y),
358                              static_cast<mouse_button::state>(event->button)));
359         workArea_.grab_focus();
360         return true;
361 }
362
363
364 bool GWorkArea::onButtonRelease(GdkEventButton * event)
365 {
366         dispatch(FuncRequest(LFUN_MOUSE_RELEASE,
367                              static_cast<int>(event->x),
368                              static_cast<int>(event->y),
369                              static_cast<mouse_button::state>(event->button)));
370         return true;
371 }
372
373
374 bool GWorkArea::onMotionNotify(GdkEventMotion * event)
375 {
376         static guint32 timeBefore;
377         Gtk::Adjustment * adjustment = vscrollbar_.get_adjustment();
378         double step = adjustment->get_step_increment();
379         double value = adjustment->get_value();
380         if (event->x < 0)
381                 value -= step;
382         else if (event->x > workArea_.get_height())
383                 value += step;
384         if (value != adjustment->get_value()) {
385                 if (event->time - timeBefore > 200) {
386                         adjustment->set_value(value);
387                         adjustment->value_changed();
388                 }
389                 timeBefore = event->time;
390         }
391         dispatch(FuncRequest(LFUN_MOUSE_MOTION,
392                              static_cast<int>(event->x),
393                              static_cast<int>(event->y),
394                              gtkButtonState(event->state)));
395         return true;
396 }
397
398
399 void GWorkArea::inputCommit(gchar * str)
400 {
401         inputCache_ = Glib::locale_from_utf8(str);
402 }
403
404
405 bool GWorkArea::onKeyPress(GdkEventKey * event)
406 {
407 #ifdef I18N
408         inputCache_ = "";
409         bool inputGet = gtk_im_context_filter_keypress(imContext_, event);
410         // cope with ascii
411         if ((inputGet && inputCache_.size() == 1 && inputCache_[0] < 128) ||
412             !inputGet) {
413 #endif
414                 GLyXKeySym *glk = new GLyXKeySym(event->keyval);
415                 workAreaKeyPress(LyXKeySymPtr(glk),
416                                  gtkKeyState(event->state));
417 #ifdef I18N
418         } else if (!inputCache_.empty())
419                 workAreaCJK_IMprocess(inputCache_.size(), inputCache_.data());
420 #endif
421         return true;
422 }
423
424
425 void GWorkArea::onClipboardGet(Gtk::SelectionData & /*selection_data*/,
426                                guint /*info*/)
427 {
428         selectionRequested();
429 }
430
431
432 void GWorkArea::onClipboardClear()
433 {
434 //      selectionLost();
435 }
436
437
438 void GWorkArea::haveSelection(bool toHave) const
439 {
440         if (toHave) {
441                 Glib::RefPtr<Gtk::Clipboard> clipboard =
442                         Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
443                 std::vector<Gtk::TargetEntry> listTargets;
444                 listTargets.push_back(Gtk::TargetEntry("UTF8_STRING"));
445                 clipboard->set(listTargets,
446                                SigC::slot(const_cast<GWorkArea&>(*this),
447                                           &GWorkArea::onClipboardGet),
448                                SigC::slot(const_cast<GWorkArea&>(*this),
449                                           &GWorkArea::onClipboardClear));
450         }
451 }
452
453
454 string const GWorkArea::getClipboard() const
455 {
456         Glib::RefPtr<Gtk::Clipboard> clipboard =
457                 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
458         return Glib::locale_from_utf8(clipboard->wait_for_text());
459 }
460
461
462 void GWorkArea::putClipboard(string const & str) const
463 {
464         Glib::RefPtr<Gtk::Clipboard> clipboard =
465                 Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
466         clipboard->set_text(Glib::locale_to_utf8(str));
467 }