PageRenderTime 84ms CodeModel.GetById 41ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/TeXmacs-1.0.7.11-src/src/Plugins/Qt/QTMWidget.cpp

#
C++ | 830 lines | 602 code | 108 blank | 120 comment | 133 complexity | 0e016c92abefb8303e941fbf1025b450 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception
  1
  2/******************************************************************************
  3* MODULE     : QTMWidget.cpp
  4* DESCRIPTION: QT Texmacs widget class
  5* COPYRIGHT  : (C) 2008 Massimiliano Gubinelli and Joris van der Hoeven
  6*******************************************************************************
  7* This software falls under the GNU general public license version 3 or later.
  8* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
  9* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
 10******************************************************************************/
 11
 12#include <QtGui>
 13
 14#include "QTMWidget.hpp"
 15#include "qt_renderer.hpp"
 16#include "qt_gui.hpp"
 17#include "qt_utilities.hpp"
 18#include "qt_simple_widget.hpp"
 19#include "converter.hpp"
 20
 21#include "config.h"
 22#include "message.hpp" 
 23
 24#ifdef USE_CAIRO
 25#include "Cairo/cairo_renderer.hpp"
 26#include "Cairo/tm_cairo.hpp"
 27
 28#if defined(Q_WS_X11)
 29#include <QX11Info>
 30extern Drawable qt_x11Handle(const QPaintDevice *pd);
 31extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
 32#undef KeyPress  // conflict between QEvent::KeyPrees and X11 defintion
 33#endif // Q_WS_X11
 34
 35#endif // USE_CAIRO
 36
 37#include <QEvent>
 38
 39#define PIXEL 256
 40
 41QSet<QTMWidget*> QTMWidget::all_widgets;
 42
 43
 44hashmap<int,string> qtkeymap (0);
 45hashmap<int,string> qtdeadmap (0);
 46
 47inline void
 48scale (QPoint& point) {
 49  point.rx() *= PIXEL; point.ry() *= -PIXEL;
 50}
 51
 52inline void
 53map (int code, string name) {
 54  qtkeymap(code) = name;
 55}
 56inline void
 57deadmap (int code, string name) {
 58  qtdeadmap(code) = name;
 59}
 60
 61void
 62initkeymap () {
 63  map (Qt::Key_Space     , "space");
 64  map (Qt::Key_Return    , "return");
 65  map (Qt::Key_Tab       , "tab");
 66  map (Qt::Key_Backspace , "backspace");
 67  map (Qt::Key_Enter     , "enter");
 68  map (Qt::Key_Escape    , "escape");
 69  map (Qt::Key_Backspace , "backspace");
 70  map (Qt::Key_Up        , "up" );
 71  map (Qt::Key_Down      , "down" );
 72  map (Qt::Key_Left      , "left" );
 73  map (Qt::Key_Right     , "right" );
 74  map (Qt::Key_F1        , "F1" );
 75  map (Qt::Key_F2        , "F2" );
 76  map (Qt::Key_F3        , "F3" );
 77  map (Qt::Key_F4        , "F4" );
 78  map (Qt::Key_F5        , "F5" );
 79  map (Qt::Key_F6        , "F6" );
 80  map (Qt::Key_F7        , "F7" );
 81  map (Qt::Key_F8        , "F8" );
 82  map (Qt::Key_F9        , "F9" );
 83  map (Qt::Key_F10       , "F10" );
 84  map (Qt::Key_F11       , "F11" );
 85  map (Qt::Key_F12       , "F12" );
 86  map (Qt::Key_F13       , "F13" );
 87  map (Qt::Key_F14       , "F14" );
 88  map (Qt::Key_F15       , "F15" );
 89  map (Qt::Key_F16       , "F16" );
 90  map (Qt::Key_F17       , "F17" );
 91  map (Qt::Key_F18       , "F18" );
 92  map (Qt::Key_F19       , "F19" );
 93  map (Qt::Key_F20       , "F20" );
 94  map (Qt::Key_F21       , "F21" );
 95  map (Qt::Key_F22       , "F22" );
 96  map (Qt::Key_F23       , "F23" );
 97  map (Qt::Key_F24       , "F24" );
 98  map (Qt::Key_F25       , "F25" );
 99  map (Qt::Key_F26       , "F26" );
100  map (Qt::Key_F27       , "F27" );
101  map (Qt::Key_F28       , "F28" );
102  map (Qt::Key_F29       , "F29" );
103  map (Qt::Key_F30       , "F30" );
104  map (Qt::Key_F31       , "F31" );
105  map (Qt::Key_F32       , "F32" );
106  map (Qt::Key_F33       , "F33" );
107  map (Qt::Key_F34       , "F34" );
108  map (Qt::Key_F35       , "F35" );
109  map (Qt::Key_Insert    , "insert" );
110  map (Qt::Key_Delete    , "delete" );
111  map (Qt::Key_Home      , "home" );
112  map (Qt::Key_End       , "end" );
113  map (Qt::Key_PageUp    , "pageup" );
114  map (Qt::Key_PageDown  , "pagedown" );
115  map (Qt::Key_ScrollLock, "scrolllock" );
116  map (Qt::Key_Pause     , "pause" );
117  map (Qt::Key_SysReq    , "sysreq" );
118  map (Qt::Key_Stop      , "stop" );
119  map (Qt::Key_Menu      , "menu" );
120  map (Qt::Key_Print     , "print" );
121  map (Qt::Key_Select    , "select" );
122  map (Qt::Key_Execute   , "execute" );
123  map (Qt::Key_Help      , "help" );
124
125  deadmap (Qt::Key_Dead_Acute     , "acute");
126  deadmap (Qt::Key_Dead_Grave     , "grave");
127  deadmap (Qt::Key_Dead_Diaeresis , "umlaut");
128  deadmap (Qt::Key_Dead_Circumflex, "hat");
129  deadmap (Qt::Key_Dead_Tilde     , "tilde");
130
131  // map (0x0003              , "K-enter");
132  // map (Qt::Key_Begin       , "begin" );
133  // map (Qt::Key_PrintScreen , "printscreen" );
134  // map (Qt::Key_Break       , "break" );
135  // map (Qt::Key_User        , "user" );
136  // map (Qt::Key_System      , "system" );
137  // map (Qt::Key_Reset       , "reset" );
138  // map (Qt::Key_ClearLine   , "clear" );
139  // map (Qt::Key_ClearDisplay, "cleardisplay" );
140  // map (Qt::Key_InsertLine  , "insertline" );
141  // map (Qt::Key_DeleteLine  , "deleteline" );
142  // map (Qt::Key_InsertChar  , "insert" );
143  // map (Qt::Key_DeleteChar  , "delete" );
144  // map (Qt::Key_Prev        , "prev" );
145  // map (Qt::Key_Next        , "next" );
146  // map (Qt::Key_Undo        , "undo" );
147  // map (Qt::Key_Redo        , "redo" );
148  // map (Qt::Key_Find        , "find" );
149  // map (Qt::Key_ModeSwitchFunctionKey, "modeswitch" );
150}
151
152
153
154QTMWidget::QTMWidget (simple_widget_rep *_wid) 
155  : QTMScrollView (), backingPixmap(), imwidget(NULL) {
156  setObjectName("A QTMWidget");
157  setProperty ("texmacs_widget", QVariant::fromValue ((void*) _wid));
158  surface()->setMouseTracking (true);
159  setFocusPolicy (Qt::StrongFocus);
160  backing_pos = origin();
161  setAttribute(Qt::WA_InputMethodEnabled);
162}
163
164
165QTMWidget::~QTMWidget () {
166  if (DEBUG_QT) cout << "destroying " << this << LF;
167}
168
169void 
170QTMWidget::invalidate_rect (int x1, int y1, int x2, int y2) {
171#ifdef Q_WS_MAC
172  //HACK: for unknown reasons we need to enlarge the invalid rect to prevent
173  //artifacts while moving the cursor (for example at the end of a formula like
174  // $a+f$. These artifacts seems present only on 64 bit Macs. 
175  rectangle r = rectangle (x1-10, y1-10, x2+10, y2+10);
176#else
177  rectangle r = rectangle (x1, y1, x2, y2);
178#endif
179  // cout << "invalidating " << r << LF;
180  invalid_regions = invalid_regions | rectangles (r);
181}
182
183void 
184QTMWidget::invalidate_all () {
185  QSize sz = surface()->size();
186 // QPoint pt = QAbstractScrollArea::viewport()->pos();
187   //cout << "invalidate all " << LF;
188  invalid_regions = rectangles();
189  invalidate_rect (0, 0, sz.width(), sz.height());
190}
191
192
193basic_renderer_rep* 
194QTMWidget::getRenderer() {
195#ifdef USE_CAIRO
196  cairo_renderer_rep *ren = the_cairo_renderer ();
197  cairo_surface_t *surf;
198#ifdef Q_WS_X11
199  //const QX11Info & info = x11Info();//qt_x11Info(this);
200  //    Display *dpy = x11Info().display();
201  //backingPixmap = QPixmap(width(),height());
202  //cout << backingPixmap.width() << LF;
203  Display *dpy = QX11Info::display();
204  Drawable drawable = backingPixmap.handle();
205  Visual *visual = (Visual*)(backingPixmap.x11Info().visual());
206  surf = tm_cairo_xlib_surface_create (dpy, drawable, visual, 
207                            backingPixmap.width (), backingPixmap.height ());
208#elif defined(Q_WS_MAC)
209  surf = tm_cairo_quartz_surface_create_for_cg_context (
210                    (CGContextRef)(this->macCGHandle()), width(), height());
211#endif
212  cairo_t *ct = tm_cairo_create (surf);
213  ren->begin (ct);
214  tm_cairo_surface_destroy (surf);
215  tm_cairo_destroy (ct);
216#else
217  qt_renderer_rep * ren = the_qt_renderer();
218  ren->begin(&backingPixmap);
219#endif
220  return ren;
221}
222
223void
224QTMWidget::repaint_invalid_regions () {
225
226  // this function is called by the qt_gui::update method to keep the backing
227  // store in sync and propagate the changes to the surface on screen.
228  // first we check that the backing store geometry is right and then we
229  // request to the texmacs canvas widget to repaint the regions which were
230  // marked invalid. Subsequently, for each succesfully repainted region, we
231  // propagate its contents from the backing store to the onscreen surface.
232  // If repaint has been interrupted we do not propagate the changes and proceed
233  // to mark the region invalid again.
234
235  QRegion qrgn; 
236  // qrgn is to keep track of the area on the sceen which needs to be updated 
237
238  // update backing store origin wrt. TeXmacs document
239  if ( backing_pos != origin() ) {
240
241    int dx =  origin().x() - backing_pos.x();
242    int dy =  origin().y() - backing_pos.y();
243    backing_pos = origin();
244    
245    QPixmap newBackingPixmap (backingPixmap.size());
246    QPainter p (&newBackingPixmap);
247    //newBackingPixmap.fill(Qt::black);
248    p.drawPixmap(-dx,-dy,backingPixmap);
249    p.end();
250    backingPixmap = newBackingPixmap;
251    //cout << "SCROLL CONTENTS BY " << dx << " " << dy << LF;
252    
253    QSize sz = backingPixmap.size();
254    
255    rectangles invalid;
256    while (!is_nil(invalid_regions)) {
257      rectangle r = invalid_regions->item ;
258      //      rectangle q = rectangle(r->x1+dx,r->y1-dy,r->x2+dx,r->y2-dy);
259      rectangle q = rectangle(r->x1-dx,r->y1-dy,r->x2-dx,r->y2-dy);
260      invalid = rectangles (q, invalid);
261      //cout << r << " ---> " << q << LF;
262      invalid_regions = invalid_regions->next;
263    }
264    invalid_regions= invalid & 
265    rectangles(rectangle(0,0,
266                         sz.width(),sz.height())) ;
267    
268    if (dy<0) 
269      invalidate_rect(0,0,sz.width(),min(sz.height(),-dy));
270    else if (dy>0)
271      invalidate_rect(0,max(0,sz.height()-dy),sz.width(),sz.height());
272    
273    if (dx<0) 
274      invalidate_rect(0,0,min(-dx,sz.width()),sz.height());
275    else if (dx>0)
276      invalidate_rect(max(0,sz.width()-dx),0,sz.width(),sz.height());
277    
278    // we cal update now to allow repainint of invalid regions
279    // this cannot be done directly since interpose handler needs
280    // to be run at least once in some situations
281    // (for example when scrolling is initiated by TeXmacs itself)
282    //the_gui->update();
283    //  QAbstractScrollArea::viewport()->scroll(-dx,-dy);
284   // QAbstractScrollArea::viewport()->update();
285    qrgn += QRect(QPoint(0,0),sz);
286  }
287  
288  
289  // update backing store size
290  {
291    QSize _oldSize = backingPixmap.size();
292    QSize _newSize = surface()->size();
293    if (_newSize != _oldSize) {
294      // cout << "RESIZING BITMAP"<< LF;
295      QPixmap newBackingPixmap (_newSize);
296      QPainter p (&newBackingPixmap);
297      p.drawPixmap(0,0,backingPixmap);
298      //p.fillRect(0, 0, _newSize.width(), _newSize.height(), Qt::red);
299      if (_newSize.width() >= _oldSize.width()) {
300        invalidate_rect(_oldSize.width(), 0, _newSize.width(), _newSize.height());
301        p.fillRect(QRect(_oldSize.width(), 0, _newSize.width()-_oldSize.width(), _newSize.height()), Qt::gray);
302      }
303      if (_newSize.height() >= _oldSize.height()) {
304        invalidate_rect(0,_oldSize.height(), _newSize.width(), _newSize.height());
305        p.fillRect(QRect(0,_oldSize.height(), _newSize.width(), _newSize.height()-_oldSize.height()), Qt::gray);
306      }
307      p.end();
308      backingPixmap = newBackingPixmap;
309    }
310  }
311  
312  // repaint invalid rectangles
313  {
314    rectangles new_regions;
315    if (!is_nil (invalid_regions)) {
316      rectangle lub= least_upper_bound (invalid_regions);
317      if (area (lub) < 1.2 * area (invalid_regions))
318        invalid_regions= rectangles (lub);
319      
320      basic_renderer_rep* ren = getRenderer();
321      tm_widget()->set_current_renderer(ren);
322      
323      SI ox = -backing_pos.x()*PIXEL;
324      SI oy = backing_pos.y()*PIXEL;
325      
326      rectangles rects = invalid_regions;
327      invalid_regions = rectangles();
328      
329      while (!is_nil (rects)) {
330        rectangle r = copy (rects->item);
331        rectangle r0 = rects->item;
332        QRect qr = QRect(r0->x1, r0->y1, r0->x2 - r0->x1, r0->y2 - r0->y1);
333        //cout << "repainting " << r0 << "\n";
334        ren->set_origin(ox,oy); 
335        ren->encode (r->x1, r->y1);
336        ren->encode (r->x2, r->y2);
337        ren->set_clipping (r->x1, r->y2, r->x2, r->y1);
338        tm_widget()->handle_repaint (r->x1, r->y2, r->x2, r->y1);
339        if (ren->interrupted ()) {
340          //cout << "interrupted repainting of  " << r0 << "\n";
341          //ren->set_color(green);
342          //ren->line(r->x1, r->y1, r->x2, r->y2);
343          //ren->line(r->x1, r->y2, r->x2, r->y1);
344          invalidate_rect (r0->x1, r0->y1, r0->x2, r0->y2);
345        } 
346        qrgn += qr;
347        rects = rects->next;
348      }
349      
350      tm_widget()->set_current_renderer(NULL);
351      ren->end();
352    } // !is_nil(invalid_regions)
353    
354  }
355
356  // propagate immediatly the changes to the screen  
357  surface()->repaint(qrgn);
358  
359}
360
361void 
362QTMWidget::scrollContentsBy ( int dx, int dy ) {
363  QTMScrollView::scrollContentsBy (dx,dy);
364
365  force_update();
366  // we force an update of the internal state to be in sync with the moving
367  // scrollbars
368}
369
370void 
371QTMWidget::resizeEvent( QResizeEvent* event ) {
372  (void) event;
373  
374  // cout << "QTMWidget::resizeEvent (" << event->size().width()
375  //      << "," << event->size().height() << ")" << LF;
376  
377  the_gui -> process_resize(tm_widget(), 0, 0); // FIXME
378
379  // force_update();
380
381  //FIXME: I would like to have a force_update here but this cause a failed
382  //assertion in TeXmacs since the at the boot not every internal structure is
383  //initialized at this point. It seems not too difficult to fix but I
384  //postpone this to discuss with Joris. 
385  //
386  //Not having a force_update results in some lack of sync of the surface
387  //while the user is actively resizing with the mouse.
388}
389
390
391
392
393void
394QTMWidget::paintEvent (QPaintEvent* event) {
395  // In the current implementation repainting take place during the call to
396  // the widget's repaint_invalid_regions method in the_gui::update. All
397  // we have to do is to take the backing store and put it on screen according
398  // to the QRegion marked invalid. 
399  // CHECK: Maybe just put onscreen all the region bounding rectangle could not 
400  // be so expensive.
401  
402  
403  if (DEBUG_QT) 
404  {
405    QRect rect = event->rect ();
406    cout << "paintEvent ("<< rect.x() << "," <<  rect.y()
407    << "," <<  rect.width() << "," <<  rect.height() << ")" << LF ;
408  }
409    
410  {    
411    QPainter p (surface());
412    QVector<QRect> rects = event->region().rects();
413    for (int i=0; i< rects.count(); i++) {
414      QRect qr = rects.at(i);
415      p.drawPixmap(qr,backingPixmap,qr);
416    }
417  } 
418  
419}
420
421
422void
423QTMWidget::keyPressEvent (QKeyEvent* event) {
424  static bool fInit = false;
425  if (!fInit) {
426    if (DEBUG_QT)
427      cout << "Initializing keymap\n";
428    initkeymap();
429    fInit= true;
430  }
431
432  if (DEBUG_QT)
433    cout << "keypressed\n";
434  simple_widget_rep *wid =  tm_widget();
435  if (!wid) return;
436
437  {
438    int key = event->key();
439    Qt::KeyboardModifiers mods = event->modifiers();
440
441    if (DEBUG_QT) {
442      cout << "key  : " << key << LF;
443      cout << "text : " << event->text().toAscii().data() << LF;
444      cout << "count: " << event->text().count() << LF;
445      if (mods & Qt::ShiftModifier) cout << "shift\n";
446      if (mods & Qt::MetaModifier) cout << "meta\n";
447      if (mods & Qt::ControlModifier) cout << "control\n";
448      if (mods & Qt::KeypadModifier) cout << "keypad\n";
449      if (mods & Qt::AltModifier) cout << "alt\n";
450    }
451
452    string r;
453    if (qtkeymap->contains (key)) {
454      r = qtkeymap[key];
455    } else if (qtdeadmap->contains (key)) {
456      mods &=~ Qt::ShiftModifier;
457      r = qtdeadmap[key];
458    } else {
459      QString nss = event->text();
460      unsigned short unic= nss.data()[0].unicode();
461      if (unic < 32 && key < 128 && key > 0) {
462        if (((char) key) >= 'A' && ((char) key) <= 'Z') {
463          if ((mods & Qt::ShiftModifier) == 0)
464            key= (int) (key + ((int) 'a') - ((int) 'A'));
465        }
466        mods &=~ Qt::ShiftModifier;
467        r= string ((char) key);
468      } else {
469        switch(unic) {
470        case 96:   r= "`"; 
471            // unicode to cork conversion not appropriate for this case...
472#ifdef Q_WS_MAC
473          // CHECKME: are these two MAC exceptions really needed?
474                   if (mods & Qt::AltModifier) r= "grave";
475#endif
476                   break;
477        case 168:  r= "umlaut"; break;
478        case 180:  r= "acute"; break;
479        // the following combining characters should be caught by qtdeadmap
480        case 0x300: r= "grave"; break;
481        case 0x301: r= "acute"; break;
482        case 0x302: r= "hat"; break;
483        case 0x308: r= "umlaut"; break;
484        case 0x33e: r= "tilde"; break;
485        default:
486          QByteArray buf= nss.toUtf8();
487          string rr (buf.constData(), buf.count());
488          r= utf8_to_cork (rr);
489          if (r == "<less>") r= "<";
490          if (r == "<gtr>") r= ">";
491        }
492#ifdef Q_WS_MAC
493        // CHECKME: are these two MAC exceptions really needed?
494        mods &=~ Qt::AltModifier;
495#endif
496        mods &=~ Qt::ShiftModifier;
497      }
498    }
499
500    if (r == "") return;
501
502#ifdef Q_WS_MAC
503    if (mods & Qt::ShiftModifier) r= "S-" * r;
504    if (mods & Qt::MetaModifier) r= "C-" * r;        // The "Control" key
505    if (mods & Qt::AltModifier) r= "A-" * r;
506    if (mods & Qt::ControlModifier) r= "M-" * r;  // The "Command" key
507    //if (mods & Qt::KeypadModifier) r= "K-" * r;
508#else
509    if (mods & Qt::ShiftModifier) r= "S-" * r;
510    if (mods & Qt::ControlModifier) r= "C-" * r;
511    if (mods & Qt::AltModifier) r= "A-" * r;
512    if (mods & Qt::MetaModifier) r= "M-" * r;     // The "Windows" key
513    //if (mods & Qt::KeypadModifier) r= "K-" * r;
514#endif
515
516    if (DEBUG_QT)
517      cout << "key press: " << r << LF;
518    //int start= texmacs_time ();
519    //wid -> handle_keypress (r, texmacs_time());
520    the_gui -> process_keypress (wid, r, texmacs_time());
521    //int end= texmacs_time ();
522    //if (end > start) cout << "Keypress " << end - start << "\n";
523  //  the_gui->update (); // FIXME: remove this line when
524                        // edit_typeset_rep::get_env_value will be faster
525    
526//    needs_update();
527  }
528}
529
530static unsigned int
531mouse_state (QMouseEvent* event, bool flag) {
532  unsigned int i= 0;
533  Qt::MouseButtons bstate= event->buttons ();
534  Qt::MouseButton  tstate= event->button ();
535  Qt::KeyboardModifiers kstate= event->modifiers ();
536  if (flag) bstate= bstate | tstate;
537  if ((bstate & Qt::LeftButton     ) != 0) i += 1;
538  if ((bstate & Qt::MidButton      ) != 0) i += 2;
539  if ((bstate & Qt::RightButton    ) != 0) i += 4;
540  if ((bstate & Qt::XButton1       ) != 0) i += 8;
541  if ((bstate & Qt::XButton2       ) != 0) i += 16;
542#ifdef Q_WS_MAC
543  if ((kstate & Qt::AltModifier    ) != 0) i = 2;
544  if ((kstate & Qt::MetaModifier   ) != 0) i = 4;
545  if ((kstate & Qt::ShiftModifier  ) != 0) i += 256;
546  if ((kstate & Qt::ControlModifier) != 0) i += 2048;
547#else
548  if ((kstate & Qt::ShiftModifier  ) != 0) i += 256;
549  if ((kstate & Qt::ControlModifier) != 0) i += 512;
550  if ((kstate & Qt::AltModifier    ) != 0) i += 2048;
551  if ((kstate & Qt::MetaModifier   ) != 0) i += 16384;
552#endif
553  return i;
554}
555
556static string
557mouse_decode (unsigned int mstate) {
558  if      (mstate & 1 ) return "left";
559  else if (mstate & 2 ) return "middle";
560  else if (mstate & 4 ) return "right";
561  else if (mstate & 8 ) return "up";
562  else if (mstate & 16) return "down";
563  return "unknown";
564}
565
566#if 0 // NOT USED
567static void setRoundedMask(QWidget *widget)
568{
569  QPixmap pixmap(widget->size());
570  QPainter painter(&pixmap);
571  painter.fillRect(pixmap.rect(), Qt::white);
572  painter.setBrush(Qt::black);
573#if (QT_VERSION >= 0x040400)
574  painter.drawRoundedRect(pixmap.rect(),8,8, Qt::AbsoluteSize);
575#else
576  painter.drawRect(pixmap.rect());
577#endif
578  widget->setMask(pixmap.createMaskFromColor(Qt::white));
579}
580#endif
581
582
583#if 0 
584// OLD INPUT METHOD PREVIEW
585void
586QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
587  if (! imwidget) {   
588    imwidget = new QLabel(this);
589    imwidget->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
590  //  imwidget->setAttribute(Qt::WA_TranslucentBackground);
591//    imwidget->setAutoFillBackground(false);
592       imwidget->setAutoFillBackground(true);
593    imwidget->setWindowOpacity(0.5);
594    imwidget->setFocusPolicy(Qt::NoFocus);
595    QPalette pal = imwidget->palette();
596//    pal.setColor(QPalette::Window, QColor(0,0,255,80));
597    pal.setColor(QPalette::Window, QColor(0,0,255,255));
598    pal.setColor(QPalette::WindowText, Qt::white);
599    imwidget->setPalette(pal);
600    QFont f = imwidget->font();
601    f.setPointSize(30);
602    imwidget->setFont(f);
603    imwidget->setMargin(5);
604  }
605
606  QString const & preedit_string = event->preeditString();
607  QString const & commit_string = event->commitString();
608
609  if (preedit_string.isEmpty()) {
610    imwidget->hide();
611  } else {
612    if (DEBUG_QT)
613      cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
614    imwidget->setText(preedit_string);
615    imwidget->adjustSize();
616    QSize sz = size();
617    QRect g = imwidget->geometry();
618    QPoint c = mapToGlobal(cursor_pos);
619    c += QPoint(5,5);
620    // g.moveCenter(QPoint(sz.width()/2,sz.height()/2));
621    g.moveTopLeft(c);
622    if (DEBUG_QT)
623      cout << "IM hotspot: " << cursor_pos.x() << "," << cursor_pos.y() << LF;
624    imwidget->setGeometry(g);
625    // setRoundedMask(imwidget);
626    imwidget->show();
627#ifdef QT_MAC_USE_COCOA
628    // HACK: we unexplicably loose the focus even when showing the small window,
629    // so we need to restore it manually.....
630    // The following fixes the problem (but I do not really understand why it 
631    // happens)
632    // Maybe this is a Qt/Cocoa bug.
633    this->window()->activateWindow();
634#endif    
635  }
636  
637  if (!commit_string.isEmpty()) {
638    if (DEBUG_QT)
639      cout << "IM committing :" << commit_string.toUtf8().data() << LF;
640
641    int key = 0;
642#if 1
643    for (int i = 0; i < commit_string.size(); ++i) {
644      QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
645      keyPressEvent(&ev);
646    }
647#else
648    QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
649    keyPressEvent(&ev);
650#endif
651  }
652  
653  event->accept();
654
655}  
656
657QVariant 
658QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
659  switch (query) {
660    case Qt::ImMicroFocus :
661      return QVariant(QRect(cursor_pos + QPoint(10,10),QSize(20,40)));
662    default:
663      return QVariant();
664  }
665}
666
667#else
668
669// NEW INPUT METHOD PREVIEW
670void
671QTMWidget::inputMethodEvent (QInputMethodEvent* event) {
672  
673  QString const & preedit_string = event->preeditString();
674  QString const & commit_string = event->commitString();
675  
676  if (!commit_string.isEmpty()) {
677    if (DEBUG_QT)
678      cout << "IM committing :" << commit_string.toUtf8().data() << LF;
679    
680    int key = 0;
681#if 1
682    for (int i = 0; i < commit_string.size(); ++i) {
683      QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]);
684      keyPressEvent(&ev);
685    }
686#else
687    QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string);
688    keyPressEvent(&ev);
689#endif
690  }
691  
692  if (DEBUG_QT)
693    cout << "IM preediting :" << preedit_string.toUtf8().data() << LF;
694  
695  string r = "pre-edit:";
696  if (!preedit_string.isEmpty())
697  {
698    
699    // find cursor position in the preedit string
700    QList<QInputMethodEvent::Attribute>  const & attrs = event->attributes();
701    //    int pos = preedit_string.count();
702    int pos = 0;
703    bool visible_cur = false;
704    for(int i=0; i< attrs.count(); i++) 
705      if (attrs[i].type == QInputMethodEvent::Cursor) {
706        pos = attrs[i].start;
707        visible_cur = (attrs[i].length != 0);
708      }
709    
710    // find selection in the preedit string
711    int sel_start = 0;
712    int sel_length = 0;
713    if (pos <  preedit_string.count()) {
714      for(int i=0; i< attrs.count(); i++) 
715        if ((attrs[i].type == QInputMethodEvent::TextFormat) &&
716            (attrs[i].start <= pos) && (pos < attrs[i].start + attrs[i].length)) {
717          sel_start = attrs[i].start;
718          sel_length =  attrs[i].length;
719          if (!visible_cur) pos += attrs[i].length;
720        }
721    } else {
722      sel_start = pos;
723      sel_length = 0;
724    }
725    
726    r = r * as_string(pos) * ":" 
727    * from_qstring(preedit_string);
728  }
729  simple_widget_rep *wid =  tm_widget();
730  if (wid)
731    the_gui -> process_keypress (wid, r, texmacs_time());
732  event->accept();
733}  
734
735QVariant 
736QTMWidget::inputMethodQuery ( Qt::InputMethodQuery query ) const {
737  switch (query) {
738    case Qt::ImMicroFocus :
739      return QVariant (QRect (cursor_pos, QSize (5,5)));
740    default:
741      return QWidget::inputMethodQuery (query);
742  }
743}
744
745
746#endif // input method variants
747
748
749
750void
751QTMWidget::mousePressEvent (QMouseEvent* event) {
752  simple_widget_rep *wid= tm_widget ();
753  if (!wid) return;
754  QPoint point = event->pos() + origin();
755  scale (point);
756  unsigned int mstate= mouse_state (event, false);
757  string s= "press-" * mouse_decode (mstate);
758  the_gui -> process_mouse (wid, s, point.x (), point.y (), 
759                            mstate, texmacs_time ());
760 // wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
761  if (DEBUG_QT)
762    cout << "mouse event: " << s << " at "
763         << point.x () << ", " << point.y () << LF;
764}
765
766void
767QTMWidget::mouseReleaseEvent (QMouseEvent* event) {
768  simple_widget_rep *wid = tm_widget();
769  if (!wid) return;
770  QPoint point = event->pos() + origin();
771  scale (point);
772  unsigned int mstate= mouse_state (event, true);
773  string s= "release-" * mouse_decode (mstate);
774  the_gui -> process_mouse (wid, s, point.x (), point.y (), 
775                            mstate, texmacs_time ());
776//  wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
777  if (DEBUG_QT)
778    cout << "mouse event: " << s << " at "
779         << point.x () << ", " << point.y () << LF;
780}
781
782void
783QTMWidget::mouseMoveEvent (QMouseEvent* event) {
784  simple_widget_rep *wid = tm_widget();
785  if (!wid) return;
786  QPoint point = event->pos() + origin();
787  scale (point);
788  unsigned int mstate= mouse_state (event, false);
789  string s= "move";
790  the_gui -> process_mouse (wid, s, point.x (), point.y (), 
791                            mstate, texmacs_time ());
792//  wid -> handle_mouse (s, point.x (), point.y (), mstate, texmacs_time ());
793  if (DEBUG_QT)
794    cout << "mouse event: " << s << " at "
795         << point.x () << ", " << point.y () << LF;
796}
797
798
799bool
800QTMWidget::event (QEvent* event) {
801  if (event->type() == QEvent::KeyPress) {
802    QKeyEvent *ke = static_cast<QKeyEvent*> (event);
803    keyPressEvent (ke);
804    return true;
805  } 
806  return QTMScrollView::event (event);
807}
808
809
810void
811QTMWidget::focusInEvent ( QFocusEvent * event ) {
812  if (DEBUG_QT) cout << "FOCUSIN" << LF;
813  simple_widget_rep *wid = tm_widget ();
814  if (wid) {
815    the_gui -> process_keyboard_focus (wid, true, texmacs_time());
816    //wid -> handle_keyboard_focus (true, texmacs_time ());
817  }
818  QTMScrollView::focusInEvent (event);
819}
820
821void
822QTMWidget::focusOutEvent ( QFocusEvent * event ) {
823  if (DEBUG_QT)   cout << "FOCUSOUT" << LF;
824  simple_widget_rep *wid = tm_widget ();
825  if (wid) {
826    the_gui -> process_keyboard_focus (wid, false, texmacs_time());
827//    wid -> handle_keyboard_focus (false, texmacs_time ());
828  }
829  QTMScrollView::focusOutEvent (event);
830}