Пример #1
0
int Gpm_GetEvent(Gpm_Event *e){
    VimEvent event;

    int n = read(gpm_fd, (void*)&event, sizeof(VimEvent));
    if(event.type == VIM_EVENT_TYPE_GPM) {
        memcpy(e, (void*)&event.event.gpm, sizeof(Gpm_Event));
        return 1;
    }else if(event.type == VIM_EVENT_TYPE_CMD) {
        do_cmdline_cmd((char_u *) event.event.cmd);
    }else if(event.type == VIM_EVENT_TYPE_RELINE) {
        char* str = event.event.cmd;
        ml_replace(curwin->w_cursor.lnum,(char_u*)str, TRUE);
        changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L);
    }else if(event.type == VIM_EVENT_TYPE_UPDATE){
        vimtouch_lock();
        update_screen(0);
        setcursor();
        out_flush();
        vimtouch_unlock();
    }else if(event.type == VIM_EVENT_TYPE_SETCOL){
        curwin->w_cursor.col = event.event.num;
    }else if(event.type == VIM_EVENT_TYPE_SCROLL){
        int do_scroll = event.event.num;
        scroll_redraw(do_scroll > 0, do_scroll>0?do_scroll:-do_scroll);
    }else if(event.type == VIM_EVENT_TYPE_RESIZE){
        out_flush();
        shell_resized_check();
        redraw_later(CLEAR);
        update_screen(CLEAR);
        out_flush();
    }
    return 0;
}
Пример #2
0
static void vimtouch_Exec_setPtyWindowSize(JNIEnv *env, jobject clazz,
    jobject fileDescriptor, jint row, jint col, jint xpixel, jint ypixel)
{
    int fd;
    struct winsize sz;

    fd = env->GetIntField(fileDescriptor, field_fileDescriptor_descriptor);

    if (env->ExceptionOccurred() != NULL) {
        return;
    }
    
    sz.ws_row = row;
    sz.ws_col = col;
    sz.ws_xpixel = xpixel;
    sz.ws_ypixel = ypixel;
    
    ioctl(fd, TIOCSWINSZ, &sz);

    vimtouch_lock();
    out_flush();
    shell_resized_check();
    redraw_later(CLEAR);
    vimtouch_unlock();
    //update_screen(CLEAR);
    //setcursor();
    //out_flush();
}
Пример #3
0
/*
 * Convert the Farsi VIM into Farsi 3342 standard.
 */
void conv_to_pstd(void)          {
  char_u      *ptr;
  int lnum, llen, i;

  /*
   * Following line contains Farsi encoded character.
   */

  do_cmdline_cmd((char_u *)"%s/\232/\202\231/g");

  for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
    ptr = ml_get((linenr_T)lnum);

    llen = (int)STRLEN(ptr);

    for ( i = 0; i < llen; i++) {
      ptr[i] = toF_TyA(ptr[i]);

    }
  }

  /* Assume the screen has been messed up: clear it and redraw. */
  redraw_later(CLEAR);
  MSG_ATTR(farsi_text_2, hl_attr(HLF_S));
}
Пример #4
0
int Gpm_GetEvent(Gpm_Event *e){
    VimEvent event;

    int n = read(gpm_fd, (void*)&event, sizeof(VimEvent));
    if(event.type == VIM_EVENT_TYPE_GPM) {
        memcpy(e, (void*)&event.event.gpm, sizeof(Gpm_Event));
        return 1;
    }else if(event.type == VIM_EVENT_TYPE_ANDROID_SEND) {
        vimtouch_send_android_event(event.event.num, (char_u *) &event.event.nums[1]);
		return 0;
    }else if(event.type == VIM_EVENT_TYPE_CMD) {
        do_cmdline_cmd((char_u *) event.event.cmd);
    }else if(event.type == VIM_EVENT_TYPE_RELINE) {
        char* str = event.event.cmd;
        ml_replace(curwin->w_cursor.lnum,(char_u*)str, TRUE);
        changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L);
    }else if(event.type == VIM_EVENT_TYPE_UPDATE){
        //vimtouch_lock();
        update_screen(0);
        setcursor();
        out_flush();
        //vimtouch_unlock();
    }else if(event.type == VIM_EVENT_TYPE_CURSOR){
        mouse_col = event.event.nums[0];
        mouse_row = event.event.nums[1];

        jump_to_mouse(MOUSE_DID_MOVE, NULL, 0);
    }else if(event.type == VIM_EVENT_TYPE_SETCOL){
        curwin->w_cursor.col = event.event.num;
    }else if(event.type == VIM_EVENT_TYPE_SCROLL){
        int do_scroll = event.event.num;
        scroll_redraw(do_scroll > 0, do_scroll>0?do_scroll:-do_scroll);
    }else if(event.type == VIM_EVENT_TYPE_RESIZE){
        out_flush();
        shell_resized_check();
        redraw_later(CLEAR);
        out_flush();
    }else if(event.type == VIM_EVENT_TYPE_SETTAB){
        int nr = event.event.nums[0];

        if (nr != tabpage_index(curtab)){
            current_tab = nr;
            if (current_tab == 255)     /* -1 in a byte gives 255 */
            current_tab = -1;
            goto_tabpage(current_tab);
            update_screen(CLEAR);
            out_flush();
        }
    }else if(event.type == VIM_EVENT_TYPE_HISTORY){
        char buf[1024];
        int i = 1;
        for(i = 1; i <= 10; i++){
            sprintf(buf, "HISTORY:%d,%s\n",i-1,get_history_entry(HIST_CMD,i));
            write(gpm_fd,buf,strlen(buf));
        }
    }
    vimtouch_sync();
    return 0;
}
Пример #5
0
/*
 * When curwin->w_leftcol has changed, adjust the cursor position.
 * Return true if the cursor was moved.
 */
bool leftcol_changed(void)
{
  // TODO(hinidu): I think it should be colnr_T or int, but p_siso is long.
  // Perhaps we can change p_siso to int.
  int64_t lastcol;
  colnr_T s, e;
  bool retval = false;

  changed_cline_bef_curs();
  lastcol = curwin->w_leftcol + curwin->w_width - curwin_col_off() - 1;
  validate_virtcol();

  /*
   * If the cursor is right or left of the screen, move it to last or first
   * character.
   */
  if (curwin->w_virtcol > (colnr_T)(lastcol - p_siso)) {
    retval = true;
    coladvance((colnr_T)(lastcol - p_siso));
  } else if (curwin->w_virtcol < curwin->w_leftcol + p_siso) {
    retval = true;
    coladvance((colnr_T)(curwin->w_leftcol + p_siso));
  }

  /*
   * If the start of the character under the cursor is not on the screen,
   * advance the cursor one more char.  If this fails (last char of the
   * line) adjust the scrolling.
   */
  getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
  if (e > (colnr_T)lastcol) {
    retval = true;
    coladvance(s - 1);
  } else if (s < curwin->w_leftcol) {
    retval = true;
    if (coladvance(e + 1) == FAIL) {    /* there isn't another character */
      curwin->w_leftcol = s;            /* adjust w_leftcol instead */
      changed_cline_bef_curs();
    }
  }

  if (retval)
    curwin->w_set_curswant = true;
  redraw_later(NOT_VALID);
  return retval;
}
Пример #6
0
/// Convert the Farsi VIM into Farsi 3342 standard.
static void conv_to_pstd(void)
{
  char_u *ptr;
  int lnum, llen, i;

  // Following line contains Farsi encoded character.
  do_cmdline_cmd("%s/\232/\202\231/ge");
  for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) {
    ptr = ml_get((linenr_T)lnum);
    llen = (int)STRLEN(ptr);
    for (i = 0; i < llen; i++) {
      ptr[i] = toF_TyA(ptr[i]);
    }
  }

  // Assume the screen has been messed up: clear it and redraw.
  redraw_later(CLEAR);
  msg_attr((const char *)farsi_text_2, hl_attr(HLF_S));
}
Пример #7
0
/// Convert the Farsi 3342 standard into Farsi VIM.
void conv_to_pvim(void)
{
  char_u *ptr;
  int lnum, llen, i;

  for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
    ptr = ml_get((linenr_T)lnum);
    llen = (int)STRLEN(ptr);
    for (i = 0; i < llen - 1; i++) {
      if (canF_Ljoin(ptr[i]) && canF_Rjoin(ptr[i + 1])) {
        ptr[i] = toF_leading(ptr[i]);
        i++;

        while (canF_Rjoin(ptr[i]) && i < llen) {
          ptr[i] = toF_Rjoin(ptr[i]);
          if (F_isterm(ptr[i]) || !F_isalpha(ptr[i])) {
            break;
          }
          i++;
        }

        if (!F_isalpha(ptr[i]) || !canF_Rjoin(ptr[i])) {
          ptr[i - 1] = toF_ending(ptr[i - 1]);
        }
      } else {
        ptr[i] = toF_TyA(ptr[i]);
      }
    }
  }

  // Following lines contains Farsi encoded character.
  do_cmdline_cmd((char_u *)"%s/\202\231/\232/g");
  do_cmdline_cmd((char_u *)"%s/\201\231/\370\334/g");

  // Assume the screen has been messed up: clear it and redraw.
  redraw_later(CLEAR);
  MSG_ATTR(farsi_text_1, hl_attr(HLF_S));
}
Пример #8
0
/*
 * Set the index of the currently selected item.  The menu will scroll when
 * necessary.  When "n" is out of range don't scroll.
 * This may be repeated when the preview window is used:
 * "repeat" == 0: open preview window normally
 * "repeat" == 1: open preview window but don't set the size
 * "repeat" == 2: don't open preview window
 * Returns TRUE when the window was resized and the location of the popup menu
 * must be recomputed.
 */
    static int
pum_set_selected(int n, int repeat)
{
    int	    resized = FALSE;
    int	    context = pum_height / 2;

    pum_selected = n;

    if (pum_selected >= 0 && pum_selected < pum_size)
    {
	if (pum_first > pum_selected - 4)
	{
	    /* scroll down; when we did a jump it's probably a PageUp then
	     * scroll a whole page */
	    if (pum_first > pum_selected - 2)
	    {
		pum_first -= pum_height - 2;
		if (pum_first < 0)
		    pum_first = 0;
		else if (pum_first > pum_selected)
		    pum_first = pum_selected;
	    }
	    else
		pum_first = pum_selected;
	}
	else if (pum_first < pum_selected - pum_height + 5)
	{
	    /* scroll up; when we did a jump it's probably a PageDown then
	     * scroll a whole page */
	    if (pum_first < pum_selected - pum_height + 1 + 2)
	    {
		pum_first += pum_height - 2;
		if (pum_first < pum_selected - pum_height + 1)
		    pum_first = pum_selected - pum_height + 1;
	    }
	    else
		pum_first = pum_selected - pum_height + 1;
	}

	/* Give a few lines of context when possible. */
	if (context > 3)
	    context = 3;
	if (pum_height > 2)
	{
	    if (pum_first > pum_selected - context)
	    {
		/* scroll down */
		pum_first = pum_selected - context;
		if (pum_first < 0)
		    pum_first = 0;
	    }
	    else if (pum_first < pum_selected + context - pum_height + 1)
	    {
		/* scroll up */
		pum_first = pum_selected + context - pum_height + 1;
	    }
	}

#if defined(FEAT_QUICKFIX)
	/*
	 * Show extra info in the preview window if there is something and
	 * 'completeopt' contains "preview".
	 * Skip this when tried twice already.
	 * Skip this also when there is not much room.
	 * NOTE: Be very careful not to sync undo!
	 */
	if (pum_array[pum_selected].pum_info != NULL
		&& Rows > 10
		&& repeat <= 1
		&& vim_strchr(p_cot, 'p') != NULL)
	{
	    win_T	*curwin_save = curwin;
	    tabpage_T   *curtab_save = curtab;
	    int		res = OK;

	    /* Open a preview window.  3 lines by default.  Prefer
	     * 'previewheight' if set and smaller. */
	    g_do_tagpreview = 3;
	    if (p_pvh > 0 && p_pvh < g_do_tagpreview)
		g_do_tagpreview = p_pvh;
	    ++RedrawingDisabled;
	    /* Prevent undo sync here, if an autocommand syncs undo weird
	     * things can happen to the undo tree. */
	    ++no_u_sync;
	    resized = prepare_tagpreview(FALSE);
	    --no_u_sync;
	    --RedrawingDisabled;
	    g_do_tagpreview = 0;

	    if (curwin->w_p_pvw)
	    {
		if (!resized
			&& curbuf->b_nwindows == 1
			&& curbuf->b_fname == NULL
			&& curbuf->b_p_bt[0] == 'n' && curbuf->b_p_bt[2] == 'f'
			&& curbuf->b_p_bh[0] == 'w')
		{
		    /* Already a "wipeout" buffer, make it empty. */
		    while (!BUFEMPTY())
			ml_delete((linenr_T)1, FALSE);
		}
		else
		{
		    /* Don't want to sync undo in the current buffer. */
		    ++no_u_sync;
		    res = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, 0, NULL);
		    --no_u_sync;
		    if (res == OK)
		    {
			/* Edit a new, empty buffer. Set options for a "wipeout"
			 * buffer. */
			set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
			set_option_value((char_u *)"bt", 0L,
					       (char_u *)"nofile", OPT_LOCAL);
			set_option_value((char_u *)"bh", 0L,
						 (char_u *)"wipe", OPT_LOCAL);
			set_option_value((char_u *)"diff", 0L,
							     NULL, OPT_LOCAL);
		    }
		}
		if (res == OK)
		{
		    char_u	*p, *e;
		    linenr_T	lnum = 0;

		    for (p = pum_array[pum_selected].pum_info; *p != NUL; )
		    {
			e = vim_strchr(p, '\n');
			if (e == NULL)
			{
			    ml_append(lnum++, p, 0, FALSE);
			    break;
			}
			else
			{
			    *e = NUL;
			    ml_append(lnum++, p, (int)(e - p + 1), FALSE);
			    *e = '\n';
			    p = e + 1;
			}
		    }

		    /* Increase the height of the preview window to show the
		     * text, but no more than 'previewheight' lines. */
		    if (repeat == 0)
		    {
			if (lnum > p_pvh)
			    lnum = p_pvh;
			if (curwin->w_height < lnum)
			{
			    win_setheight((int)lnum);
			    resized = TRUE;
			}
		    }

		    curbuf->b_changed = 0;
		    curbuf->b_p_ma = FALSE;
		    curwin->w_cursor.lnum = 1;
		    curwin->w_cursor.col = 0;

		    if ((curwin != curwin_save && win_valid(curwin_save))
			    || (curtab != curtab_save
						&& valid_tabpage(curtab_save)))
		    {
			if (curtab != curtab_save && valid_tabpage(curtab_save))
			    goto_tabpage_tp(curtab_save, FALSE, FALSE);

			/* When the first completion is done and the preview
			 * window is not resized, skip the preview window's
			 * status line redrawing. */
			if (ins_compl_active() && !resized)
			    curwin->w_redr_status = FALSE;

			/* Return cursor to where we were */
			validate_cursor();
			redraw_later(SOME_VALID);

			/* When the preview window was resized we need to
			 * update the view on the buffer.  Only go back to
			 * the window when needed, otherwise it will always be
			 * redraw. */
			if (resized)
			{
			    ++no_u_sync;
			    win_enter(curwin_save, TRUE);
			    --no_u_sync;
			    update_topline();
			}

			/* Update the screen before drawing the popup menu.
			 * Enable updating the status lines. */
			pum_do_redraw = TRUE;
			update_screen(0);
			pum_do_redraw = FALSE;

			if (!resized && win_valid(curwin_save))
			{
			    ++no_u_sync;
			    win_enter(curwin_save, TRUE);
			    --no_u_sync;
			}

			/* May need to update the screen again when there are
			 * autocommands involved. */
			pum_do_redraw = TRUE;
			update_screen(0);
			pum_do_redraw = FALSE;
		    }
		}
	    }
	}
#endif
    }

    if (!resized)
	pum_redraw();

    return resized;
}
Пример #9
0
/// Set the index of the currently selected item.  The menu will scroll when
/// necessary.  When "n" is out of range don't scroll.
/// This may be repeated when the preview window is used:
/// "repeat" == 0: open preview window normally
/// "repeat" == 1: open preview window but don't set the size
/// "repeat" == 2: don't open preview window
///
/// @param n
/// @param repeat
///
/// @returns TRUE when the window was resized and the location of the popup
/// menu must be recomputed.
static int pum_set_selected(int n, int repeat)
{
  int resized = FALSE;
  int context = pum_height / 2;

  pum_selected = n;

  if ((pum_selected >= 0) && (pum_selected < pum_size)) {
    if (pum_first > pum_selected - 4) {
      // scroll down; when we did a jump it's probably a PageUp then
      // scroll a whole page
      if (pum_first > pum_selected - 2) {
        pum_first -= pum_height - 2;
        if (pum_first < 0) {
          pum_first = 0;
        } else if (pum_first > pum_selected) {
          pum_first = pum_selected;
        }
      } else {
        pum_first = pum_selected;
      }
    } else if (pum_first < pum_selected - pum_height + 5) {
      // scroll up; when we did a jump it's probably a PageDown then
      // scroll a whole page
      if (pum_first < pum_selected - pum_height + 1 + 2) {
        pum_first += pum_height - 2;
        if (pum_first < pum_selected - pum_height + 1) {
          pum_first = pum_selected - pum_height + 1;
        }
      } else {
        pum_first = pum_selected - pum_height + 1;
      }
    }

    // Give a few lines of context when possible.
    if (context > 3) {
      context = 3;
    }

    if (pum_height > 2) {
      if (pum_first > pum_selected - context) {
        // scroll down
        pum_first = pum_selected - context;

        if (pum_first < 0) {
          pum_first = 0;
        }
      } else if (pum_first < pum_selected + context - pum_height + 1) {
        // scroll up
        pum_first = pum_selected + context - pum_height + 1;
      }
    }

    // Show extra info in the preview window if there is something and
    // 'completeopt' contains "preview".
    // Skip this when tried twice already.
    // Skip this also when there is not much room.
    // NOTE: Be very careful not to sync undo!
    if ((pum_array[pum_selected].pum_info != NULL)
        && (Rows > 10)
        && (repeat <= 1)
        && (vim_strchr(p_cot, 'p') != NULL)) {
      win_T *curwin_save = curwin;
      int res = OK;

      // Open a preview window.  3 lines by default.  Prefer
      // 'previewheight' if set and smaller.
      g_do_tagpreview = 3;

      if ((p_pvh > 0) && (p_pvh < g_do_tagpreview)) {
        g_do_tagpreview = p_pvh;
      }
      resized = prepare_tagpreview(false);
      g_do_tagpreview = 0;

      if (curwin->w_p_pvw) {
        if ((curbuf->b_fname == NULL)
            && (curbuf->b_p_bt[0] == 'n')
            && (curbuf->b_p_bt[2] == 'f')
            && (curbuf->b_p_bh[0] == 'w')) {
          // Already a "wipeout" buffer, make it empty.
          while (!bufempty()) {
            ml_delete((linenr_T)1, FALSE);
          }
        } else {
          // Don't want to sync undo in the current buffer.
          no_u_sync++;
          res = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, 0, NULL);
          no_u_sync--;

          if (res == OK) {
            // Edit a new, empty buffer. Set options for a "wipeout"
            // buffer.
            set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
            set_option_value((char_u *)"bt", 0L,
                             (char_u *)"nofile", OPT_LOCAL);
            set_option_value((char_u *)"bh", 0L,
                             (char_u *)"wipe", OPT_LOCAL);
            set_option_value((char_u *)"diff", 0L,
                             NULL, OPT_LOCAL);
          }
        }

        if (res == OK) {
          char_u *p, *e;
          linenr_T lnum = 0;

          for (p = pum_array[pum_selected].pum_info; *p != NUL;) {
            e = vim_strchr(p, '\n');
            if (e == NULL) {
              ml_append(lnum++, p, 0, FALSE);
              break;
            } else {
              *e = NUL;
              ml_append(lnum++, p, (int)(e - p + 1), FALSE);
              *e = '\n';
              p = e + 1;
            }
          }

          // Increase the height of the preview window to show the
          // text, but no more than 'previewheight' lines.
          if (repeat == 0) {
            if (lnum > p_pvh) {
              lnum = p_pvh;
            }

            if (curwin->w_height < lnum) {
              win_setheight((int)lnum);
              resized = TRUE;
            }
          }

          curbuf->b_changed = 0;
          curbuf->b_p_ma = FALSE;
          curwin->w_cursor.lnum = 1;
          curwin->w_cursor.col = 0;

          if ((curwin != curwin_save) && win_valid(curwin_save)) {
            // Return cursor to where we were
            validate_cursor();
            redraw_later(SOME_VALID);

            // When the preview window was resized we need to
            // update the view on the buffer.  Only go back to
            // the window when needed, otherwise it will always be
            // redraw.
            if (resized) {
              win_enter(curwin_save, true);
              update_topline();
            }

            // Update the screen before drawing the popup menu.
            // Enable updating the status lines.
            pum_do_redraw = TRUE;
            update_screen(0);
            pum_do_redraw = FALSE;

            if (!resized && win_valid(curwin_save)) {
              win_enter(curwin_save, true);
            }

            // May need to update the screen again when there are
            // autocommands involved.
            pum_do_redraw = TRUE;
            update_screen(0);
            pum_do_redraw = FALSE;
          }
        }
      }
    }
  }

  if (!resized) {
    pum_redraw();
  }

  return resized;
}
Пример #10
0
// Move the cursor to the specified row and column on the screen.
// Change current window if necessary. Returns an integer with the
// CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
//
// The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
// The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
//
// If flags has MOUSE_FOCUS, then the current window will not be changed, and
// if the mouse is outside the window then the text will scroll, or if the
// mouse was previously on a status line, then the status line may be dragged.
//
// If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
// cursor is moved unless the cursor was on a status line.
// This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or
// IN_SEP_LINE depending on where the cursor was clicked.
//
// If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
// the mouse is on the status line of the same window.
//
// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
// the last call.
//
// If flags has MOUSE_SETPOS, nothing is done, only the current position is
// remembered.
int jump_to_mouse(int flags,
                  bool *inclusive,  // used for inclusive operator, can be NULL
                  int which_button)  // MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
{
  static int on_status_line = 0;        // #lines below bottom of window
  static int on_sep_line = 0;           // on separator right of window
  static int prev_row = -1;
  static int prev_col = -1;
  static win_T *dragwin = NULL;         // window being dragged
  static int did_drag = false;          // drag was noticed

  win_T       *wp, *old_curwin;
  pos_T old_cursor;
  int count;
  bool first;
  int row = mouse_row;
  int col = mouse_col;
  int mouse_char;

  mouse_past_bottom = false;
  mouse_past_eol = false;

  if (flags & MOUSE_RELEASED) {
    // On button release we may change window focus if positioned on a
    // status line and no dragging happened.
    if (dragwin != NULL && !did_drag)
      flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
    dragwin = NULL;
    did_drag = false;
  }

  if ((flags & MOUSE_DID_MOVE)
      && prev_row == mouse_row
      && prev_col == mouse_col) {
retnomove:
    // before moving the cursor for a left click which is NOT in a status
    // line, stop Visual mode
    if (on_status_line)
      return IN_STATUS_LINE;
    if (on_sep_line)
      return IN_SEP_LINE;
    if (flags & MOUSE_MAY_STOP_VIS) {
      end_visual_mode();
      redraw_curbuf_later(INVERTED);            // delete the inversion
    }
    return IN_BUFFER;
  }

  prev_row = mouse_row;
  prev_col = mouse_col;

  if (flags & MOUSE_SETPOS)
    goto retnomove;                             // ugly goto...

  // Remember the character under the mouse, it might be a '-' or '+' in the
  // fold column.
  if (row >= 0 && row < Rows && col >= 0 && col <= Columns
      && ScreenLines != NULL)
    mouse_char = ScreenLines[LineOffset[row] + (unsigned)col];
  else
    mouse_char = ' ';

  old_curwin = curwin;
  old_cursor = curwin->w_cursor;

  if (!(flags & MOUSE_FOCUS)) {
    if (row < 0 || col < 0)                     // check if it makes sense
      return IN_UNKNOWN;

    // find the window where the row is in
    wp = mouse_find_win(&row, &col);
    dragwin = NULL;
    // winpos and height may change in win_enter()!
    if (row >= wp->w_height) {                  // In (or below) status line
      on_status_line = row - wp->w_height + 1;
      dragwin = wp;
    } else {
      on_status_line = 0;
    }

    if (col >= wp->w_width) {           // In separator line
      on_sep_line = col - wp->w_width + 1;
      dragwin = wp;
    } else {
      on_sep_line = 0;
    }

    // The rightmost character of the status line might be a vertical
    // separator character if there is no connecting window to the right.
    if (on_status_line && on_sep_line) {
      if (stl_connected(wp))
        on_sep_line = 0;
      else
        on_status_line = 0;
    }

    // Before jumping to another buffer, or moving the cursor for a left
    // click, stop Visual mode.
    if (VIsual_active
        && (wp->w_buffer != curwin->w_buffer
            || (!on_status_line
                && !on_sep_line
                && (
                  wp->w_p_rl ? col < wp->w_width - wp->w_p_fdc :
                                     col >= wp->w_p_fdc
                                             + (cmdwin_type == 0 && wp ==
                                                curwin ? 0 : 1)
                  )
                && (flags & MOUSE_MAY_STOP_VIS)))) {
      end_visual_mode();
      redraw_curbuf_later(INVERTED);            // delete the inversion
    }
    if (cmdwin_type != 0 && wp != curwin) {
      // A click outside the command-line window: Use modeless
      // selection if possible.  Allow dragging the status lines.
      on_sep_line = 0;
      row = 0;
      col += wp->w_wincol;
      wp = curwin;
    }
    // Only change window focus when not clicking on or dragging the
    // status line.  Do change focus when releasing the mouse button
    // (MOUSE_FOCUS was set above if we dragged first).
    if (dragwin == NULL || (flags & MOUSE_RELEASED))
      win_enter(wp, true);                      // can make wp invalid!
    // set topline, to be able to check for double click ourselves
    if (curwin != old_curwin)
      set_mouse_topline(curwin);
    if (on_status_line) {                       // In (or below) status line
      // Don't use start_arrow() if we're in the same window
      if (curwin == old_curwin)
        return IN_STATUS_LINE;
      else
        return IN_STATUS_LINE | CURSOR_MOVED;
    }
    if (on_sep_line) {                          // In (or below) status line
      // Don't use start_arrow() if we're in the same window
      if (curwin == old_curwin)
        return IN_SEP_LINE;
      else
        return IN_SEP_LINE | CURSOR_MOVED;
    }

    curwin->w_cursor.lnum = curwin->w_topline;
  } else if (on_status_line && which_button == MOUSE_LEFT)   {
    if (dragwin != NULL) {
      // Drag the status line
      count = row - dragwin->w_winrow - dragwin->w_height + 1
              - on_status_line;
      win_drag_status_line(dragwin, count);
      did_drag |= count;
    }
    return IN_STATUS_LINE;                      // Cursor didn't move
  } else if (on_sep_line && which_button == MOUSE_LEFT)   {
    if (dragwin != NULL) {
      // Drag the separator column
      count = col - dragwin->w_wincol - dragwin->w_width + 1
              - on_sep_line;
      win_drag_vsep_line(dragwin, count);
      did_drag |= count;
    }
    return IN_SEP_LINE;                         // Cursor didn't move
  } else {
    // keep_window_focus must be true
    // before moving the cursor for a left click, stop Visual mode
    if (flags & MOUSE_MAY_STOP_VIS) {
      end_visual_mode();
      redraw_curbuf_later(INVERTED);            // delete the inversion
    }


    row -= curwin->w_winrow;
    col -= curwin->w_wincol;

    // When clicking beyond the end of the window, scroll the screen.
    // Scroll by however many rows outside the window we are.
    if (row < 0) {
      count = 0;
      for (first = true; curwin->w_topline > 1; ) {
        if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
          ++count;
        else
          count += plines(curwin->w_topline - 1);
        if (!first && count > -row)
          break;
        first = false;
        (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
        if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) {
          ++curwin->w_topfill;
        } else {
          --curwin->w_topline;
          curwin->w_topfill = 0;
        }
      }
      check_topfill(curwin, false);
      curwin->w_valid &=
        ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
      redraw_later(VALID);
      row = 0;
    } else if (row >= curwin->w_height)   {
      count = 0;
      for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count; ) {
        if (curwin->w_topfill > 0) {
          ++count;
        } else {
          count += plines(curwin->w_topline);
        }

        if (!first && count > row - curwin->w_height + 1) {
          break;
        }
        first = false;

        if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline)
            && curwin->w_topline == curbuf->b_ml.ml_line_count) {
          break;
        }

        if (curwin->w_topfill > 0) {
          --curwin->w_topfill;
        } else {
          ++curwin->w_topline;
          curwin->w_topfill =
            diff_check_fill(curwin, curwin->w_topline);
        }
      }
      check_topfill(curwin, false);
      redraw_later(VALID);
      curwin->w_valid &=
        ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
      row = curwin->w_height - 1;
    } else if (row == 0)   {
      // When dragging the mouse, while the text has been scrolled up as
      // far as it goes, moving the mouse in the top line should scroll
      // the text down (done later when recomputing w_topline).
      if (mouse_dragging > 0
          && curwin->w_cursor.lnum
          == curwin->w_buffer->b_ml.ml_line_count
          && curwin->w_cursor.lnum == curwin->w_topline) {
        curwin->w_valid &= ~(VALID_TOPLINE);
      }
    }
  }

  // Check for position outside of the fold column.
  if (curwin->w_p_rl ? col < curwin->w_width - curwin->w_p_fdc :
      col >= curwin->w_p_fdc + (cmdwin_type == 0 ? 0 : 1)) {
    mouse_char = ' ';
  }

  // compute the position in the buffer line from the posn on the screen
  if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum)) {
    mouse_past_bottom = true;
  }

  if (!(flags & MOUSE_RELEASED) && which_button == MOUSE_LEFT) {
    col = mouse_adjust_click(curwin, row, col);
  }

  // Start Visual mode before coladvance(), for when 'sel' != "old"
  if ((flags & MOUSE_MAY_VIS) && !VIsual_active) {
    check_visual_highlight();
    VIsual = old_cursor;
    VIsual_active = true;
    VIsual_reselect = true;
    // if 'selectmode' contains "mouse", start Select mode
    may_start_select('o');
    setmouse();

    if (p_smd && msg_silent == 0) {
      redraw_cmdline = true;            // show visual mode later
    }
  }

  curwin->w_curswant = col;
  curwin->w_set_curswant = false;       // May still have been true
  if (coladvance(col) == FAIL) {        // Mouse click beyond end of line
    if (inclusive != NULL) {
      *inclusive = true;
    }
    mouse_past_eol = true;
  } else if (inclusive != NULL) {
    *inclusive = false;
  }

  count = IN_BUFFER;
  if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
      || curwin->w_cursor.col != old_cursor.col) {
    count |= CURSOR_MOVED;              // Cursor has moved
  }

  if (mouse_char == '+') {
    count |= MOUSE_FOLD_OPEN;
  } else if (mouse_char != ' ') {
    count |= MOUSE_FOLD_CLOSE;
  }

  return count;
}