+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 graphical frame specially. Such frames can
+ have variable-height lines and centering point on the basis of
+ line counts would lead to strange effects. */
+ if (FRAME_WINDOW_P (XFRAME (w->frame)))
+ {
+ if (center_p)
+ {
+ struct it it;
+ struct text_pos pt;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+ move_it_vertically (&it, - window_box_height (w) / 2);
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+ }
+ else if (XINT (arg) < 0)
+ {
+ struct it it;
+ struct text_pos pt;
+ int y0, y1, h, nlines;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+ y0 = it.current_y;
+
+ /* The amount of pixels we have to move back is the window
+ height minus what's displayed in the line containing PT,
+ and the lines below. */
+ nlines = - XINT (arg) - 1;
+ move_it_by_lines (&it, nlines, 1);
+
+ y1 = it.current_y - y0;
+ h = line_bottom_y (&it) - y1;
+
+ /* If we can't move down NLINES lines because we hit
+ the end of the buffer, count in some empty lines. */
+ if (it.vpos < nlines)
+ y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
+
+ y0 = it.last_visible_y - y1 - h;
+
+ start_display (&it, w, pt);
+ move_it_vertically (&it, - y0);
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+ }
+ else
+ {
+ struct position pos;
+ pos = *vmotion (PT, - XINT (arg), w);
+ charpos = pos.bufpos;
+ bytepos = pos.bytepos;
+ }
+ }
+ else