/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. */ /* * Porting to KDE(2) was done by * * (C) 2000 by Thomas Capricelli * * Please visit http://freehackers.org/kvim for other vim- or * kde-related coding. * * $Id$ * */ #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION>=300 #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "gui_kde_wid.h" #include extern "C" { #include "version.h" } // Pixmap for dialog #ifdef FEAT_GUI_DIALOG # include "../../pixmaps/alert.xpm" # include "../../pixmaps/error.xpm" # include "../../pixmaps/generic.xpm" # include "../../pixmaps/info.xpm" # include "../../pixmaps/quest.xpm" #endif /** * Keycodes recognized by vim. */ struct special_key {//{{{ int qtkey; char_u code0; char_u code1; } special_keys[] = { {Qt::Key_Up, 'k', 'u'}, {Qt::Key_Down, 'k', 'd'}, {Qt::Key_Left, 'k', 'l'}, {Qt::Key_Right, 'k', 'r'}, {Qt::Key_F1, 'k', '1'}, {Qt::Key_F2, 'k', '2'}, {Qt::Key_F3, 'k', '3'}, {Qt::Key_F4, 'k', '4'}, {Qt::Key_F5, 'k', '5'}, {Qt::Key_F6, 'k', '6'}, {Qt::Key_F7, 'k', '7'}, {Qt::Key_F8, 'k', '8'}, {Qt::Key_F9, 'k', '9'}, {Qt::Key_F10, 'k', ';'}, {Qt::Key_F11, 'F', '1'}, {Qt::Key_F12, 'F', '2'}, {Qt::Key_F13, 'F', '3'}, {Qt::Key_F14, 'F', '4'}, {Qt::Key_F15, 'F', '5'}, {Qt::Key_F16, 'F', '6'}, {Qt::Key_F17, 'F', '7'}, {Qt::Key_F18, 'F', '8'}, {Qt::Key_F19, 'F', '9'}, {Qt::Key_F20, 'F', 'A'}, {Qt::Key_F21, 'F', 'B'}, {Qt::Key_F22, 'F', 'C'}, {Qt::Key_F23, 'F', 'D'}, {Qt::Key_F24, 'F', 'E'}, {Qt::Key_F25, 'F', 'F'}, {Qt::Key_F26, 'F', 'G'}, {Qt::Key_F27, 'F', 'H'}, {Qt::Key_F28, 'F', 'I'}, {Qt::Key_F29, 'F', 'J'}, {Qt::Key_F30, 'F', 'K'}, {Qt::Key_F31, 'F', 'L'}, {Qt::Key_F32, 'F', 'M'}, {Qt::Key_F33, 'F', 'N'}, {Qt::Key_F34, 'F', 'O'}, {Qt::Key_F35, 'F', 'P'}, {Qt::Key_Help, '%', '1'}, // { Qt::Key_Undo, '&', '8'}, <= hmmm ? {Qt::Key_BackSpace, 'k', 'b'}, {Qt::Key_Insert, KS_EXTRA, KE_KINS }, {Qt::Key_Delete, KS_EXTRA, KE_KDEL }, {Qt::Key_Home, 'K', '1'}, {Qt::Key_End, 'K', '4'}, {Qt::Key_Prior, 'K', '3'}, {Qt::Key_Next, 'K', '5'}, {Qt::Key_Print, '%', '9'}, {Qt::Key_Plus, 'K', '6'}, {Qt::Key_Minus, 'K', '7'}, {Qt::Key_Slash, 'K', '8'}, {Qt::Key_multiply, 'K', '9'}, {Qt::Key_Enter, 'K', 'A'}, {Qt::Key_Period, 'K', 'B'}, {Qt::Key_0, 'K', 'C'}, {Qt::Key_1, 'K', 'D'}, {Qt::Key_2, 'K', 'E'}, {Qt::Key_3, 'K', 'F'}, {Qt::Key_4, 'K', 'G'}, {Qt::Key_5, 'K', 'H'}, {Qt::Key_6, 'K', 'I'}, {Qt::Key_7, 'K', 'J'}, {Qt::Key_8, 'K', 'K'}, {Qt::Key_9, 'K', 'L'}, /* End of list marker: */ {0, 0, 0} };//}}} #ifdef FEAT_CLIENTSERVER typedef int (*QX11EventFilter)(XEvent*); extern QX11EventFilter qt_set_x11_event_filter(QX11EventFilter filter); static QX11EventFilter oldFilter = 0; static int kvim_x11_event_filter(XEvent* e); #endif void gui_keypress(QKeyEvent *e); /* * Return OK if the key with the termcap name "name" is supported. */ int gui_mch_haskey(char_u * name)//{{{ { for (int i = 0; special_keys[i].qtkey != 0; i++) if (name[0] == special_keys[i].code0 && name[1] == special_keys[i].code1) return OK; return FAIL; }//}}} /* * custom Frame for drawing ... */ void VimWidget::paintEvent(QPaintEvent *e)//{{{ { QRect r = e->rect(); gui_redraw(r.x(), r.y(), r.width(), r.height()); }//}}} void VimWidget::draw_string(int x, int y, QString s, int len, int flags)//{{{ { gui.current_font->setBold(flags & DRAW_BOLD); gui.current_font->setUnderline(flags & DRAW_UNDERL); gui.current_font->setItalic(flags & DRAW_ITALIC); painter->setBackgroundMode(flags & DRAW_TRANSP ? Qt::TransparentMode : Qt::OpaqueMode); painter->setFont(*(gui.current_font)); painter->drawText(x, y, s, len); }//}}} void VimWidget::mousePressEvent(QMouseEvent *event)//{{{ { int button = 0; int modifiers = 0; ButtonState state = event->state(); ButtonState buttons = event->button(); //Look at button states if (buttons & QMouseEvent::LeftButton) button |= MOUSE_LEFT; if (buttons & QMouseEvent::RightButton) button |= MOUSE_RIGHT; if (buttons & QMouseEvent::MidButton) button |= MOUSE_MIDDLE; //Look for keyboard modifiers if (state & QMouseEvent::ShiftButton) modifiers |= MOUSE_SHIFT; if (state & QMouseEvent::ControlButton) modifiers |= MOUSE_CTRL; if (state & QMouseEvent::AltButton) modifiers |= MOUSE_ALT; gui_send_mouse_event(button, event->x(), event->y(), FALSE, modifiers); #if QT_VERSION>=300 QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << kapp->dcopClient()->appId() << button << modifiers << gui.row << gui.col; kapp->dcopClient()->emitDCOPSignal( "mousePEvent(QCString, int, int, int, int)", params); #endif event->accept(); }//}}} #if defined(FEAT_SESSION) void VimMainWindow::saveGlobalProperties(KConfig *conf) { //we write a mksession file to a file written in the user's ~/.kde/share/config/ //the name of the file in saved in 'conf' //when restoring app, we source this file #if 0 //disabled for release QString filename = KGlobal::dirs()->localkdedir() + KGlobal::dirs()->kde_default("config") + kapp->randomString(10); QString cmd("mksession "); cmd+=filename; do_cmdline_cmd((char_u*)cmd.latin1()); conf->writePathEntry("sessionfile", filename); conf->sync(); #endif } void VimMainWindow::readGlobalProperties (KConfig *conf) { #if 0 QString filename = conf->readPathEntry("sessionfile"); if (filename.isNull()) return; QString cmd("source "); cmd+=filename; do_cmdline_cmd((char_u*)cmd.latin1()); #endif } #endif void VimMainWindow::wheelEvent (QWheelEvent *event)//{{{ { ButtonState state = event->state(); int button = 0; int modifiers = 0; if (event->delta() > 0) button |= MOUSE_4; else button |= MOUSE_5; if (state & ShiftButton) modifiers |= MOUSE_SHIFT; if (state & ControlButton) modifiers |= MOUSE_CTRL; if (state & AltButton) modifiers |= MOUSE_ALT; gui_send_mouse_event(button, event->x(), event->y(), FALSE, modifiers); #if QT_VERSION>=300 QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << kapp->dcopClient()->appId() << button << modifiers << gui.row << gui.col; kapp->dcopClient()->emitDCOPSignal( "mouseWhlEvent(QCString, int, int, int, int)", params); #endif event->accept(); }//}}} void VimWidget::mouseDoubleClickEvent(QMouseEvent *event)//{{{ { ButtonState state = event->state(); ButtonState buttons = event->button(); int modifiers = 0; int button = 0; //Look at button states if (buttons & LeftButton) button |= MOUSE_LEFT; if (buttons & RightButton) button |= MOUSE_RIGHT; if (buttons & MidButton) button |= MOUSE_MIDDLE; //Look for keyboard modifiers if (state & ShiftButton) modifiers |= MOUSE_SHIFT; if (state & ControlButton) modifiers |= MOUSE_CTRL; if (state & AltButton) modifiers |= MOUSE_ALT; gui_send_mouse_event(button, event->x(), event->y(), TRUE, modifiers); #if QT_VERSION>=300 QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << kapp->dcopClient()->appId() << button << modifiers << gui.row << gui.col; kapp->dcopClient()->emitDCOPSignal( "mouseDblClickEvent(QCString, int, int, int, int)", params); #endif event->accept(); }//}}} void VimWidget::mouseMoveEvent(QMouseEvent *event)//{{{ { ButtonState state = event->state(); int modifiers = 0; int button = 0; gui_mch_mousehide(FALSE); //Look at button states //warning: we use state here, this is important ! if (state & QMouseEvent::LeftButton || state & QMouseEvent::RightButton || state & QMouseEvent::MidButton) button |= MOUSE_DRAG; //Look for keyboard modifiers if (state & ShiftButton) modifiers |= MOUSE_SHIFT; if (state & ControlButton) modifiers |= MOUSE_CTRL; if (state & AltButton) modifiers |= MOUSE_ALT; if (button != MOUSE_DRAG) gui_mouse_moved(event->x(), event->y()); else gui_send_mouse_event(MOUSE_DRAG, event->x(), event->y(), FALSE, modifiers); }//}}} void VimWidget::mouseReleaseEvent(QMouseEvent *event)//{{{ { ButtonState state = event->state(); int modifiers = 0; //Look for keyboard modifiers if (state & ShiftButton) modifiers |= MOUSE_SHIFT; if (state & ControlButton) modifiers |= MOUSE_CTRL; if (state & AltButton) modifiers |= MOUSE_ALT; gui_send_mouse_event(MOUSE_RELEASE, event->x(), event->y(), FALSE, modifiers); event->accept(); }//}}} /* * The main widget (everything but toolbar/menubar) */ VimWidget::VimWidget(QWidget *parent, const char *name, WFlags f)//{{{ :QWidget(parent, name, f) , DCOPObject("KVim") #ifdef FEAT_MZSCHEME , mzscheme_timer_id(-1) #endif { //to be able to show/hide the cursor when moving the mouse setMouseTracking(true); painter = new QPainter(this); setKeyCompression(true); setFocusPolicy(QWidget::StrongFocus); setAcceptDrops(TRUE); // DND blink_state = BLINK_NONE; blink_on_time = 700; blink_off_time = 400; blink_wait_time = 250; connect( &blink_timer, SIGNAL(timeout()), SLOT(blink_cursor())); connect( &wait_timer, SIGNAL(timeout()), SLOT(wait_timeout())); setInputMethodEnabled(true); }//}}} void VimWidget::execNormal(QString command)//{{{ { QString cmd("execute 'normal "); cmd += command; cmd += "'"; QCString unistring = vmw->codec->fromUnicode(cmd); do_cmdline_cmd((char_u *)(const char*)unistring); gui_update_screen(); }//}}} void VimWidget::execInsert(QString command)//{{{ { QString cmd("execute 'normal i"); cmd += command; cmd += "'"; QCString unistring = vmw->codec->fromUnicode(cmd); do_cmdline_cmd((char_u *)(const char*)unistring); gui_update_screen(); }//}}} void VimWidget::execRaw(QString command)//{{{ { QString cmd("execute '"); cmd += command; cmd += "'"; QCString unistring = vmw->codec->fromUnicode(cmd); do_cmdline_cmd((char_u *)(const char*)unistring); gui_update_screen(); }//}}} void VimWidget::execCmd(QString command)//{{{ { QCString unistring = vmw->codec->fromUnicode(command); do_cmdline_cmd((char_u *)(const char*)unistring); gui_update_screen(); }//}}} QString VimWidget::eval(QString expr)//{{{ { #ifdef FEAT_EVAL QCString unistring = vmw->codec->fromUnicode(expr); QString val((const char *)eval_to_string( (char_u *)(const char*)unistring, NULL)); return val; #else return QString::null; #endif }//}}} void VimWidget::wait(long wtime)//{{{ { if (wait_timer.isActive()) wait_timer.stop(); wait_done = false; wait_timer.start( wtime, true); }//}}} void VimWidget::wait_timeout() //{{{ { wait_done = true; }//}}} void VimWidget::dragEnterEvent (QDragEnterEvent *e)//{{{ { #if (defined(FEAT_WINDOWS) && defined(HAVE_DROP_FILE)) || defined(PROTO) e->accept(QUriDrag::canDecode(e)); #else e->ignore(); #endif }//}}} void VimWidget::dropEvent(QDropEvent *e) // {{{ { #if (defined(FEAT_WINDOWS) && defined(HAVE_DROP_FILE)) || defined(PROTO) QStrList urls; char_u **fnames; int redo_dirs = FALSE; int i; int n; int nfiles; int url = FALSE; /* Count how many items there may be and normalize delimiters. */ if (QUriDrag::decode(e, urls)) { n = urls.count(); fnames = (char_u **)lalloc((n+1) * sizeof(char_u *), TRUE); nfiles = 0; #if QT_VERSION>=300 QPtrListIterator it(urls); for (; it.current(); ++it) { KURL u(*it); #else for (i = 0; i < urls.count(); ++i) { KURL u(urls.at(i)); #endif if (!u.isLocalFile()) url = TRUE; else { fnames[nfiles] = (char_u *)strdup((const char *)u.path()); ++nfiles; } } /* Real files (i.e. not http and not ftp) */ if (url == FALSE) { if (nfiles == 1) { if (mch_isdir(fnames[0])) { /* Handle dropping a directory on Vim. */ if (mch_chdir((char *)fnames[0]) == 0) { free(fnames[0]); fnames[0] = NULL; redo_dirs = TRUE; } } } else { /* Ignore any directories */ for (i = 0; i < nfiles; ++i) { if (mch_isdir(fnames[i])) { vim_free(fnames[i]); fnames[i] = NULL; } } } if (0) { /* Shift held down, change to first file's directory */ if (fnames[0] != NULL && vim_chdirfile(fnames[0]) == OK) redo_dirs = TRUE; } else { char_u dirname[MAXPATHL]; char_u *s; if (mch_dirname(dirname, MAXPATHL) == OK) for (i = 0; i < nfiles; ++i) if (fnames[i] != NULL) { s = shorten_fname(fnames[i], dirname); if (s != NULL && (s = vim_strsave(s)) != NULL) { vim_free(fnames[i]); fnames[i] = s; } } } } /* Handle the drop, :edit or :split to get to the file */ handle_drop(nfiles, fnames, FALSE); if (redo_dirs) shorten_fnames(TRUE); } /* Update the screen display */ update_screen(NOT_VALID); #ifdef FEAT_MENU gui_update_menus(0); #endif setcursor(); out_flush(); gui_update_cursor(FALSE, FALSE); gui_mch_flush(); #endif } // }}} void VimWidget::keyPressEvent(QKeyEvent *e) // {{{ { gui_keypress(e); } // }}} void gui_keypress(QKeyEvent *e) // {{{ { int key = (int)e->key(); int modifiers = 0, i; uchar string[256], string2[256]; uchar *s, *d; Qt::ButtonState state = e->state(); QCString unistring = vmw->codec->fromUnicode(e->text()); if (unistring.length() > 0) strncpy((char*)string, (const char*)unistring, unistring.length()); string[unistring.length()] = 0; int len = unistring.length(); // ignore certain keys if (key == Qt::Key_Shift || key == Qt::Key_Alt || key == Qt::Key_Control || key == Qt::Key_Meta || key == Qt::Key_CapsLock || key == Qt::Key_NumLock || key == Qt::Key_ScrollLock) { e->ignore(); return; } #ifdef FEAT_MBYTE if (input_conv.vc_type != CONV_NONE) { mch_memmove(string2, string, len); len = convert_input(string2, len, sizeof(string2)); s = string2; } else #endif s = string; d = string; for (i = 0; i < len; ++i) { *d++ = s[i]; if (d[-1] == CSI && d + 2 < string + sizeof(string)) { /* Turn CSI into K_CSI. */ *d++ = KS_EXTRA; *d++ = (int)KE_CSI; } } len = d - string; // change shift-tab (backtab) into S_TAB if (key == Qt::Key_BackTab && state & Qt::ShiftButton) key = Qt::Key_Tab; // Change C-@ and C-2 in NUL ? Gtk does this if ((key == Qt::Key_2 || key == Qt::Key_At) && state & Qt::ControlButton) { string[0] = NUL; len = 1; } else if (len == 0 && (key == Qt::Key_Space || key == Qt::Key_Tab)) { /* When there are modifiers, these keys get zero length; we need the * original key here to be able to add a modifier below. */ string[0] = (key & 0xff); len = 1; } /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character * that already has the 8th bit set. * Don't do this for , that should become K_S_TAB with ALT. */ if (len == 1 && (key != Qt::Key_BackSpace && key != Qt::Key_Delete) && (string[0] & 0x80) == 0 && (state & Qt::AltButton) && !(key == Qt::Key_Tab && (state & Qt::ShiftButton))) { string[0] |= 0x80; #ifdef FEAT_MBYTE if (enc_utf8) // convert to utf-8 { string[1] = string[0] & 0xbf; string[0] = ((unsigned)string[0] >> 6) + 0xc0; if (string[1] == CSI) { string[2] = KS_EXTRA; string[3] = (int)KE_CSI; len = 4; } else len = 2; } #endif } /* Check for special keys, making sure BS and DEL are recognised. */ if (len == 0 || key == Qt::Key_BackSpace || key == Qt::Key_Delete) { while (special_keys[i].qtkey != 0 && special_keys[i].qtkey != key) i++; if (special_keys[i].qtkey != 0) { string[0] = CSI; string[1] = special_keys[i].code0; string[2] = special_keys[i].code1; len = -3; } /* for (i = 0; special_keys[i].qtkey != 0 ; i++) { if (special_keys[i].qtkey == key ) { string[0] = CSI; string[1] = special_keys[i].code0; string[2] = special_keys[i].code1; len = -3; break; } }*/ } if (len == 0) { //no need to dump that, that's a QT problem, we can't do anything //dbf("Unrecognised Key : %X %s", key, e->text().latin1()); e->ignore(); return; } /* Special keys (and a few others) may have modifiers */ if (len == -3 || key == Qt::Key_Space || key == Qt::Key_Tab || key == Qt::Key_Return || key == Qt::Key_Enter || key == Qt::Key_Escape) { modifiers = 0; if (state & Qt::ShiftButton) modifiers |= MOD_MASK_SHIFT; if (state & Qt::ControlButton) modifiers |= MOD_MASK_CTRL; if (state & Qt::AltButton) modifiers |= MOD_MASK_ALT; /* * For some keys a shift modifier is translated into another key * code. Do we need to handle the case where len != 1 and * string[0] != CSI? */ if (len == -3) key = TO_SPECIAL(string[1], string[2]); else key = string[0]; key = simplify_key(key, &modifiers); if (key == CSI) key = K_CSI; if (IS_SPECIAL(key)) { string[0] = CSI; string[1] = K_SECOND(key); string[2] = K_THIRD(key); len = 3; } else { string[0] = key; len = 1; } if (modifiers != 0) { uchar string2[10]; string2[0] = CSI; string2[1] = KS_MODIFIER; string2[2] = modifiers; add_to_input_buf(string2, 3); } } /* special keys */ if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts) || (string[0] == intr_char && intr_char != Ctrl_C))) { trash_input_buf(); got_int = TRUE; } add_to_input_buf(string, len); if (p_mh) gui_mch_mousehide(TRUE); //DCOP Embedding stuff //if we are here then the user has type something in the window, thus we can easily imagine that : // 1 - text has changed (emit textChanged()) // 2 - characters were interactively inserted (emit charactersInteractivelyInserted()) // 3 - cursor position has changed ( emit cursorPositionChanged() ) // 4 - selection has changed ? dunno yet //XXX // 5 - undo changed too ? (each character typed in makes the undo changes anyway) // conclusion : this makes a lot of things to send to the vim kpart, maybe too much // for now i'll just send : keyboardEvent to the kpart with the event string as parameter, // with current current position // i'll do the same for mouseEvents #if QT_VERSION>=300 QByteArray params; QDataStream stream(params, IO_WriteOnly); stream << kapp->dcopClient()->appId() << unistring << gui.row << gui.col; kapp->dcopClient()->emitDCOPSignal( "keyboardEvent(QCString, QCString, int, int)", params); #endif e->ignore(); } // }}} #ifdef FEAT_CLIENTSERVER void VimWidget::serverActivate(WId id) //{{{ { if (serverName == NULL && serverDelayedStartName != NULL) { commWindow = id; (void)serverRegisterName(qt_xdisplay(), serverDelayedStartName); } else serverChangeRegisteredWindow( qt_xdisplay(), id); }//}}} #endif #ifdef FEAT_XIM static int preedit_buf_len = 0; static int im_preedit_cursor = 0; static int im_preedit_trailing = 0; static void im_delete_preedit(void) { char_u bskey[] = {CSI, 'k', 'b'}; char_u delkey[] = {CSI, 'k', 'D'}; if (State & NORMAL) { im_preedit_cursor = 0; return; } for (; im_preedit_cursor > 0; --im_preedit_cursor) add_to_input_buf(bskey, (int)sizeof(bskey)); for (; im_preedit_trailing > 0; --im_preedit_trailing) add_to_input_buf(delkey, (int)sizeof(delkey)); } void im_set_position(int row, int col) { vmw->w->setMicroFocusHint( TEXT_X(gui.col), TEXT_Y(gui.row), 0, 0, TRUE, &vmw->w->font()); } int im_is_preediting() { return (preedit_start_col != MAXCOL); } int im_get_feedback_attr(int col) { if (draw_feedback != NULL && col < preedit_buf_len) { if (draw_feedback[col] & XIMReverse) return HL_INVERSE; else if (draw_feedback[col] & XIMUnderline) return HL_UNDERLINE; else return hl_attr(HLF_V); } return -1; } void VimWidget::imStartEvent(QIMEvent *e) { if (State & CMDLINE) preedit_start_col = cmdline_getvcol_cursor(); else if (curwin != NULL) getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL); xic = (XIC)!NULL; e->accept(); } void VimWidget::imEndEvent(QIMEvent *e) { uchar string[256]; im_delete_preedit(); QCString unistring = vmw->codec->fromUnicode(e->text()); if (unistring.length() > 0) strncpy((char*)string, (const char*)unistring, unistring.length()); string[unistring.length()] = 0; int len = unistring.length(); add_to_input_buf_csi(string, len); im_preedit_cursor = 0; im_preedit_trailing = 0; preedit_start_col = MAXCOL; preedit_buf_len = 0; if (draw_feedback) { free(draw_feedback); draw_feedback = NULL; } xic = 0; e->accept(); } void VimWidget::imComposeEvent(QIMEvent *e) { uchar string[256]; char_u backkey[] = {CSI, 'k', 'l'}; im_delete_preedit(); if (State & NORMAL) { im_preedit_cursor = 0; return; } QCString unistring = vmw->codec->fromUnicode(e->text()); if (unistring.length() > 0) strncpy((char*)string, (const char*)unistring,unistring.length()); string[unistring.length()] = 0; int len = unistring.length(); add_to_input_buf_csi(string, len); preedit_buf_len = e->text().length(); if (draw_feedback == NULL) draw_feedback = (char *)alloc(preedit_buf_len); else draw_feedback = (char *)realloc(draw_feedback, preedit_buf_len); preedit_end_col = preedit_start_col; char_u *p = string; for (int n = 0; n < preedit_buf_len; n++) { if (n < e->cursorPos() || n >= e->cursorPos() + e->selectionLength()) draw_feedback[n] = XIMUnderline; else draw_feedback[n] = XIMReverse; preedit_end_col += (*mb_ptr2cells)(p); p += (*mb_ptr2len_check)(p); } im_preedit_cursor = e->cursorPos(); im_preedit_trailing = preedit_buf_len - im_preedit_cursor; # ifdef FEAT_RIGHTLEFT if ((State & CMDLINE) == 0 && curwin != NULL && curwin->w_p_rl) backkey[2] = 'r'; # endif for (int n = 0; n < im_preedit_trailing; n++) add_to_input_buf(backkey, (int)sizeof(backkey)); e->accept(); } #endif void VimMainWindow::lock() { locked = true; } void VimMainWindow::unlock() { locked = false; } bool VimMainWindow::isLocked() { return locked; } // ->resize VimWidget if not locked // void VimMainWindow::resizeEvent(QResizeEvent *e) //{{{ { if (vmw->isLocked()) return; //remove toolbar and menubar height int height = e->size().height(); int width = e->size().width(); if (vmw->menuBar()->isVisible() && vmw->menuBar()->isEnabled() #if QT_VERSION>=300 && !vmw->menuBar()->isTopLevelMenu() #endif ) height -= vmw->menuBar()->height(); #ifdef FEAT_TOOLBAR if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled() && (vmw->toolBar()->barPos() == KToolBar::Top || vmw->toolBar()->barPos() == KToolBar::Bottom)) height -= vmw->toolBar()->height(); if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled() && (vmw->toolBar()->barPos() == KToolBar::Left || vmw->toolBar()->barPos() == KToolBar::Right)) width -= vmw->toolBar()->width(); #endif height = ((int)(height/gui.char_height))*gui.char_height; if (!vmw->isLocked()) gui_resize_shell(width, height); }//}}} void VimWidget::focusInEvent(QFocusEvent *fe) // {{{ { gui_focus_change(true); if (blink_state == BLINK_NONE) gui_mch_start_blink(); } // }}} void VimWidget::focusOutEvent(QFocusEvent *fe)//{{{ { gui_focus_change(false); if (blink_state != BLINK_NONE) gui_mch_stop_blink(); }//}}} void VimWidget::set_blink_time(long wait, long on, long off)//{{{ { blink_wait_time = wait; blink_on_time = on; blink_off_time = off; }//}}} void VimWidget::start_cursor_blinking()//{{{ { if (blink_timer.isActive()) blink_timer.stop(); /* Only switch blinking on if none of the times is zero */ if (blink_wait_time && blink_on_time && blink_off_time && gui.in_focus) { blink_state = BLINK_ON; gui_update_cursor(TRUE, FALSE); // The first blink appears after wait_time blink_timer.start( blink_wait_time, true); } }//}}} void VimWidget::blink_cursor()//{{{ { if (blink_state == BLINK_ON) { // set cursor off gui_undraw_cursor(); blink_state = BLINK_OFF; blink_timer.start( blink_off_time, true); } else { // set cursor on gui_update_cursor(TRUE, FALSE); blink_state = BLINK_ON; blink_timer.start( blink_on_time, true); } }//}}} void VimWidget::stop_cursor_blinking()//{{{ { if (blink_timer.isActive()) blink_timer.stop(); if (blink_state == BLINK_OFF) gui_update_cursor(TRUE, FALSE); blink_state = BLINK_NONE; }//}}} #ifdef FEAT_MZSCHEME void VimWidget::timerEvent(QTimerEvent * evnt)//{{{ { if (evnt->timerId() == mzscheme_timer_id) timer_proc(); }//}}} void VimWidget::enable_mzscheme_threads()//{{{ { mzscheme_timer_id = startTimer(p_mzq); }//}}} void VimWidget::disable_mzscheme_threads()//{{{ { killTimer(mzscheme_timer_id); }//}}} #endif void VimWidget::flash()//{{{ { QPainter p(this); p.setRasterOp(Qt::XorROP); p.fillRect(geometry(), QColor(0xFF, 0xFF, 0xFF)); p.flush(); //FIXME: Make this a little smarter. Maybe add a timer or something usleep(19000); p.fillRect(geometry(), QColor(0xFF, 0xFF, 0xFF)); p.flush(); p.end(); }//}}} /* * The main Window */ VimMainWindow::VimMainWindow(const char *name , WFlags f)//{{{ :KMainWindow(0L, name, f) { #ifdef FEAT_CLIENTSERVER oldFilter = qt_set_x11_event_filter(kvim_x11_event_filter); #endif if (echo_wid_arg == 1) { fprintf(stderr, "WID: %ld\n", (long)winId()); fflush(stderr); } w = new VimWidget(this, "main vim widget"); gui.w = w; setFocusProxy(w); w->setFocus(); have_tearoff = 0; finddlg = new KEdFind(this, 0, false); repldlg = new KEdReplace(this, 0, false); QObject::connect(finddlg, SIGNAL(search()), this, SLOT(slotSearch())); QObject::connect(repldlg, SIGNAL(find()), this, SLOT(slotFind())); QObject::connect(repldlg, SIGNAL(replace()), this, SLOT(slotReplace())); QObject::connect(repldlg, SIGNAL(replaceAll()), this, SLOT(slotReplaceAll())); #ifdef FEAT_TOOLBAR connect(toolBar(), SIGNAL(clicked(int)), this, SLOT(menu_activated(int))); #endif #ifdef FEAT_CLIENTSERVER w->serverActivate(winId()); if (serverName != NULL) kapp->dcopClient()->registerAs(QCString((const char*)serverName), false); else if (serverDelayedStartName != NULL) kapp->dcopClient()->registerAs( QCString((const char*)serverDelayedStartName), false); else if (argServerName != NULL) kapp->dcopClient()->registerAs(argServerName->utf8(), false); #else if (argServerName != NULL) kapp->dcopClient()->registerAs(argServerName->utf8(), false); #endif QXEmbed::initialize(); }//{{{ bool VimMainWindow::queryClose()//{{{ { gui_shell_closed(); return true; }//}}} bool VimMainWindow::queryExit()//{{{ { return true; }//}}} void VimMainWindow::menu_activated(int dx)//{{{ { #ifdef FEAT_MENU if (!dx) // tearoff return; gui_mch_set_foreground(); gui_menu_cb((VimMenu *)dx); #endif }//}}} void VimMainWindow::clipboard_selection_update()//{{{ { if (kapp->clipboard()->ownsSelection()) clip_own_selection(&clip_star); else clip_lose_selection(&clip_star); }//}}} void VimMainWindow::clipboard_data_update()//{{{ { #if QT_VERSION>=300 if (kapp->clipboard()->ownsClipboard()) clip_own_selection(&clip_plus); else clip_lose_selection(&clip_plus); #else if (kapp->clipboard()->ownsSelection()) clip_own_selection(&clip_star); else clip_lose_selection(&clip_star); #endif }//}}} void VimMainWindow::slotSearch()//{{{ { QString find_text; bool direction_down = TRUE; bool casesensitive = TRUE; int flags = FRD_FINDNEXT; find_text = finddlg->getText(); direction_down = !(finddlg->get_direction()); casesensitive = finddlg->case_sensitive(); // if (casesensitive) find_text = "\\C" + find_text; // else find_text = "\\c" + find_text; if (casesensitive) flags |= FRD_MATCH_CASE; QCString unistring = vmw->codec->fromUnicode(find_text); gui_do_findrepl(flags, (char_u *)(const char *)unistring, NULL, (int)direction_down); }//}}} void VimMainWindow::slotFind()//{{{ { QString find_text; bool direction_down = TRUE; bool casesensitive = TRUE; int flags = FRD_R_FINDNEXT; find_text = repldlg->getText(); direction_down = !(repldlg->get_direction()); casesensitive = repldlg->case_sensitive(); // if (casesensitive) find_text = "\\C" + find_text; // else find_text = "\\c" + find_text; if (casesensitive) flags |= FRD_MATCH_CASE; QCString unistring = vmw->codec->fromUnicode(find_text); gui_do_findrepl(flags, (char_u *)(const char *)unistring, NULL, (int)direction_down); }//}}} void VimMainWindow::slotReplace()//{{{ { QString find_text; QString repl_text; bool direction_down = TRUE; bool casesensitive = TRUE; int flags = FRD_REPLACE; find_text = repldlg->getText(); repl_text = repldlg->getReplaceText(); direction_down = !(repldlg->get_direction()); //if (casesensitive) find_text = "\\C" + find_text; //else find_text = "\\c" + find_text; if (casesensitive) flags |= FRD_MATCH_CASE; QCString unistring = vmw->codec->fromUnicode(find_text); QCString unistring2 = vmw->codec->fromUnicode(repl_text); gui_do_findrepl(flags, (char_u *)(const char *)unistring, (char_u *)(const char*)unistring2, (int)direction_down); }//}}} void VimMainWindow::slotReplaceAll()//{{{ { QString find_text; QString repl_text; bool direction_down = TRUE; bool casesensitive = TRUE; int flags = FRD_REPLACEALL; find_text = repldlg->getText(); repl_text = repldlg->getReplaceText(); direction_down = !(repldlg->get_direction()); casesensitive = repldlg->case_sensitive(); // if (casesensitive) find_text = "\\C" + find_text; // else find_text = "\\c" + find_text; if (casesensitive) flags |= FRD_MATCH_CASE; QCString unistring = vmw->codec->fromUnicode(find_text); QCString unistring2 = vmw->codec->fromUnicode(repl_text); gui_do_findrepl(flags, (char_u *)(const char *)unistring, (char_u *)(const char*)unistring2, (int)direction_down); }//}}} void VimMainWindow::showAboutKDE() { KAboutKDE *kde = new KAboutKDE(this); kde->show(); } void VimMainWindow::showAboutApplication()//{{{ { KAboutData *aboutData = new KAboutData( "kvim" , I18N_NOOP("KVim") , VIM_VERSION_SHORT , I18N_NOOP("Vim in a KDE interface") , 0 , "(c) Vim Team, \":help credits\" for more infos.\nType \":help iccf\" to see how you can help the children in Uganda" , 0l , "http://freehackers.org/kvim" , "kvim-dev@freenux.org" ); aboutData->addAuthor("Bram Moolenaar", I18N_NOOP("Main vim author"), "Bram@vim.org", "http://www.vim.org/"); aboutData->addAuthor("Thomas Capricelli", I18N_NOOP("KDE porting"), "orzel@freehackers.org", "http://orzel.freehackers.org"); aboutData->addAuthor("Philippe Fremy", I18N_NOOP("KDE porting"), "pfremy@chez.com", "http://www.freehackers.org/kvim"); aboutData->addAuthor("Mark Westcott", I18N_NOOP("Qtopia porting, maintainer of the Qtopia part"), "mark@houseoffish.org", "http://houseoffish.org"); aboutData->addAuthor("Mickael Marchand", I18N_NOOP("KDE porting, maintainer"), "marchand@kde.org", "http://freenux.org"); aboutData->addAuthor("Many other people", I18N_NOOP("type :help credits for more infos") ); aboutData->addCredit("Vince Negri", I18N_NOOP("Antialiasing support, Color fixes"), "vnegri@asl-electronics.co.uk"); aboutData->addCredit("Malte Starostik", I18N_NOOP("Patch for performance improvement"), "malte@kde.org"); aboutData->addCredit("Mark Stosberg", I18N_NOOP("Provided a FreeBSD box to debug KVim on BSD"), "mark@summersault.com" ); aboutData->addCredit("Henrik Skott", I18N_NOOP("Font patch when KDE not configured"), "henrik.skott@hem.utfors.se" ); aboutData->addCredit("Kailash Sethuraman", I18N_NOOP("NetBSD configure/compilation fixes") ); aboutData->setLicenseText( "KVim as an extension of Vim follows Vim license.\n\ You can read it with \":help license\"\n\ Or read the file $VIMRUNTIME/doc/uganda.txt."); KAboutApplication *about = new KAboutApplication(aboutData); about->show(); }//}}} void VimMainWindow::showTipOfTheDay() { #if QT_VERSION>=300 KTipDialog::showTip(vmw, QString::null, true); #endif } void VimMainWindow::buffersToolbar() { } void VimMainWindow::showBugReport() { KBugReport *bug= new KBugReport(this, true); bug->show(); } /* * Vim Dialog * * Returns: * 0: Cancel * 1- : nb of the pressed button */ VimDialog::VimDialog(int type, /* type of dialog *///{{{ char_u * title, /* title of dialog */ char_u * message, /* message text */ char_u * buttons, /* names of buttons */ int def_but, /* default button */ char_u *textfield) /* input field */ :QDialog(vmw, "vim generic dialog", true), // true is for "modal" mapper(this, "dialog signal mapper") { /* * Create Icon */ char ** icon_data; switch (type) { case VIM_GENERIC: icon_data = generic_xpm; break; case VIM_ERROR: icon_data = error_xpm; break; case VIM_WARNING: icon_data = alert_xpm; break; case VIM_INFO: icon_data = info_xpm; break; case VIM_QUESTION: icon_data = quest_xpm; break; default: icon_data = generic_xpm; }; QLabel * icon = new QLabel(this); icon->setPixmap(QPixmap((const char **) icon_data)); icon->setFixedSize(icon->sizeHint()); QLabel * text = new QLabel(QSTR(message), this); text->setAlignment(AlignHCenter | AlignVCenter | ExpandTabs); QStringList buttonText = QStringList::split(DLG_BUTTON_SEP, QSTR(buttons)); int butNb = buttonText.count(); /* * Layout */ QVBoxLayout * vly = new QVBoxLayout(this, 5, 5); QHBoxLayout * hly1 = new QHBoxLayout(vly, 5); hly1->addWidget(icon); hly1->addWidget(text); QHBoxLayout * hly3 = new QHBoxLayout(vly , 5); if (textfield != NULL) { entry = new QLineEdit(QSTR(textfield), this); entry->setText(QSTR(textfield)); hly3->addWidget(entry); ret = textfield; } else entry = NULL; QHBoxLayout * hly2 = new QHBoxLayout(vly, 15); QString s; QPushButton * pushButton = 0L; for (int i = 0; isetAccel(s.at(s.find('&') + 1).latin1()); hly2->addWidget(pushButton); if (i == def_but - 1) { pushButton->setDefault(true); pushButton->setAutoDefault(true); setResult(i + 1); } connect(pushButton, SIGNAL(clicked()), &mapper, SLOT(map())); mapper.setMapping(pushButton, i + 1); } connect(&mapper, SIGNAL(mapped(int)), this, SLOT(done(int))); setCaption(QSTR(title)); vly->activate(); }//}}} void VimDialog::done(int r) { if (entry != NULL) { if (r) { QCString unistring = vmw->codec->fromUnicode(entry->text()); STRCPY(ret, (const char*)unistring); } else *ret = NUL; } QDialog::done(r); } /* * ScrollBar pool handling */ SBPool::SBPool(void)//{{{ :mapper(this, "SBPool signal mapper") { connect(&mapper, SIGNAL(mapped(int)), this, SLOT(sbUsed(int))); }//}}} void SBPool::create(GuiScrollbar * sb, int orient)//{{{ { switch(orient) { case SBAR_HORIZ: sb->w = new QScrollBar(QScrollBar::Horizontal, vmw); break; case SBAR_VERT: sb->w = new QScrollBar(QScrollBar::Vertical, vmw); break; default: sb->w = 0; return; } connect(sb->w, SIGNAL(valueChanged(int)), &mapper, SLOT(map())); mapper.setMapping(sb->w, (long)sb); }//}}} void SBPool::sbUsed(int who)//{{{ { GuiScrollbar *sb = (GuiScrollbar*)who; gui_drag_scrollbar(sb, sb->w->value(), FALSE); }//}}} void SBPool::destroy(GuiScrollbar *sb)//{{{ { if (!sb->w) return; delete sb->w; sb->w = 0; }//}}} #ifdef FEAT_CLIENTSERVER static int kvim_x11_event_filter(XEvent* e)//{{{ { if (e->xproperty.type == PropertyNotify && e->xproperty.atom == commProperty && e->xproperty.window == commWindow && e->xproperty.state == PropertyNewValue) serverEventProc(qt_xdisplay(), e); if (oldFilter) return oldFilter( e ); return FALSE; }//}}} #endif //add some QT 3 fonts usefull functions #if QT_VERSION<300 QString KVimUtils::toString(QFont *f) { QStringList l; l.append(f->family()); l.append(QString::number(f->pointSize())); l.append(QString::number(f->pixelSize())); l.append(QString::number((int)f->styleHint())); l.append(QString::number(f->weight())); l.append(QString::number((int)f->italic())); l.append(QString::number((int)f->underline())); l.append(QString::number((int)f->strikeOut())); l.append(QString::number((int)f->fixedPitch())); l.append(QString::number((int)f->rawMode())); return l.join(","); } bool KVimUtils::fromString(QFont *f, QString descrip) { QStringList l(QStringList::split(',', descrip)); int count = l.count(); if (count != 10 && count != 9) return FALSE; f->setFamily(l[0]); f->setPointSize(l[1].toInt()); if (count == 9) { f->setStyleHint((QFont::StyleHint) l[2].toInt()); f->setWeight(l[3].toInt()); f->setItalic(l[4].toInt()); f->setUnderline(l[5].toInt()); f->setStrikeOut(l[6].toInt()); f->setFixedPitch(l[7].toInt()); f->setRawMode(l[8].toInt()); } else { f->setPixelSize(l[2].toInt()); f->setStyleHint((QFont::StyleHint) l[3].toInt()); f->setWeight(l[4].toInt()); f->setItalic(l[5].toInt()); f->setUnderline(l[6].toInt()); f->setStrikeOut(l[7].toInt()); f->setFixedPitch(l[8].toInt()); f->setRawMode(l[9].toInt()); } return TRUE; } #endif QString KVimUtils::convertEncodingName(QString name) { if (name.startsWith("ucs") || name.startsWith("utf-16")) return QString("utf16"); if (name == "cp950") return QString("Big5"); return QString(); }