+
+\f
+/***********************************************************************
+ Marginal Areas
+ ***********************************************************************/
+
+DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
+ 2, 3, 0,
+ "Set width of marginal areas of window WINDOW.\n\
+If window is nil, set margins of the currently selected window.\n\
+First parameter LEFT-WIDTH specifies the number of character\n\
+cells to reserve for the left marginal area. Second parameter\n\
+RIGHT-WIDTH does the same for the right marginal area.\n\
+A nil width parameter means no margin.")
+ (window, left, right)
+ Lisp_Object window, left, right;
+{
+ struct window *w = decode_window (window);
+
+ if (!NILP (left))
+ CHECK_NUMBER_OR_FLOAT (left, 1);
+ if (!NILP (right))
+ CHECK_NUMBER_OR_FLOAT (right, 2);
+
+ /* Check widths < 0 and translate a zero width to nil.
+ Margins that are too wide have to be checked elsewhere. */
+ if ((INTEGERP (left) && XINT (left) < 0)
+ || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
+ XSETFASTINT (left, 0);
+ if (INTEGERP (left) && XFASTINT (left) == 0)
+ left = Qnil;
+
+ if ((INTEGERP (right) && XINT (right) < 0)
+ || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
+ XSETFASTINT (right, 0);
+ if (INTEGERP (right) && XFASTINT (right) == 0)
+ right = Qnil;
+
+ w->left_margin_width = left;
+ w->right_margin_width = right;
+
+ ++windows_or_buffers_changed;
+ adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+ return Qnil;
+}
+
+
+DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
+ 0, 1, 0,
+ "Get width of marginal areas of window WINDOW.\n\
+If WINDOW is omitted or nil, use the currently selected window.\n\
+Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
+If a marginal area does not exist, its width will be returned\n\
+as nil.")
+ (window)
+ Lisp_Object window;
+{
+ struct window *w = decode_window (window);
+ return Fcons (w->left_margin_width, w->right_margin_width);
+}
+
+
+\f
+/***********************************************************************
+ Smooth scrolling
+ ***********************************************************************/
+
+DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
+ "Return the amount by which WINDOW is scrolled vertically.\n\
+Use the selected window if WINDOW is nil or omitted.\n\
+Value is a multiple of the canonical character height of WINDOW.")
+ (window)
+ Lisp_Object window;
+{
+ Lisp_Object result;
+ struct frame *f;
+ struct window *w;
+
+ if (NILP (window))
+ window = selected_window;
+ else
+ CHECK_WINDOW (window, 0);
+ w = XWINDOW (window);
+ f = XFRAME (w->frame);
+
+ if (FRAME_WINDOW_P (f))
+ result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
+ else
+ result = make_number (0);
+ return result;
+}
+
+
+DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
+ 2, 2, 0,
+ "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
+WINDOW nil or omitted means use the selected window. VSCROLL is a\n\
+non-negative multiple of the canonical character height of WINDOW.")
+ (window, vscroll)
+ Lisp_Object window, vscroll;
+{
+ struct window *w;
+ struct frame *f;
+
+ if (NILP (window))
+ window = selected_window;
+ else
+ CHECK_WINDOW (window, 0);
+ CHECK_NUMBER_OR_FLOAT (vscroll, 1);
+
+ w = XWINDOW (window);
+ f = XFRAME (w->frame);
+
+ if (FRAME_WINDOW_P (f))
+ {
+ int old_dy = w->vscroll;
+
+ w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
+ w->vscroll = min (w->vscroll, 0);
+
+ /* Adjust glyph matrix of the frame if the virtual display
+ area becomes larger than before. */
+ if (w->vscroll < 0 && w->vscroll < old_dy)
+ adjust_glyphs (f);
+
+ /* Prevent redisplay shortcuts. */
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ }
+
+ return Fwindow_vscroll (window);
+}
+
+\f
+/* Call FN for all leaf windows on frame F. FN is called with the
+ first argument being a pointer to the leaf window, and with
+ additional arguments A1..A4. */
+
+void
+foreach_window (f, fn, a1, a2, a3, a4)
+ struct frame *f;
+ void (* fn) ();
+ int a1, a2, a3, a4;
+{
+ foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
+}
+
+
+/* Helper function for foreach_window. Call FN for all leaf windows
+ reachable from W. FN is called with the first argument being a
+ pointer to the leaf window, and with additional arguments A1..A4. */
+
+static void
+foreach_window_1 (w, fn, a1, a2, a3, a4)
+ struct window *w;
+ void (* fn) ();
+ int a1, a2, a3, a4;
+{
+ while (w)
+ {
+ if (!NILP (w->hchild))
+ foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
+ else if (!NILP (w->vchild))
+ foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
+ else
+ fn (w, a1, a2, a3, a4);
+
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+}
+
+
+/* Freeze or unfreeze the window start of W if unless it is a
+ mini-window or the selected window. FREEZE_P non-zero means freeze
+ the window start. */
+
+static void
+freeze_window_start (w, freeze_p)
+ struct window *w;
+ int freeze_p;
+{
+ if (w == XWINDOW (selected_window)
+ || MINI_WINDOW_P (w)
+ || (MINI_WINDOW_P (XWINDOW (selected_window))
+ && ! NILP (Vminibuf_scroll_window)
+ && w == XWINDOW (Vminibuf_scroll_window)))
+ freeze_p = 0;
+
+ w->frozen_window_start_p = freeze_p;
+}
+
+
+/* Freeze or unfreeze the window starts of all leaf windows on frame
+ F, except the selected window and a mini-window. FREEZE_P non-zero
+ means freeze the window start. */
+
+void
+freeze_window_starts (f, freeze_p)
+ struct frame *f;
+ int freeze_p;
+{
+ foreach_window (f, freeze_window_start, freeze_p);
+}
+
+\f
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+/* Return 1 if window configurations C1 and C2
+ describe the same state of affairs. This is used by Fequal. */
+
+int
+compare_window_configurations (c1, c2, ignore_positions)
+ Lisp_Object c1, c2;
+ int ignore_positions;
+{
+ register struct save_window_data *d1, *d2;
+ struct Lisp_Vector *sw1, *sw2;
+ int i;
+
+ if (!WINDOW_CONFIGURATIONP (c1))
+ wrong_type_argument (Qwindow_configuration_p, c1);
+ if (!WINDOW_CONFIGURATIONP (c2))
+ wrong_type_argument (Qwindow_configuration_p, c2);
+
+ d1 = (struct save_window_data *) XVECTOR (c1);
+ d2 = (struct save_window_data *) XVECTOR (c2);
+ sw1 = XVECTOR (d1->saved_windows);
+ sw2 = XVECTOR (d2->saved_windows);
+
+ if (! EQ (d1->frame_width, d2->frame_width))
+ return 0;
+ if (! EQ (d1->frame_height, d2->frame_height))
+ return 0;
+ if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
+ return 0;
+ if (! EQ (d1->selected_frame, d2->selected_frame))
+ return 0;
+ /* Don't compare the current_window field directly.
+ Instead see w1_is_current and w2_is_current, below. */
+ if (! EQ (d1->current_buffer, d2->current_buffer))
+ return 0;
+ if (! ignore_positions)
+ if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
+ return 0;
+ /* Don't compare the root_window field.
+ We don't require the two configurations
+ to use the same window object,
+ and the two root windows must be equivalent
+ if everything else compares equal. */
+ if (! EQ (d1->focus_frame, d2->focus_frame))
+ return 0;
+ if (! EQ (d1->min_width, d2->min_width))
+ return 0;
+ if (! EQ (d1->min_height, d2->min_height))
+ return 0;
+
+ /* Verify that the two confis have the same number of windows. */
+ if (sw1->size != sw2->size)
+ return 0;
+
+ for (i = 0; i < sw1->size; i++)
+ {
+ struct saved_window *p1, *p2;
+ int w1_is_current, w2_is_current;
+
+ p1 = SAVED_WINDOW_N (sw1, i);
+ p2 = SAVED_WINDOW_N (sw2, i);
+
+ /* Verify that the current windows in the two
+ configurations correspond to each other. */
+ w1_is_current = EQ (d1->current_window, p1->window);
+ w2_is_current = EQ (d2->current_window, p2->window);
+
+ if (w1_is_current != w2_is_current)
+ return 0;
+
+ /* Verify that the corresponding windows do match. */
+ if (! EQ (p1->buffer, p2->buffer))
+ return 0;
+ if (! EQ (p1->left, p2->left))
+ return 0;
+ if (! EQ (p1->top, p2->top))
+ return 0;
+ if (! EQ (p1->width, p2->width))
+ return 0;
+ if (! EQ (p1->height, p2->height))
+ return 0;
+ if (! EQ (p1->display_table, p2->display_table))
+ return 0;
+ if (! EQ (p1->parent, p2->parent))
+ return 0;
+ if (! EQ (p1->prev, p2->prev))
+ return 0;
+ if (! ignore_positions)
+ {
+ if (! EQ (p1->hscroll, p2->hscroll))
+ return 0;
+ if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
+ return 0;
+ if (NILP (Fequal (p1->start, p2->start)))
+ return 0;
+ if (NILP (Fequal (p1->pointm, p2->pointm)))
+ return 0;
+ if (NILP (Fequal (p1->mark, p2->mark)))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+DEFUN ("compare-window-configurations", Fcompare_window_configurations,
+ Scompare_window_configurations, 2, 2, 0,
+ "Compare two window configurations as regards the structure of windows.\n\
+This function ignores details such as the values of point and mark\n\
+and scrolling positions.")
+ (x, y)
+ Lisp_Object x, y;
+{
+ if (compare_window_configurations (x, y, 1))
+ return Qt;
+ return Qnil;
+}