patch 8.2.1727: a popup created with "cursorline" will ignore "firstline"

Problem:    A popup created with "cursorline" will ignore "firstline".
Solution:   When both "cursorline" and "firstline" are present put the cursor
            on "firstline". (closes #7000)  Add the "winid" argument to
            getcurpos().
diff --git a/src/evalfunc.c b/src/evalfunc.c
index de723aa..570aef8 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -646,7 +646,7 @@
     {"getcmdtype",	0, 0, 0,	  ret_string,	f_getcmdtype},
     {"getcmdwintype",	0, 0, 0,	  ret_string,	f_getcmdwintype},
     {"getcompletion",	2, 3, FEARG_1,	  ret_list_string, f_getcompletion},
-    {"getcurpos",	0, 0, 0,	  ret_list_number, f_getcurpos},
+    {"getcurpos",	0, 1, FEARG_1,	  ret_list_number, f_getcurpos},
     {"getcwd",		0, 2, FEARG_1,	  ret_string,	f_getcwd},
     {"getenv",		1, 1, FEARG_1,	  ret_string,	f_getenv},
     {"getfontname",	0, 1, 0,	  ret_string,	f_getfontname},
@@ -3259,7 +3259,8 @@
     typval_T	*rettv,
     int		getcurpos)
 {
-    pos_T	*fp;
+    pos_T	*fp = NULL;
+    win_T	*wp = curwin;
     list_T	*l;
     int		fnum = -1;
 
@@ -3267,7 +3268,16 @@
     {
 	l = rettv->vval.v_list;
 	if (getcurpos)
-	    fp = &curwin->w_cursor;
+	{
+	    if (argvars[0].v_type != VAR_UNKNOWN)
+	    {
+		wp = find_win_by_nr_or_id(&argvars[0]);
+		if (wp != NULL)
+		    fp = &wp->w_cursor;
+	    }
+	    else
+		fp = &curwin->w_cursor;
+	}
 	else
 	    fp = var2fpos(&argvars[0], TRUE, &fnum);
 	if (fnum != -1)
@@ -3287,13 +3297,14 @@
 	    colnr_T save_curswant = curwin->w_curswant;
 	    colnr_T save_virtcol = curwin->w_virtcol;
 
-	    update_curswant();
-	    list_append_number(l, curwin->w_curswant == MAXCOL ?
-		    (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
+	    if (wp == curwin)
+		update_curswant();
+	    list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
+		    ?  (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
 
 	    // Do not change "curswant", as it is unexpected that a get
 	    // function has a side effect.
-	    if (save_set_curswant)
+	    if (wp == curwin && save_set_curswant)
 	    {
 		curwin->w_set_curswant = save_set_curswant;
 		curwin->w_curswant = save_curswant;
diff --git a/src/evalwindow.c b/src/evalwindow.c
index bc3bcba..884f409 100644
--- a/src/evalwindow.c
+++ b/src/evalwindow.c
@@ -530,6 +530,22 @@
 		return;
 	}
     }
+#ifdef FEAT_PROP_POPUP
+    if (wparg != NULL)
+    {
+	tabnr = 0;
+	FOR_ALL_TABPAGES(tp)
+	{
+	    tabnr++;
+	    FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
+	    if (wp == wparg)
+		break;
+	}
+	d = get_win_info(wparg, tp == NULL ? 0 : tabnr, 0);
+	if (d != NULL)
+	    list_append_dict(rettv->vval.v_list, d);
+    }
+#endif
 }
 
 /*
diff --git a/src/popupwin.c b/src/popupwin.c
index d29986d..6080ecb 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -593,8 +593,9 @@
 	    ++wp->w_topline;
     }
 
-    // Don't use "firstline" now.
-    wp->w_firstline = 0;
+    // Don't let "firstline" cause a scroll.
+    if (wp->w_firstline > 0)
+	wp->w_firstline = wp->w_topline;
 }
 
 /*
@@ -948,6 +949,18 @@
     if (nr > 0)
 	wp->w_popup_flags |= POPF_HIDDEN;
 
+    // when "firstline" and "cursorline" are both set move the cursor to the
+    // "firstline".
+    if (wp->w_firstline > 0 && (wp->w_popup_flags & POPF_CURSORLINE))
+    {
+	if (wp->w_firstline > wp->w_buffer->b_ml.ml_line_count)
+	    wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
+	else
+	    wp->w_cursor.lnum = wp->w_firstline;
+	wp->w_topline = wp->w_cursor.lnum;
+	curwin->w_valid &= ~VALID_BOTLINE;
+    }
+
     popup_mask_refresh = TRUE;
     popup_highlight_curline(wp);
 }
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 7ff9b7a..2492c93 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -2520,7 +2520,19 @@
   call assert_equal('6', @")
   call assert_equal(-1, setpos('.', test_null_list()))
   call assert_equal(-1, setpos('.', {}))
+
+  let winid = win_getid()
+  normal G$
+  let pos = getcurpos()
+  wincmd w
+  call assert_equal(pos, getcurpos(winid))
+
+  wincmd w
   close!
+
+  call assert_equal(getcurpos(), getcurpos(0))
+  call assert_equal([0, 0, 0, 0, 0], getcurpos(-1))
+  call assert_equal([0, 0, 0, 0, 0], getcurpos(1999))
 endfunc
 
 " Test for glob()
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 954086c..333e9a2 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -516,6 +516,19 @@
   call popup_close(winid)
 endfunc
 
+func Test_popup_firstline_cursorline()
+  let winid = popup_create(['1111', '222222', '33333', '44444'], #{
+	\ maxheight: 2,
+	\ firstline: 3,
+	\ cursorline: 1,
+	\ })
+  call assert_equal(3, popup_getoptions(winid).firstline)
+  call assert_equal(3, getwininfo(winid)[0].topline)
+  call assert_equal(3, getcurpos(winid)[1])
+
+  call popup_close(winid)
+endfunc
+
 func Test_popup_noscrolloff()
   set scrolloff=5
   let winid = popup_create(['xxx']->repeat(50), #{
diff --git a/src/version.c b/src/version.c
index fd9d499..cafc31d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1727,
+/**/
     1726,
 /**/
     1725,