+/***********************************************************************
+ Window List
+ ***********************************************************************/
+
+/* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
+ pointer. This is a callback function for foreach_window, used in
+ function window_list. */
+
+static int
+add_window_to_list (w, user_data)
+ struct window *w;
+ void *user_data;
+{
+ Lisp_Object *list = (Lisp_Object *) user_data;
+ Lisp_Object window;
+ XSETWINDOW (window, w);
+ *list = Fcons (window, *list);
+ return 1;
+}
+
+
+/* Return a list of all windows, for use by next_window. If
+ Vwindow_list is a list, return that list. Otherwise, build a new
+ list, cache it in Vwindow_list, and return that. */
+
+static Lisp_Object
+window_list ()
+{
+ if (!CONSP (Vwindow_list))
+ {
+ Lisp_Object tail;
+
+ Vwindow_list = Qnil;
+ for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object args[2];
+
+ /* We are visiting windows in canonical order, and add
+ new windows at the front of args[1], which means we
+ have to reverse this list at the end. */
+ args[1] = Qnil;
+ foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
+ args[0] = Vwindow_list;
+ args[1] = Fnreverse (args[1]);
+ Vwindow_list = Fnconc (2, args);
+ }
+ }
+
+ return Vwindow_list;
+}
+
+
+/* Value is non-zero if WINDOW satisfies the constraints given by
+ OWINDOW, MINIBUF and ALL_FRAMES.
+
+ MINIBUF t means WINDOW may be minibuffer windows.
+ `lambda' means WINDOW may not be a minibuffer window.
+ a window means a specific minibuffer window
+
+ ALL_FRAMES t means search all frames,
+ nil means search just current frame,
+ `visible' means search just visible frames,
+ 0 means search visible and iconified frames,
+ a window means search the frame that window belongs to,
+ a frame means consider windows on that frame, only. */
+
+static int
+candidate_window_p (window, owindow, minibuf, all_frames)
+ Lisp_Object window, owindow, minibuf, all_frames;
+{
+ struct window *w = XWINDOW (window);
+ struct frame *f = XFRAME (w->frame);
+ int candidate_p = 1;
+
+ if (!BUFFERP (w->buffer))
+ candidate_p = 0;
+ else if (MINI_WINDOW_P (w)
+ && (EQ (minibuf, Qlambda)
+ || (WINDOWP (minibuf) && !EQ (minibuf, window))))
+ {
+ /* If MINIBUF is `lambda' don't consider any mini-windows.
+ If it is a window, consider only that one. */
+ candidate_p = 0;
+ }
+ else if (EQ (all_frames, Qt))
+ candidate_p = 1;
+ else if (NILP (all_frames))
+ {
+ xassert (WINDOWP (owindow));
+ candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
+ }
+ else if (EQ (all_frames, Qvisible))
+ {
+ FRAME_SAMPLE_VISIBILITY (f);
+ candidate_p = FRAME_VISIBLE_P (f);
+ }
+ else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
+ {
+ FRAME_SAMPLE_VISIBILITY (f);
+ candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
+ }
+ else if (WINDOWP (all_frames))
+ candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
+ || EQ (XWINDOW (all_frames)->frame, w->frame)
+ || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
+ else if (FRAMEP (all_frames))
+ candidate_p = EQ (all_frames, w->frame);
+
+ return candidate_p;
+}
+
+
+/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
+ Fwindow_list. See there for the meaning of WINDOW, MINIBUF, and
+ ALL_FRAMES. */
+
+static void
+decode_next_window_args (window, minibuf, all_frames)
+ Lisp_Object *window, *minibuf, *all_frames;
+{
+ if (NILP (*window))
+ *window = selected_window;
+ else
+ CHECK_LIVE_WINDOW (*window, 0);
+
+ /* MINIBUF nil may or may not include minibuffers. Decide if it
+ does. */
+ if (NILP (*minibuf))
+ *minibuf = minibuf_level ? minibuf_window : Qlambda;
+ else if (!EQ (*minibuf, Qt))
+ *minibuf = Qlambda;
+
+ /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
+ => count none of them, or a specific minibuffer window (the
+ active one) to count. */
+
+ /* ALL_FRAMES nil doesn't specify which frames to include. */
+ if (NILP (*all_frames))
+ *all_frames = (!EQ (*minibuf, Qlambda)
+ ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
+ : Qnil);
+ else if (EQ (*all_frames, Qvisible))
+ ;
+ else if (XFASTINT (*all_frames) == 0)
+ ;
+ else if (FRAMEP (*all_frames))
+ ;
+ else if (!EQ (*all_frames, Qt))
+ *all_frames = Qnil;
+
+ /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
+ search just current frame, `visible' meaning search just visible
+ frames, 0 meaning search visible and iconified frames, or a
+ window, meaning search the frame that window belongs to, or a
+ frame, meaning consider windows on that frame, only. */
+}
+
+
+/* Return the next or previous window of WINDOW in canonical ordering
+ of windows. NEXT_P non-zero means return the next window. See the
+ documentation string of next-window for the meaning of MINIBUF and
+ ALL_FRAMES. */
+
+static Lisp_Object
+next_window (window, minibuf, all_frames, next_p)
+ Lisp_Object window, minibuf, all_frames;
+ int next_p;
+{
+ decode_next_window_args (&window, &minibuf, &all_frames);
+
+ /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
+ return the first window on the frame. */
+ if (FRAMEP (all_frames)
+ && !EQ (all_frames, XWINDOW (window)->frame))
+ return Fframe_first_window (all_frames);
+
+ if (next_p)
+ {
+ Lisp_Object list;
+
+ /* Find WINDOW in the list of all windows. */
+ list = Fmemq (window, window_list ());
+
+ /* Scan forward from WINDOW to the end of the window list. */
+ if (CONSP (list))
+ for (list = XCDR (list); CONSP (list); list = XCDR (list))
+ if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+ break;
+
+ /* Scan from the start of the window list up to WINDOW. */
+ if (!CONSP (list))
+ for (list = Vwindow_list;
+ CONSP (list) && !EQ (XCAR (list), window);
+ list = XCDR (list))
+ if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+ break;
+
+ if (CONSP (list))
+ window = XCAR (list);
+ }
+ else
+ {
+ Lisp_Object candidate, list;
+
+ /* Scan through the list of windows for candidates. If there are
+ candidate windows in front of WINDOW, the last one of these
+ is the one we want. If there are candidates following WINDOW
+ in the list, again the last one of these is the one we want. */
+ candidate = Qnil;
+ for (list = window_list (); CONSP (list); list = XCDR (list))
+ {
+ if (EQ (XCAR (list), window))
+ {
+ if (WINDOWP (candidate))
+ break;
+ }
+ else if (candidate_window_p (XCAR (list), window, minibuf,
+ all_frames))
+ candidate = XCAR (list);
+ }
+
+ if (WINDOWP (candidate))
+ window = candidate;
+ }
+
+ return window;
+}