/* vi:set ts=8 sts=0 sw=8:
 *
 * 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 <orzel@kde.org>
 *
 *  Please visit http://klotski.berlios.de/kvim for other vim- or
 *  kde-related coding.
 *
 *  $Id: gui_kde_x11.cc,v 1.11 2002/04/02 06:40:34 marchand Exp $
 *
 */

#include <qscrollbar.h>
#include <qdatetime.h>
#include <qcursor.h>
#include <qfontmetrics.h>
#include <qpaintdevice.h>
#include <qclipboard.h>
#include <kfontdialog.h>
#include <ktip.h>
#if (QT_VERSION>=300)
#include <qnamespace.h>
#include <qpopupmenu.h>
#include <qpainter.h>
#endif
#include <qfontmetrics.h>
#include <kmenubar.h>

#include "gui_kde_widget.h"
#include <dcopclient.h>

extern "C" {
#include "vim.h"
}

#include <stdio.h>

/*
 * global variable for KDE, we can't put them in Gui, cause there are C++ types
 */
VimMainWindow	*vmw=0;
SBPool		*sbpool=0;

/* This is the single only fixed width font in X11, which seems to be present
 * on all servers and available in all the variants we need.
 *
 * Don't try to tell me that X11 is a wonderfull technology.  If You need to
 * look for a nice GUI design look for the PalmOS instead!
 */

//#define DFLT_FONT		"-misc-fixed-medium--r-normal-*-140-*-*-*-m-*-*-*"
//#define DFLT_FONT		"-adobe-courier-medium-r-normal-*-9-*-*-*-m-*-*-*"
// This is our new Font management :), this adds a better support and some new fonts
// the old syntax is still accepted, try it if you have problems ...
#if QT_VERSION>=300
#define DFLT_FONT		"courier [bitstream]"
#else
#define DFLT_FONT		"bitstream-courier"
#endif
#define DFLT_SIZE		10

/*
 * Arguments handled by KDE internally.
 */

/* tip dialog */
static int tip=0; // 1 no dialog, 0 use it if enabled in conf, 2 force the tip
/* reverse colors */
static int reverse=0; // 0 bg : white, 1 : bg : black

/*
 * Parse the GUI related command-line arguments.  Any arguments used are
 * deleted from argv, and *argc is decremented accordingly.  This is called
 * when vim is started, whether or not the GUI has been started.
 */
void
gui_mch_prepare(int *argc, char **argv)
{
// disable XFT in KDE 2
#if QT_VERSION<300
	putenv("QT_XFT=0");	
#endif
	// mikmak: me can safely remove it , this is will speed up Vim's startup i think
    KAboutData *aboutData = new KAboutData (
	    "kvim"
	    , I18N_NOOP("KVim")
	    , "6.0"		// XXX should be #defined
	    , I18N_NOOP("The vim editor in a KDE interface")
	    , 5			// AboutData::Licence_other ??
	    , "(c) Vim Team, \":help credits\" for more infos."
	    , 0l
	    , "http://www.vim.org"
	    , "vim@vim.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@kde.org",  "http://www.freehackers.org/kvim");
    aboutData->addAuthor("Philippe Fremy",	I18N_NOOP("KDE porting"),	"pfremy@chez.com",  "http://www.freehackers.org/kvim");
    aboutData->addAuthor("Mickael Marchand",	I18N_NOOP("KDE porting"),	"marchand@kde.org",  "http://freenux.org");

    static char *hop="vim";
    KCmdLineArgs::init( 1, &hop, aboutData ); // we have to keep this (vim -g not recognized otherwise)

    // now we have to remove all KDE / QT args from the commandline and set appropriate values here, 
    // otherwise won't start saying 'unknown option'
    int found = 0;
    for (int i = 1; i < *argc ; i++)
    {
	found = 0;    
	if (strcmp(argv[i],"-tip")==0 ) {
		tip=2;
		found=1;
	}
	if (strcmp(argv[i],"-notip")==0 ) {
		tip=1;
		found=1;
	}
	if (strcmp(argv[i],"-reverse")==0 ) {
		reverse=1;
		found=1;
	}
	if (strcmp(argv[i],"-rv")==0 ) {
		reverse=1;
		found=1;
	}
	//remove from the list of argv
	if (found == 1 && --*argc>i) {
                mch_memmove(&argv[i], &argv[i + 1],
                       	(*argc - i) * sizeof(char *));
	}
    }
}

/****************************************************************************
 * Focus handlers:
 */

/*
 * Initialises time intervals for the cursor blinking
 */
void
gui_mch_set_blinking(long waittime, long on, long off)
{
    gui.w->set_blink_time( waittime, on, off );
}

/*
 * Stop the cursor blinking.  Show the cursor if it wasn't shown.
 */
void
gui_mch_stop_blink()
{
    gui.w->stop_cursor_blinking();
}

/*
 * Start the cursor blinking.  If it was already blinking, this restarts the
 * waiting time and shows the cursor.
 */
void
gui_mch_start_blink()
{
    gui.w->serverActivate();
    gui.w->start_cursor_blinking();
}

/*
 * Check if the GUI can be started.  Called before gvimrc is sourced.
 * Return OK or FAIL.
 */
int
gui_mch_init_check(void)
{
    gui.dpy = qt_xdisplay();
    return OK;
}

/*
 * Initialise the X GUI.  Create all the windows, set up all the call-backs etc.
 * Returns OK for success, FAIL when the GUI can't be started.
 */
int
gui_mch_init()
{
    (void) new KApplication();
    KApplication::kApplication()->dcopClient()->registerAs(KApplication::kApplication()->name(),false);
#include "../runtime/vim32x32.xpm"
    char ** magick = vim32x32;
    vmw = new VimMainWindow("kvim");
    QPixmap p( (const char **) magick);
    vmw->setIcon( p );
    sbpool = new SBPool;

    kapp->setMainWidget(vmw);
    kapp->setTopWidget(vmw);
    
    vmw->connect(kapp->clipboard(),SIGNAL(dataChanged()),vmw,SLOT(clipboard_update()));
    clip_lose_selection(&clip_plus);
    clip_lose_selection(&clip_star);

    gui.in_focus = FALSE; // will be updated


    if (reverse) {
        gui.def_norm_pixel = gui_mch_get_color((char_u *)"White");
        gui.def_back_pixel = gui_mch_get_color((char_u *)"Black");
        gui.w->fg_color = Qt::white;
        gui.w->bg_color = Qt::black;
    } else {
        gui.def_norm_pixel = gui_mch_get_color((char_u *)"Black");
        gui.def_back_pixel = gui_mch_get_color((char_u *)"White");
        gui.w->fg_color = Qt::black;
        gui.w->bg_color = Qt::white;
    }

    gui.w->drawing_area.setBackgroundColor ( gui.w->bg_color );


    gui.norm_pixel = gui.def_norm_pixel;
    gui.back_pixel = gui.def_back_pixel;

    gui.border_width  = 0;
    gui.border_offset = gui.border_width;

    if (tip==2) KTipDialog::showTip (vmw,QString::null,true);
    else if (tip==0) KTipDialog::showTip (vmw);

    
    return OK;
}


/*
 * Called when the foreground or background color has been changed.
 */
void
gui_mch_new_colors()
{
    QColor color(0x111111,gui.back_pixel);
#if QT_VERSION>=300
    gui.w->drawing_area.setEraseColor(color);
#else
    gui.w->drawing_area.setBackgroundColor(color);
#endif
}

/*
 * Open the GUI window which was created by a call to gui_mch_init().
 */
int
gui_mch_open()
{
    set_normal_colors();

    /* Check that none of the colors are the same as the background color */
    gui_check_colors();

    /* Get the colors for the highlight groups (gui_check_colors() might have
     * changed them).
     */
    highlight_gui_started();    /* re-init colors and fonts */

    vmw->show();
    return OK;
}


/*ARGSUSED*/
void
gui_mch_exit(int rc)
{
    kapp->quit();
}

/*
 * Get the position of the top left corner of the window.
 */
int
gui_mch_get_winpos(int *x, int *y)
{
    *x = vmw->x();
    *y = vmw->y();
    return OK;
}

/*
 * Set the position of the top left corner of the window to the given
 * coordinates.
 */
void
gui_mch_set_winpos(int x, int y)
{
    vmw->move(x,y);
}

/*
 * Set the windows size.
 */
/*ARGSUSED*/
void
gui_mch_set_shellsize(int width, int height,
		    int min_width, int min_height,
		    int base_width, int base_height)
{
    vmw->resize(width, height);
    vmw->setMinimumSize(min_width, min_height);

    gui_mch_update();
}


/*
 * The screen size is used to make sure the initial window doesn't get bigger
 * then the screen.  This subtracts some room for menubar, toolbar and window
 * decoreations.
 */
void
gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
{
    *screen_w = kapp->desktop()->width();
    *screen_h = kapp->desktop()->height();
}

#if defined(FEAT_MENU) || defined(PROTO)
void
gui_mch_enable_menu(int showit)
{
    if (showit) {
	vmw->menuBar()->show();
    } else {
	vmw->menuBar()->hide();
   }
}
#endif


#if defined(FEAT_TOOLBAR) || defined(PROTO)
void
gui_mch_show_toolbar(int showit)
{
    if (showit) {
	vmw->toolBar()->show();
    } else {
	vmw->toolBar()->hide();
   }
}
#endif

GuiFont
get_font (char_u *font_name) {
//	dbf("%s", font_name);
	if (STRCMP(font_name, "*") == 0)
	{
		QFont myFont;
		if (gui.fontname) {
			gui.fontname=NULL;
		}
		int result = KFontDialog::getFont( myFont, true );
		if ( result != KFontDialog::Accepted ) {
			return NOFONT;
		}
#if QT_VERSION>=300
		myFont.setStyleStrategy(QFont::NoAntialias);
#endif
		myFont.setFixedPitch(true);
		gui.fontname = (char_u *)strdup((const char *)myFont.rawName());
		vim_free(p_guifont);
		p_guifont=vim_strsave(gui.fontname);
		font_name = p_guifont;
		return new QFont(myFont); // we should not return directly the QFont and let gui_mch_get_font do it
		// but i fear the conversion from QFont -> QString make us lost a _lot_ of information, this is not a grave hack, so we should really keep it until QT _fully_ support XFLD Font names (which will never be the case i think ;p).
	}

	return gui_mch_get_font(font_name, FALSE);
}

/*
 * Initialise vim to use the font with the given name.
 * Return FAIL if the font could not be loaded, OK otherwise.
 */
int
gui_mch_init_font(char_u * font_name, int fontset)
{
	QString fontname;
	if (font_name==NULL) {
		fontname = (const char *)DFLT_FONT;		
		font_name = (char_u *)DFLT_FONT;
	}
	
	GuiFont font = get_font(font_name);
	if (font == NULL)
            return FAIL;
	fontname = (const char *)font_name;
	
	if (fontname.contains('*') && fontname.contains('-')) {
		font->setRawName((const char *)fontname);
	} else {
		if (fontname == (const char *)DFLT_FONT) font->setPointSize((int)DFLT_SIZE);
	}
        
	gui_mch_free_font(gui.norm_font);
	gui.norm_font = font;
	QFontMetrics f(*font);
  	gui.char_width  = f.maxWidth();
	gui.char_height = f.ascent()+f.descent()+p_linespace+1; // added 1 , looks better , otherwise some fonts may be broekn 'g' <= bottom of letters being cut
        gui.char_ascent = f.ascent()+p_linespace/2;
	//check values, just to make sure and avoid a crash
	if (gui.char_width<=0) gui.char_width=1;
	if (gui.char_height<=0) gui.char_height=1;
    	vmw->setSizeIncrement (gui.char_width,gui.char_height);

	hl_set_font_name(font_name);
	
	return OK;
}


GuiFont
gui_mch_get_font(char_u * name, int report_error)
{
//	dbf("%s", name);
		
	if (!gui.in_use || name == NULL)
        	return NOFONT;
	QFont *myFont = new QFont((const char *)name);
#if QT_VERSION>=300
	myFont->setStyleStrategy(QFont::NoAntialias);
#endif
	myFont->setFixedPitch(true);
	return (GuiFont) myFont;
}

/*
 * Set the current text font.
 * Since we create all GC on demand, we use just gui.current_font to
 * indicate the desired current font.
 */
void
gui_mch_set_font(GuiFont font)
{
	//dbf("%s", font);
	gui.current_font=font;
	
}

/*
 * If a font is not going to be used, free its structure.
 */
void
gui_mch_free_font(GuiFont font)
{
//	dbf("%s", font);
	delete font; // this is a QFont , we can delete it :)
	return;
}


/*
 * Return the Pixel value (color) for the given color name.  This routine was
 * pretty much taken from example code in the Silicon Graphics OSF/Motif
 * Programmer's Guide.
 * Return -1 for error.
 */
guicolor_T
gui_mch_get_color(char_u * name)
{
    //dbf( "%s", name );
 
    int i;
    static char *(vimnames[][2]) =
    {
    /* A number of colors that some X11 systems don't have */
	{"LightRed", "#FFA0A0"},
	{"LightGreen", "#80FF80"},
	{"LightMagenta", "#FFA0FF"},
	{"DarkCyan", "#008080"},
	{"DarkBlue", "#0000C0"},
	{"DarkRed", "#C00000"},
	{"DarkMagenta", "#C000C0"},
	{"DarkGrey", "#C0C0C0"},
	{NULL, NULL}
    };

    if (!gui.in_use)		/* can't do this when GUI not running */
	return (guicolor_T)(-1);

    QColor _color((const char *)name);


    if (_color.isValid()) {
//	printf("color allocated : pixel %x, rgb %x\n", _color.pixel(), _color.rgb() );
	return (guicolor_T) _color.pixel();
    }

    /* add a few builtin names */
    for (i = 0;; ++i) {
        if (vimnames[i][0] == NULL)
	    return (guicolor_T)(-1);
        if (STRICMP(name, vimnames[i][0]) == 0) {
	    name = (char_u *) vimnames[i][1];
	    return gui_mch_get_color(name);
	}
    }

    return (guicolor_T)(-1); // dead code, should not be reached..
}

/*
 * Set the current text foreground color.
 */
void
gui_mch_set_fg_color(guicolor_T color)
{
    //dbf("%lX", color);
 
    //if ( ((guicolor_T)-1) == color) return;
    gui.w->fg_color = QColor(0x111111, color); // 0x111111 is a fake color here, only the pixel matters..
}

/*
 * Set the current text background color.
 */
void
gui_mch_set_bg_color(guicolor_T color)
{
    //dbf("%lX", color);

    //if ( ((guicolor_T)-1) == color) return;
    gui.w->bg_color = QColor(0x111111, color); // 0x111111 is a fake color here, only the pixel matters..
}

/*
 * Use the blank mouse pointer or not.
 *
 * hide: TRUE = use blank ptr, FALSE = use parent ptr
 */
void
gui_mch_mousehide(int hide)
{
    if (hide == gui.pointer_hidden) return;
#if (QT_VERSION<300)
    gui.w->setCursor( (hide)?BlankCursor:ArrowCursor );
#else
    gui.w->setCursor( (hide)?Qt::BlankCursor:Qt::ArrowCursor );
#endif
    gui.pointer_hidden = hide;

}

void
gui_mch_draw_string(int row, int col, char_u * s, int len, int flags)
{
    gui.w->drawing_area.draw_string( TEXT_X(col), TEXT_Y(row), QString( (const char *) s), len, flags );
}

#if defined(FEAT_TITLE) || defined(PROTO)
/*
 * Return the text window-id and display.  Only required for X-based GUI's
 */
int
gui_get_x11_windis(Window * win, Display ** dis)
{
	*win = vmw->winId();
	*dis = qt_xdisplay();
	return OK;
}
#endif

void
gui_mch_beep()
{
    kapp->beep();
}

void
gui_mch_flash(int msec)
{
    gui.w->flash();
}

/*
 * Invert a rectangle from row r, column c, for nr rows and nc columns.
 */
void
gui_mch_invert_rectangle(int r, int c, int nr, int nc)
{
	dbf("%d-%d %d-%d", r, c, nr, nc);
	//TODO: used when selecting stuff in the command line
}

/*
 * Iconify the GUI window.
 */
void
gui_mch_iconify()
{
	vmw->showMinimized();
}

/*
 * Draw a cursor without focus.
 */
void
gui_mch_draw_hollow_cursor(guicolor_T color)
{
    //dbf("color %lX", color);

    QPainter p(&(gui.w->drawing_area));
    p.setPen( QColor(0x111111, color));

    p.drawRect(FILL_X(gui.col), FILL_Y(gui.row), gui.char_width - 1, gui.char_height - 1 );

    p.end();

}

/*
 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
 * color "color".
 */
void
gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
{
    //dbf("%d x %d, color %lX", w, h, color);

    QPainter p(&(gui.w->drawing_area));
    p.setPen( QColor(0x111111, color));
    p.fillRect(
                       FILL_X(gui.col),
                       FILL_Y(gui.row) + gui.char_height - h +1,
                       w, h-2, QColor( 0x111111, color));
    p.drawRect(FILL_X(gui.col),FILL_Y(gui.row) + gui.char_height - h + (int)p_linespace / 2,
		    w, h - (int)p_linespace );

}


/*
 * Catch up with any queued X11 events.  This may put keyboard input into the
 * input buffer, call resize call-backs, trigger timers etc.  If there is
 * nothing in the X11 event queue (& no timers pending), then we return
 * immediately.
 */
void
gui_mch_update()
{
    kapp->processEvents();
}


/*
 * GUI input routine called by gui_wait_for_chars().  Waits for a character
 * from the keyboard.
 *  wtime == -1     Wait forever.
 *  wtime == 0      This should never happen.
 *  wtime > 0       Wait wtime milliseconds for a character.
 * Returns OK if a character was found to be available within the given time,
 * or FAIL otherwise.
 */
int
gui_mch_wait_for_chars(long wtime)
{
#if 0
    // This works the best in terms of CPU consumption
    if (wtime>0) {
	return vim_is_input_buf_empty() ?FAIL:OK;
    } else
	while (vim_is_input_buf_empty() ) {
	    kapp->processOneEvent();
	}

    return OK;
#endif
    // malte@kde.org's  gift to KVim ;), thanks to him :) for this hard to find bug
    if (wtime>0) {
	gui.w->wait( wtime );
	while ( vim_is_input_buf_empty() && !gui.w->wait_done )
		kapp->processOneEvent();
	return vim_is_input_buf_empty() ? FAIL : OK;
    } else
	while (vim_is_input_buf_empty() ) {
		kapp->processOneEvent();
    }

    return OK;
}


/****************************************************************************
 * Output drawing routines.
 ****************************************************************************/


/* Flush any output to the screen */
void
gui_mch_flush()
{
    kapp->flushX();
}

/*
 * Clear a rectangular region of the screen from text pos (row1, col1) to
 * (row2, col2) inclusive.
 */
void
gui_mch_clear_block(int row1, int col1, int row2, int col2)
{
    gui.w->drawing_area.erase (FILL_X(col1), FILL_Y(row1),
		    (col2 - col1 + 1) * gui.char_width+ (col2 == Columns - 1),
		    (row2 - row1 + 1) * gui.char_height );
    
}

void
gui_mch_clear_all(void)
{
    gui.w->drawing_area.erase();
}

/*
 * Delete the given number of lines from the given row, scrolling up any
 * text further down within the scroll region.
 */
void
gui_mch_delete_lines(int row, int num_lines)
{
    if (num_lines <= 0)
	return;

    if (row + num_lines > gui.scroll_region_bot) {
	/* Scrolled out of region, just blank the lines out */
	gui_clear_block(row, gui.scroll_region_left, gui.scroll_region_bot, gui.scroll_region_right);
    } else {
	bitBlt (
	    &gui.w->drawing_area,
	    FILL_X(gui.scroll_region_left), FILL_Y(row),
	    &gui.w->drawing_area,
	    FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
	    gui.char_width * (gui.scroll_region_right -gui.scroll_region_left + 1) + 1,
	    gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
	    Qt::CopyROP,	    // raster Operation
	    true );		    // ignoreMask

        /* Update gui.cursor_row if the cursor scrolled or copied over */
        if (gui.cursor_row >= row) {
            if (gui.cursor_row < row + num_lines)
                gui.cursor_is_valid = FALSE;
            else if (gui.cursor_row <= gui.scroll_region_bot)
                gui.cursor_row -= num_lines;
        }                                                                      

	gui_clear_block(gui.scroll_region_bot - num_lines + 1, gui.scroll_region_left,
			gui.scroll_region_bot, gui.scroll_region_right);
	
    }
#if 0
    if (num_lines <= 0)
	return;

    if (row + num_lines > gui.scroll_region_bot) {
	/* Scrolled out of region, just blank the lines out */
	gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1);
    } else {
	bitBlt (
	    &gui.w->drawing_area,
	    FILL_X(0), FILL_Y(row),
	    &gui.w->drawing_area,
	    FILL_X(0), FILL_Y(row + num_lines),
	    gui.char_width * (int) Columns + 1,
	    gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
	    Qt::CopyROP,	    // raster Operation
	    true );		    // ignoreMask

        /* Update gui.cursor_row if the cursor scrolled or copied over */
        if (gui.cursor_row >= row) {
            if (gui.cursor_row < row + num_lines)
                gui.cursor_is_valid = FALSE;
            else if (gui.cursor_row <= gui.scroll_region_bot)
                gui.cursor_row -= num_lines;
        }                                                                      

	gui_clear_block(gui.scroll_region_bot - num_lines + 1, 0,
			gui.scroll_region_bot, (int) Columns - 1);
	//TODO: update to GTK's version

	
    }
#endif

}

/*
 * Insert the given number of lines before the given row, scrolling down any
 * following text within the scroll region.
 */
void
gui_mch_insert_lines(int row, int num_lines)
{
    if (num_lines <= 0)
	return;

    if (row + num_lines > gui.scroll_region_bot) {
	/* Scrolled out of region, just blank the lines out */
	gui_clear_block(row, gui.scroll_region_left, gui.scroll_region_bot, gui.scroll_region_right - 1);
    } else {
	bitBlt (
	    &gui.w->drawing_area,
	    FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
	    &gui.w->drawing_area,
	    FILL_X(gui.scroll_region_left), FILL_Y(row),
	    gui.char_width * ( gui.scroll_region_right - gui.scroll_region_left + 1 ) + 1,
	    gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
	    Qt::CopyROP,	    // raster Operation
	    true );		    // ignoreMask

        /* Update gui.cursor_row if the cursor scrolled or copied over */
        if (gui.cursor_row >= gui.row) {
            if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
                gui.cursor_row += num_lines;
            else if (gui.cursor_row <= gui.scroll_region_bot)
                gui.cursor_is_valid = FALSE;
        }

	gui_clear_block(row, gui.scroll_region_left, row + num_lines - 1, gui.scroll_region_right);
    }
#if 0
    if (num_lines <= 0)
	return;

    if (row + num_lines > gui.scroll_region_bot) {
	/* Scrolled out of region, just blank the lines out */
	gui_clear_block(row, 0, gui.scroll_region_bot, (int) Columns - 1);
    } else {
	bitBlt (
	    &gui.w->drawing_area,
	    FILL_X(0), FILL_Y(row + num_lines),
	    &gui.w->drawing_area,
	    FILL_X(0), FILL_Y(row),
	    gui.char_width * (int) Columns + 1,
	    gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
	    Qt::CopyROP,	    // raster Operation
	    true );		    // ignoreMask

        /* Update gui.cursor_row if the cursor scrolled or copied over */
        if (gui.cursor_row >= gui.row) {
            if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
                gui.cursor_row += num_lines;
            else if (gui.cursor_row <= gui.scroll_region_bot)
                gui.cursor_is_valid = FALSE;
        }

	gui_clear_block(row, 0, row + num_lines - 1, (int) Columns - 1);
    }
	//TODO: update to GTK's version
#endif
}

/*
 * X Selection stuff, for cutting and pasting text to other windows.
 */
void
clip_mch_request_selection(VimClipboard *cbd)
{
	// TODO: validate clipboard behavior, probably wrong
    QString selection = kapp->clipboard()->text();
    
    //clip_yank_selection(MCHAR,(char_u *) selection.latin1(),(long) selection.length(),&clip_star);
    clip_yank_selection(MCHAR,(char_u *) selection.latin1(),(long) selection.length(),cbd);
	
}

void
clip_mch_lose_selection(VimClipboard *cbd)
{
    //Don't need to do anything here
    gui_mch_update();
}

/*
 * Check whatever we allready own the selection.
 */
int
clip_mch_own_selection(VimClipboard *cbd)
{
    //Don't need to do anything here
    return OK;
}

/*
 * Send the current selection to the clipboard.
 */
void
clip_mch_set_selection(VimClipboard *cbd){
    char_u *data;
    long_u length;
	 
    //clip_get_selection(&clip_plus);
    //clip_get_selection(&clip_star);
    clip_get_selection(cbd);
    if(clip_convert_selection(&data,&length,cbd)<0) return;
//    if(clip_convert_selection(&data,&length,&clip_plus)<0)
//	return;

    QString selection((const char *) data);
    //We must turncate the string because it is not 
    // null terminated
    selection.truncate((uint) length);

    kapp->clipboard()->setText(selection);
}


#if defined(FEAT_MENU) || defined(PROTO)
/*
 * Make a menu item appear either active or not active (grey or not grey).
 */
void
gui_mch_menu_grey(vimmenu_T * menu, int grey)
{
    if ( !menu || !menu->parent || !menu->parent->widget ) return;
    menu->parent->widget->setItemEnabled((int)menu, !grey);
    gui_mch_update();
}

/*
 * Make menu item hidden or not hidden.
 */
void
gui_mch_menu_hidden(vimmenu_T * menu, int hidden)
{
	gui_mch_menu_grey(menu,hidden); // it's hard to remove an item in a QPopupMenu
}

/*
 * This is called after setting all the menus to grey/hidden or not.
 */
void
gui_mch_draw_menubar()
{
    // nothing to do under kde
}
#endif

/*
 * Scrollbar stuff.
 */
void
gui_mch_enable_scrollbar(scrollbar_T * sb, int flag)
{
    if (!sb->w) return;
    if (flag)
	sb->w->show();
    else
	sb->w->hide();
}


/*
 * Return the lightness of a pixel.  White is 255.
 */

int
gui_mch_get_lightness(guicolor_T pixel)
{
    QColor c(0, pixel);
    return qGray( c.rgb() );
}


/*
 * Return the RGB value of a pixel as "#RRGGBB".
 */

long_u 
gui_mch_get_rgb(guicolor_T pixel)
{
    QColor c(0x111111,pixel);
	
    return  ((c.red() & 0xff00) << 8) +  ((c.green() & 0xff00)) + (c.blue() >> 8);
}

/*
 * Get current y mouse coordinate in text window.
 * Return -1 when unknown.
 */
int
gui_mch_get_mouse_x(void)
{
    return vmw->mapFromGlobal( QCursor::pos() ).x();
}

int
gui_mch_get_mouse_y(void)
{
    return vmw->mapFromGlobal( QCursor::pos() ).y();
}

void
gui_mch_setmouse(int x, int y)
{
    QCursor::setPos( vmw->mapToGlobal( QPoint(x,y)) );
}

void
mch_set_mouse_shape (int shape)
{
}

int
gui_mch_adjust_charsize ()
{
   QFont f(*(gui.current_font));
   QFontMetrics fm (f);
   gui.char_height = fm.ascent() + fm.descent() + p_linespace+1; // see init_font for +1 explanation
   gui.char_ascent = fm.ascent() + p_linespace/2; 
   
   return OK;
}

void
gui_mch_set_foreground ()
{
}


