+DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
+ "Center point in window and redisplay frame.\n\
+With prefix argument ARG, recenter putting point on screen line ARG\n\
+relative to the current window. If ARG is negative, it counts up from the\n\
+bottom of the window. (ARG should be less than the height of the window.)\n\
+\n\
+If ARG is omitted or nil, erase the entire frame and then\n\
+redraw with point in the center of the current window.\n\
+Just C-u as prefix means put point in the center of the window\n\
+and redisplay normally--don't erase and redraw the frame.")
+ (arg)
+ register Lisp_Object arg;
+{
+ struct window *w = XWINDOW (selected_window);
+ struct buffer *buf = XBUFFER (w->buffer);
+ struct buffer *obuf = current_buffer;
+ int center_p = 0;
+ int charpos, bytepos;
+
+ if (NILP (arg))
+ {
+ int i;
+
+ /* Invalidate pixel data calculated for all compositions. */
+ for (i = 0; i < n_compositions; i++)
+ composition_table[i]->font = NULL;
+
+ Fredraw_frame (w->frame);
+ SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
+ center_p = 1;
+ }
+ else if (CONSP (arg)) /* Just C-u. */
+ center_p = 1;
+ else
+ {
+ arg = Fprefix_numeric_value (arg);
+ CHECK_NUMBER (arg, 0);
+ }
+
+ set_buffer_internal (buf);
+
+ /* Handle centering on a gfaphical frame specially. Such frames can
+ have variable-height lines and centering point on the basis of
+ line counts would lead to strange effects. */
+ if (center_p && FRAME_WINDOW_P (XFRAME (w->frame)))
+ {
+ struct it it;
+ struct text_pos pt;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+ move_it_vertically (&it, - it.last_visible_y / 2);
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+ }
+ else
+ {
+ struct position pos;
+
+ if (center_p)
+ {
+ int ht = displayed_window_lines (w);
+ arg = make_number (ht / 2);
+ }
+ else if (XINT (arg) < 0)
+ {
+ int ht = displayed_window_lines (w);
+ XSETINT (arg, XINT (arg) + ht);
+ }
+
+ pos = *vmotion (PT, - XINT (arg), w);
+ charpos = pos.bufpos;
+ bytepos = pos.bytepos;
+ }
+
+ /* Set the new window start. */
+ set_marker_both (w->start, w->buffer, charpos, bytepos);
+ w->window_end_valid = Qnil;
+ w->force_start = Qt;
+ if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
+ w->start_at_line_beg = Qt;
+ else
+ w->start_at_line_beg = Qnil;
+
+ set_buffer_internal (obuf);
+ return Qnil;
+}
+
+