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