patch 8.1.0307: there is no good way to get the window layout

Problem:    There is no good way to get the window layout.
Solution:   Add the winlayout() function. (Yegappan Lakshmanan)
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 2bebdd1..5e7c013 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -463,6 +463,7 @@
 static void f_winbufnr(typval_T *argvars, typval_T *rettv);
 static void f_wincol(typval_T *argvars, typval_T *rettv);
 static void f_winheight(typval_T *argvars, typval_T *rettv);
+static void f_winlayout(typval_T *argvars, typval_T *rettv);
 static void f_winline(typval_T *argvars, typval_T *rettv);
 static void f_winnr(typval_T *argvars, typval_T *rettv);
 static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
@@ -952,6 +953,7 @@
     {"winbufnr",	1, 1, f_winbufnr},
     {"wincol",		0, 0, f_wincol},
     {"winheight",	1, 1, f_winheight},
+    {"winlayout",	0, 1, f_winlayout},
     {"winline",		0, 0, f_winline},
     {"winnr",		0, 1, f_winnr},
     {"winrestcmd",	0, 0, f_winrestcmd},
@@ -13743,6 +13745,29 @@
 }
 
 /*
+ * "winlayout()" function
+ */
+    static void
+f_winlayout(typval_T *argvars, typval_T *rettv)
+{
+    tabpage_T	*tp;
+
+    if (rettv_list_alloc(rettv) != OK)
+	return;
+
+    if (argvars[0].v_type == VAR_UNKNOWN)
+	tp = curtab;
+    else
+    {
+	tp = find_tabpage((int)get_tv_number(&argvars[0]));
+	if (tp == NULL)
+	    return;
+    }
+
+    get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
+}
+
+/*
  * "winline()" function
  */
     static void
diff --git a/src/proto/window.pro b/src/proto/window.pro
index 7ed8042..c31e599 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -94,4 +94,5 @@
 win_T *win_id2wp(typval_T *argvars);
 int win_id2win(typval_T *argvars);
 void win_findbuf(typval_T *argvars, list_T *list);
+void get_framelayout(frame_T *fr, list_T *l, int topframe);
 /* vim: set ft=c : */
diff --git a/src/testdir/test_window_id.vim b/src/testdir/test_window_id.vim
index b3b506d..d10d831 100644
--- a/src/testdir/test_window_id.vim
+++ b/src/testdir/test_window_id.vim
@@ -101,3 +101,23 @@
   call assert_equal(win_getid(1), win_getid(1, 1))
   tabclose!
 endfunc
+
+func Test_winlayout()
+  let w1 = win_getid()
+  call assert_equal(['leaf', w1], winlayout())
+
+  split
+  let w2 = win_getid()
+  call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout())
+
+  split
+  let w3 = win_getid()
+  call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout())
+
+  2wincmd w
+  vsplit
+  let w4 = win_getid()
+  call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout())
+
+  only!
+endfunc
diff --git a/src/version.c b/src/version.c
index 5f03975..bad2b33 100644
--- a/src/version.c
+++ b/src/version.c
@@ -795,6 +795,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    307,
+/**/
     306,
 /**/
     305,
diff --git a/src/window.c b/src/window.c
index e1781d3..5671cf9 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7236,4 +7236,53 @@
 		list_append_number(list, wp->w_id);
 }
 
+/*
+ * Get the layout of the given tab page for winlayout().
+ */
+    void
+get_framelayout(frame_T *fr, list_T *l, int outer)
+{
+    frame_T	*child;
+    list_T	*fr_list;
+    list_T	*win_list;
+
+    if (fr == NULL)
+	return;
+
+    if (outer)
+	// outermost call from f_winlayout()
+	fr_list = l;
+    else
+    {
+	fr_list = list_alloc();
+	if (fr_list == NULL)
+	    return;
+	list_append_list(l, fr_list);
+    }
+
+    if (fr->fr_layout == FR_LEAF)
+    {
+	if (fr->fr_win != NULL)
+	{
+	    list_append_string(fr_list, (char_u *)"leaf", -1);
+	    list_append_number(fr_list, fr->fr_win->w_id);
+	}
+    }
+    else
+    {
+	list_append_string(fr_list,
+	     fr->fr_layout == FR_ROW ?  (char_u *)"row" : (char_u *)"col", -1);
+
+	win_list = list_alloc();
+	if (win_list == NULL)
+	    return;
+	list_append_list(fr_list, win_list);
+	child = fr->fr_child;
+	while (child != NULL)
+	{
+	    get_framelayout(child, win_list, FALSE);
+	    child = child->fr_next;
+	}
+    }
+}
 #endif