Commit f451eb13 authored by Jim Blandy's avatar Jim Blandy

* frame.h (struct frame): New fields `can_have_scrollbars' and

	`has_vertical_scrollbars'.
	(FRAME_CAN_HAVE_SCROLLBARS, FRAME_HAS_VERTICAL_SCROLLBARS): New
	accessors, for both the MULTI_FRAME and non-MULTI_FRAME.
	(VERTICAL_SCROLLBAR_WIDTH, WINDOW_VERTICAL_SCROLLBAR,
	WINDOW_VERTICAL_SCROLLBAR_COLUMN,
	WINDOW_VERTICAL_SCROLLBAR_HEIGHT): New macros.
	* window.h (struct window): New field `vertical_scrollbar'.
	* xterm.h (struct x_display): vertical_scrollbars,
	judge_timestamp, vertical_scrollbar_extra: New fields.
	(struct scrollbar): New struct.
	(VERTICAL_SCROLLBAR_PIXEL_WIDTH, VERTICAL_SCROLLBAR_PIXEL_HEIGHT,
	VERTICAL_SCROLLBAR_LEFT_BORDER, VERTICAL_SCROLLBAR_RIGHT_BORDER,
	VERTICAL_SCROLLBAR_TOP_BORDER, VERTICAL_SCROLLBAR_BOTTOM_BORDER,
	CHAR_TO_PIXEL_WIDTH, CHAR_TO_PIXEL_HEIGHT, PIXEL_TO_CHAR_WIDTH,
	PIXEL_TO_CHAR_HEIGHT): New accessors and macros.
	* frame.c (make_frame): Initialize the `can_have_scrollbars' and
	`has_vertical_scrollbars' fields of the frame.
	* term.c (term_init): Note that TERMCAP terminals don't support
	scrollbars.
	(mouse_position_hook): Document new args.
	(set_vertical_scrollbar_hook, condemn_scrollbars_hook,
	redeem_scrollbar_hook, judge_scrollbars_hook): New hooks.
	* termhooks.h: Declare and document them.
	(enum scrollbar_part): New type.
	(struct input_event): Describe the new form of the scrollbar_click
	event type.  Change `part' from a Lisp_Object to an enum
	scrollbar_part.  Add a new field `scrollbar'.
	* keyboard.c (kbd_buffer_get_event): Pass appropriate new
	parameters to *mouse_position_hook, and make_lispy_movement.
	* xfns.c (x_set_vertical_scrollbar): New function.
	(x_figure_window_size): Use new macros to calculate frame size.
	(Fx_create_frame): Note that X Windows frames do support scroll
	bars.  Default to "yes".
	* xterm.c: #include <X11/cursorfont.h> and "window.h".
	(x_vertical_scrollbar_cursor): New variable.
	(x_term_init): Initialize it.
	(last_mouse_bar, last_mouse_bar_frame, last_mouse_part,
	last_mouse_scroll_range_start, last_mouse_scroll_range_end): New
	variables.
	(XTmouse_position): Use them to return scrollbar movement events.
	Take new arguments, for that purpose.
	(x_window_to_scrollbar, x_scrollbar_create,
	x_scrollbar_set_handle, x_scrollbar_remove, x_scrollbar_move,
	XTset_scrollbar, XTcondemn_scrollbars, XTredeem_scrollbar,
	XTjudge_scrollbars, x_scrollbar_expose,
	x_scrollbar_background_expose, x_scrollbar_handle_click,
	x_scrollbar_handle_motion): New functions to implement scrollbars.
	(x_term_init): Set the termhooks.h hooks to point to them.
	(x_set_window_size): Use new macros to calculate frame size.  Set
	vertical_scrollbar_extra field.
	(x_make_frame_visible): Use the frame accessor
	FRAME_HAS_VERTICAL_SCROLLBARS to decide if we need to map the
	frame's subwindows as well.
	(XTread_socket): Use new size-calculation macros from xterm.h when
	processing ConfigureNotify events.
	(x_wm_set_size_hint): Use PIXEL_TO_CHAR_WIDTH and
	PIXEL_TO_CHAR_HEIGHT macros.
	* ymakefile (xdisp.o): This now depends on termhooks.h.
	(xterm.o): This now depends on window.h.

	* xterm.h (struct x_display): Delete v_scrollbar, v_thumbup,
	v_thumbdown, v_slider, h_scrollbar, h_thumbup,
	h_thumbdown, h_slider, v_scrollbar_width, h_scrollbar_height
	fields.
	* keyboard.c (Qvscrollbar_part, Qvslider_part, Qvthumbup_part,
	Qvthumbdown_part, Qhscrollbar_part, Qhslider_part, Qhthumbup_part,
	Qhthumbdown_part, Qscrollbar_click): Deleted; part of an obsolete
	interface.
	(head_table): Removed from here as well.
	(syms_of_keyboard): And here.
	* keyboard.h: And here.
	(POSN_SCROLLBAR_BUTTON): Removed.
	* xscrollbar.h: File removed - no longer necessary.
	* xfns.c: Don't #include it any more.
	(Qhorizontal_scroll_bar, Qvertical_scroll_bar): Deleted.
	(syms_of_xfns): Don't initialize or staticpro them.
	(gray_bits): Salvaged from xscrollbar.h.
	(x_window_to_scrollbar): Deleted.
	(x_set_horizontal_scrollbar): Deleted.
	(enum x_frame_parm, x_frame_parms): Remove references to
	x_set_horizontal_scrollbar.
	(x_set_foreground_color, x_set_background_color,
	x_set_border_pixel): Remove special code to support scrollbars.
	(Fx_create_frame): Remove old scrollbar setup code.
	(install_vertical_scrollbar, install_horizontal_scrollbar,
	adjust_scrollbars, x_resize_scrollbars): Deleted.
	* xterm.c (construct_mouse_click): This doesn't need to take care of
	scrollbar clicks anymore.
	(XTread_socket): Remove old code to support scrollbars.  Call new
	functions instead for events which occur in scrollbar windows.
	(XTupdate_end): Remove call to adjust_scrollbars; the main
	redisplay code takes care of that now.
	(enum window_type): Deleted.
	* ymakefile: Note that xfns.o no longer depends on xscrollbar.h.

	* xterm.c (x_set_mouse_position): Clip mouse position to be within
	frame.

	* xterm.c: Adjust the first line of each page to have a reasonable
	description.  This makes pages-directory more useful.

	* xterm.c (x_do_pending_expose): Declare this routine only if
	HAVE_X11 is not #defined; X11 doesn't need it.
	(XTread_socket): Protect call to x_do_pending_expose with `#ifdef
	HAVE_X11'.

	* xterm.c (notice_mouse_movement): Deleted; obsolete and unused.

	Properly handle focus shift events, so the cursor is filled and
	hollow at the appropriate times, even in titleless windows.
	* xterm.c (x_focus_event_frame): New variable.
	(XTread_socket): When we receive a FocusIn event that's not
	NotifyPointer, record the frame in x_focus_event_frame.  When we
	receive a FocusOut event that's not NotifyPointer, clear it.  When
	we get a LeaveNotify event, don't take it seriously if we still
	have focus.

	* xterm.c (XTread_socket): Remove special code in EnterNotify case
	to handle scrollbars and fake mouse motion events.

	Change the meaning of focus redirection to make switching windows
	work properly.  Fredirect_frame_focus has the details.
	* frame.h (focus_frame): Doc fix.
	[not MULTI_FRAME] (FRAME_FOCUS_FRAME): Make this Qnil, which
	indicates no focus redirection, instead of zero, which is
	selected_frame.
	* frame.c (make_frame): Initialize f->focus_frame to Qnil, rather
	than making it point to frame itself.
	(Fselect_frame): If changing the selected frame from FOO to BAR,
	make all redirections to FOO shift to BAR as well.  Doc fix.
	(Fredirect_frame_focus): Doc fix.  Accept nil as a valid
	redirection, not just as a default for FRAME.
	(Fframe_focus): Doc fix.
	* keyboard.c (kbd_buffer_store_event, kbd_buffer_get_event): Deal
	with focus redirections being nil.
	* xterm.c (XTframe_rehighlight): Doc fix.  Deal with focus
	redirections being nil.

	* xterm.c (x_error_quitter): Just abort, so we can look at the
	core to see what happened.

	It's a pain to remember that you can't assign to FRAME->visible.
	Let's change all references to the `visible' member of struct
	frame to use the accessor macros, and then write a setter for the
	`visible' field that does the right thing.
	* frame.h (FRAME_VISIBLE_P): Make this not an l-value.
	(FRAME_SET_VISIBLE): New macro.
	* frame.c (make_terminal_frame, Fdelete_frame): Use FRAME_SET_VISIBLE.
	(Fframe_visible_p, Fvisible_frame_list): Use FRAME_VISIBLE_P and
	FRAME_ICONIFIED_P.
	* dispnew.c (Fredraw_display): Use the FRAME_VISIBLE_P and
	FRAME_GARBAGED_P accessors.
	* xdisp.c (redisplay): Use the FRAME_VISIBLE_P accessor.
	* xfns.c (x_set_foreground_color, x_set_background_color,
	x_set_cursor_color, x_set_border_pixel, x_set_icon_type): Use the
	FRAME_VISIBLE_P accessor.
	(Fx_create_frame): Use FRAME_SET_VISIBILITY.
	* xterm.c (clear_cursor, x_display_bar_cursor,
	x_display_box_cursor): Use FRAME_SET_VISIBILITY.
parent 179956b9
......@@ -38,6 +38,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This may include sys/types.h, and that somehow loses
if this is not done before the other system files. */
#include "xterm.h"
#include <X11/cursorfont.h>
#ifndef USG
/* Load sys/types.h if not already loaded.
......@@ -89,6 +90,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "frame.h"
#include "disptab.h"
#include "buffer.h"
#include "window.h"
#ifdef HAVE_X11
#define XMapWindow XMapRaised /* Raise them when mapping. */
......@@ -105,8 +107,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Nonzero means we must reprint all windows
because 1) we received an ExposeWindow event
or 2) we received too many ExposeRegion events to record. */
or 2) we received too many ExposeRegion events to record.
This is never needed under X11. */
static int expose_all_windows;
/* Nonzero means we must reprint all icon windows. */
......@@ -159,6 +162,9 @@ Lisp_Object invocation_name;
Display *x_current_display;
/* The cursor to use for vertical scrollbars on x_current_display. */
static Cursor x_vertical_scrollbar_cursor;
/* Frame being updated by update_frame. */
/* This is set by XTupdate_begin and looked at by all the
XT functions. It is zero while not inside an update.
......@@ -168,9 +174,18 @@ Display *x_current_display;
static struct frame *updating_frame;
/* The frame (if any) which has the X window that has keyboard focus.
Zero if none. This is examined by Ffocus_frame in frame.c. */
Zero if none. This is examined by Ffocus_frame in frame.c. Note
that a mere EnterNotify event can set this; if you need to know the
last frame specified in a FocusIn or FocusOut event, use
x_focus_event_frame. */
struct frame *x_focus_frame;
/* The last frame mentioned in a FocusIn or FocusOut event. This is
separate from x_focus_frame, because whether or not LeaveNotify
events cause us to lose focus depends on whether or not we have
received a FocusIn event for it. */
struct frame *x_focus_event_frame;
/* The frame which currently has the visual highlight, and should get
keyboard input (other sorts of input have the frame encoded in the
event). It points to the X focus frame's selected window's
......@@ -260,7 +275,9 @@ static int XTcursor_to ();
static int XTclear_end_of_line ();
/* These hooks are called by update_frame at the beginning and end
/* Starting and ending updates.
These hooks are called by update_frame at the beginning and end
of a frame update. We record in `updating_frame' the identity
of the frame being updated, so that the XT... functions do not
need to take a frame as argument. Most of the XT... functions
......@@ -289,7 +306,9 @@ XTupdate_begin (f)
UNBLOCK_INPUT;
}
#ifndef HAVE_X11
static void x_do_pending_expose ();
#endif
static
XTupdate_end (f)
......@@ -304,9 +323,8 @@ XTupdate_end (f)
BLOCK_INPUT;
#ifndef HAVE_X11
dumpqueue ();
#endif /* HAVE_X11 */
adjust_scrollbars (f);
x_do_pending_expose ();
#endif /* HAVE_X11 */
x_display_cursor (f, 1);
......@@ -356,8 +374,8 @@ XTreset_terminal_modes ()
/* XTclear_frame (); */
}
/* Set the nominal cursor position of the frame:
where display update commands will take effect.
/* Set the nominal cursor position of the frame.
This is where display update commands will take effect.
This does not affect the place where the cursor-box is displayed. */
static int
......@@ -524,8 +542,8 @@ dumpglyphs (f, left, top, gp, n, hl, font)
}
#endif /* ! 0 */
/* Output some text at the nominal frame cursor position,
advancing the cursor over the text.
/* Output some text at the nominal frame cursor position.
Advance the cursor over the text.
Output LEN glyphs at START.
`highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
......@@ -577,7 +595,8 @@ XTwrite_glyphs (start, len)
UNBLOCK_INPUT;
}
/* Erase the current text line from the nominal cursor position (inclusive)
/* Clear to the end of the line.
Erase the current text line from the nominal cursor position (inclusive)
to column FIRST_UNUSED (exclusive). The idea is that everything
from FIRST_UNUSED onward is already erased. */
......@@ -758,8 +777,9 @@ XTring_bell ()
}
}
/* Insert and delete character are not supposed to be used
because we are supposed to turn off the feature of using them. */
/* Insert and delete character.
These are not supposed to be used because we are supposed to turn
off the feature of using them. */
static
XTinsert_glyphs (start, len)
......@@ -794,8 +814,8 @@ XTset_terminal_window (n)
flexlines = n;
}
/* Perform an insert-lines operation, inserting N lines
at a vertical position curs_y. */
/* Perform an insert-lines operation.
Insert N lines at a vertical position curs_y. */
static void
stufflines (n)
......@@ -955,6 +975,7 @@ XTins_del_lines (vpos, n)
UNBLOCK_INPUT;
}
/* Support routines for exposure events. */
static void clear_cursor ();
/* Output into a rectangle of an X-window (for frame F)
......@@ -1072,10 +1093,11 @@ dumpqueue ()
}
#endif /* HAVE_X11 */
/* Process all expose events that are pending.
/* Process all expose events that are pending, for X10.
Redraws the cursor if necessary on any frame that
is not in the process of being updated with update_frame. */
#ifndef HAVE_X11
static void
x_do_pending_expose ()
{
......@@ -1139,6 +1161,7 @@ x_do_pending_expose ()
dumpqueue ();
#endif /* ! defined (HAVE_X11) */
}
#endif
#ifdef HAVE_X11
static void
......@@ -1245,9 +1268,9 @@ x_new_focus_frame (frame)
}
/* The focus has changed, or we have make a frame's selected window
point to a window on a different frame (this happens with global
minibuffer frames). Shift the highlight as appropriate. */
/* The focus has changed, or we have redirected a frame's focus to
another frame (this happens when a frame uses a surrogate
minibuffer frame). Shift the highlight as appropriate. */
static void
XTframe_rehighlight ()
{
......@@ -1255,10 +1278,15 @@ XTframe_rehighlight ()
if (x_focus_frame)
{
x_highlight_frame = XFRAME (FRAME_FOCUS_FRAME (x_focus_frame));
if (x_highlight_frame->display.nothing == 0)
XSET (FRAME_FOCUS_FRAME (x_focus_frame), Lisp_Frame,
(x_highlight_frame = x_focus_frame));
x_highlight_frame =
((XTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
: x_focus_frame);
if (! FRAME_LIVE_P (x_highlight_frame))
{
FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
x_highlight_frame = x_focus_frame;
}
}
else
x_highlight_frame = 0;
......@@ -1271,114 +1299,6 @@ XTframe_rehighlight ()
frame_highlight (x_highlight_frame);
}
}
enum window_type
{
no_window,
scrollbar_window,
text_window,
};
/* Position of the mouse in characters */
unsigned int x_mouse_x, x_mouse_y;
/* Offset in buffer of character under the pointer, or 0. */
extern int mouse_buffer_offset;
extern int buffer_posn_from_coords ();
/* Symbols from xfns.c to denote the different parts of a window. */
extern Lisp_Object Qmodeline_part, Qtext_part;
#if 0
/* Set *RESULT to an emacs input_event corresponding to MOTION_EVENT.
F is the frame in which the event occurred.
WINDOW_TYPE says whether the event happened in a scrollbar window
or a text window, affecting the format of the event created.
PART specifies which part of the scrollbar the event happened in,
if WINDOW_TYPE == scrollbar_window.
If the mouse is over the same character as the last time we checked,
don't return an event; set result->kind to no_event. */
static void
notice_mouse_movement (result, motion_event, f, window_type, part)
struct input_event *result;
XMotionEvent motion_event;
struct frame *f;
int window_type;
Lisp_Object part;
{
int x, y, root_x, root_y, pix_x, pix_y;
unsigned int keys_and_buttons;
Window w, root_window;
/* Unless we decide otherwise below, return a non-event. */
result->kind = no_event;
if (XQueryPointer (x_current_display,
FRAME_X_WINDOW (f),
&root_window, &w,
&root_x, &root_y, &pix_x, &pix_y,
&keys_and_buttons)
== False)
return;
#if 0
if (w == None) /* Mouse no longer in window. */
return Qnil;
#endif /* ! 0 */
pixel_to_glyph_translation (f, pix_x, pix_y, &x, &y);
if (x == x_mouse_x && y == x_mouse_y)
return;
x_mouse_x = x;
x_mouse_y = y;
/* What sort of window are we in now? */
if (window_type == text_window) /* Text part */
{
int modeline_p;
Vmouse_window = window_from_coordinates (f, x, y, &modeline_p);
if (XTYPE (Vmouse_window) == Lisp_Window)
mouse_buffer_offset
= buffer_posn_from_coords (XWINDOW (Vmouse_window), x, y);
else
mouse_buffer_offset = 0;
if (EQ (Vmouse_window, Qnil))
Vmouse_frame_part = Qnil;
else if (modeline_p)
Vmouse_frame_part = Qmodeline_part;
else
Vmouse_frame_part = Qtext_part;
result->kind = window_sys_event;
result->code = Qmouse_moved;
return;
}
else if (window_type == scrollbar_window) /* Scrollbar */
{
Vmouse_window = f->selected_window;
mouse_buffer_offset = 0;
Vmouse_frame_part = part;
result->kind = window_sys_event;
result->code = Qmouse_moved;
return;
}
return;
}
#endif /* ! 0 */
/* Mouse clicks and mouse movement. Rah. */
#ifdef HAVE_X11
......@@ -1531,30 +1451,21 @@ x_convert_modifiers (state)
| ((state & x_meta_mod_mask) ? meta_modifier : 0));
}
extern struct frame *x_window_to_scrollbar ();
extern Lisp_Object Vmouse_event;
/* Prepare a mouse-event in *RESULT for placement in the input queue.
If the event is a button press, then note that we have grabbed
the mouse.
If PART and PREFIX are 0, then the event occurred in the text part;
otherwise it happened in a scrollbar. */
the mouse. */
static Lisp_Object
construct_mouse_click (result, event, f, part, prefix)
construct_mouse_click (result, event, f)
struct input_event *result;
XButtonEvent *event;
struct frame *f;
int prefix;
Lisp_Object part;
{
/* Initialize those fields text and scrollbar clicks hold in common.
Make the event type no_event; we'll change that when we decide
/* Make the event type no_event; we'll change that when we decide
otherwise. */
result->kind = no_event;
XSET (result->code, Lisp_Int, event->button);
result->kind = mouse_click;
XSET (result->code, Lisp_Int, event->button - Button1);
result->timestamp = event->time;
result->modifiers = (x_convert_modifiers (event->state)
| (event->type == ButtonRelease
......@@ -1575,33 +1486,14 @@ construct_mouse_click (result, event, f, part, prefix)
Vmouse_depressed = Qnil;
}
if (! NILP (part)) /* Scrollbar event */
{
int pos, len;
pos = event->y - (f->display.x->v_scrollbar_width - 2);
x_mouse_x = pos;
len = ((FONT_HEIGHT (f->display.x->font) * f->height)
+ f->display.x->internal_border_width
- (2 * (f->display.x->v_scrollbar_width - 2)));
x_mouse_y = len;
result->kind = scrollbar_click;
result->part = part;
XSET (result->x, Lisp_Int, (f->display.x->top_pos - event->y));
XSET (result->y, Lisp_Int, f->display.x->pixel_height);
result->frame = f;
}
else /* Text Window Event */
{
int row, column;
{
int row, column;
pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
result->kind = mouse_click;
XFASTINT (result->x) = column;
XFASTINT (result->y) = row;
result->frame = f;
}
pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
XFASTINT (result->x) = column;
XFASTINT (result->y) = row;
result->frame = f;
}
}
......@@ -1628,6 +1520,15 @@ construct_mouse_click (result, event, f, part, prefix)
static FRAME_PTR last_mouse_frame;
static XRectangle last_mouse_glyph;
/* If the last-checked mouse motion was in a scrollbar, this is that
scrollbar, the part being dragged, and the limits it is moving in.
Otherwise, this is zero. */
static struct scrollbar *last_mouse_bar;
static FRAME_PTR last_mouse_bar_frame;
static enum scrollbar_part last_mouse_part;
static int last_mouse_scroll_range_start;
static int last_mouse_scroll_range_end;
/* This is a hack. We would really prefer that XTmouse_position would
return the time associated with the position it returns, but there
doesn't seem to be any way to wrest the timestamp from the server
......@@ -1679,8 +1580,10 @@ note_mouse_position (frame, event)
*/
static void
XTmouse_position (f, x, y, time)
XTmouse_position (f, bar, part, x, y, time)
FRAME_PTR *f;
struct scrollbar **bar;
enum scrollbar_part *part;
Lisp_Object *x, *y;
unsigned long *time;
{
......@@ -1724,17 +1627,35 @@ XTmouse_position (f, x, y, time)
try instead. */
guess = root;
*f = last_mouse_frame = x_window_to_frame (guess);
if (! *f)
*x = *y = Qnil;
if (last_mouse_bar)
{
*f = last_mouse_bar_frame;
*bar = last_mouse_bar;
*part = last_mouse_part;
if (iy < last_mouse_scroll_range_start)
iy = last_mouse_scroll_range_start;
if (iy > last_mouse_scroll_range_end)
iy = last_mouse_scroll_range_end;
XSETINT (*x, iy - last_mouse_scroll_range_start);
XSETINT (*y, (last_mouse_scroll_range_end
- last_mouse_scroll_range_start));
}
else
{
pixel_to_glyph_coords (*f, ix, iy, &ix, &iy, &last_mouse_glyph);
XSET (*x, Lisp_Int, ix);
XSET (*y, Lisp_Int, iy);
*f = last_mouse_frame = x_window_to_frame (guess);
if (! *f)
*x = *y = Qnil;
else
{
pixel_to_glyph_coords (*f, ix, iy, &ix, &iy, &last_mouse_glyph);
XSET (*x, Lisp_Int, ix);
XSET (*y, Lisp_Int, iy);
}
}
mouse_moved = 0;
last_mouse_bar = 0;
/* I don't know how to find the time for the last movement; it seems
like XQueryPointer ought to return it, but it doesn't. So, we'll
......@@ -1750,6 +1671,472 @@ XTmouse_position (f, x, y, time)
#define XEvent XKeyPressedEvent
#endif /* ! defined (HAVE_X11) */
/* Scrollbar support. */
/* Map an X window that implements a scroll bar to the struct
scrollbar representing it. */
static struct scrollbar *
x_window_to_scrollbar (window_id)
Window window_id;
{
Lisp_Object tail, frame;
struct frame *f;
for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
{
struct scrollbar *bar;
Lisp_Object frame = XCONS (tail)->car;
/* All elements of Vframe_list should be frames. */
if (XTYPE (frame) != Lisp_Frame)
abort ();
/* Scan this frame's scrollbar list for a scrollbar with the
right window ID. */
for (bar = XFRAME (frame)->display.x->vertical_scrollbars;
bar;
bar = bar->next)
if (bar->window == window_id)
return bar;
}
return 0;
}
/* Open a new X window to serve as a scrollbar. */
static struct scrollbar *
x_scrollbar_create (frame, top, left, width, height)
FRAME_PTR frame;
int top, left, width, height;
{
struct x_display *d = frame->display.x;
/* We can't signal a malloc error from within redisplay, so call
malloc instead of xmalloc. */
struct scrollbar *bar =
(struct scrollbar *) malloc (sizeof (struct scrollbar));
if (! bar)
return 0;
BLOCK_INPUT;
{
XSetWindowAttributes a;
unsigned long mask;
a.background_pixel = d->background_pixel;
a.border_pixel = d->foreground_pixel;
a.event_mask = (KeyPressMask
| ButtonPressMask | ButtonReleaseMask
| ButtonMotionMask);
a.cursor = x_vertical_scrollbar_cursor;
mask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
bar->window =
XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
/* Position and size of scrollbar. */
top, left, width, height,
/* Border width, depth, class, and visual. */
1, CopyFromParent, CopyFromParent, CopyFromParent,
/* Attributes. */
mask, &a);
}
bar->frame = frame;
bar->top = top;
bar->left = left;
bar->width = width;
bar->height = height;
bar->start = bar->end = 0;
bar->judge_timestamp = d->judge_timestamp;
bar->dragging = -1;
/* Add bar to its frame's list of scroll bars. */
bar->next = d->vertical_scrollbars;
d->vertical_scrollbars = bar;
XMapWindow (x_current_display, bar->window);
UNBLOCK_INPUT;
}
/* Draw BAR's handle in the proper position. */
static void
x_scrollbar_set_handle (bar, start, end)
struct scrollbar *bar;
int start, end;
{
BLOCK_INPUT;
{
int inside_width = (bar->width
- VERTICAL_SCROLLBAR_LEFT_BORDER
- VERTICAL_SCROLLBAR_RIGHT_BORDER);
int inside_height = (bar->height
- VERTICAL_SCROLLBAR_TOP_BORDER
- VERTICAL_SCROLLBAR_BOTTOM_BORDER);
/* Make sure the values are reasonable, and try to preserve
the distance between start and end. */
if (end < start)
end = start;
if (start < VERTICAL_SCROLLBAR_TOP_BORDER)
{
end = VERTICAL_SCROLLBAR_TOP_BORDER + (end - start);
start = VERTICAL_SCROLLBAR_TOP_BORDER;
}
if (end > bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER)
{
start = ((bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER)
- (end - start));
end = bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER;
}
if (start < VERTICAL_SCROLLBAR_TOP_BORDER)
start = VERTICAL_SCROLLBAR_TOP_BORDER;
/* Draw the empty space above the handle. */
XClearArea (x_current_display, bar->window,
/* x, y, width, height, and exposures. */
VERTICAL_SCROLLBAR_LEFT_BORDER,
VERTICAL_SCROLLBAR_TOP_BORDER,
inside_width + 1, start + 1,
False);
/* Draw the handle itself. */
XFillRectangle (x_current_display, bar->window,
bar->frame->display.x->normal_gc,
/* x, y, width, height */
VERTICAL_SCROLLBAR_LEFT_BORDER, start,
inside_width, (end - start) + 1);
/* Draw the empty space below the handle. */
XClearArea (x_current_display, bar->window,
/* x, y, width, height, and exposures. */
VERTICAL_SCROLLBAR_LEFT_BORDER,
VERTICAL_SCROLLBAR_TOP_BORDER + end,
inside_width + 1, (inside_height - end) + 1,
False);
bar->start = start;
bar->end = end;
}
UNBLOCK_INPUT;
}
/* Remove the scrollbar BAR. */
static void
x_scrollbar_remove (bar)
struct scrollbar *bar;
{
BLOCK_INPUT;
/* Remove bar from the frame's list. */
{
struct scrollbar **ptr;
for (ptr = &bar->frame->display.x->vertical_scrollbars;
*ptr;
ptr = &(*ptr)->next)
if (*ptr == bar)
{
*ptr = bar->next;
break;
}
}
/* Destroy the window. */
XDestroyWindow (x_current_display, bar->window);
/* Free the storage. */
free (bar);
UNBLOCK_INPUT;
}
static void
x_scrollbar_move (bar, top, left, width, height)
struct scrollbar *bar;
int top, left, width, height;
{
BLOCK_INPUT;
{
XWindowChanges wc;
unsigned int mask = 0;
wc.x = left;
wc.y = top;
wc.width = width;
wc.height = height;
if (left != bar->left) mask |= CWX;
if (top != bar->top) mask |= CWY;
if (width != bar->width) mask |= CWWidth;
if (height != bar->height) mask |= CWHeight;
XConfigureWindow (x_current_display, bar->window, mask, &wc);
}
UNBLOCK_INPUT;
}
/* Set BAR to be the vertical scroll bar for WINDOW. Set its handle
to indicate that we are displaying PORTION characters out of a
total of WHOLE characters, starting at POSITION. Return BAR. If
BAR is zero, create a new scrollbar and return a pointer to it. */
static struct scrollbar *
XTset_scrollbar (bar, window, portion, whole, position)
struct scrollbar *bar;
struct window *window;
int portion, whole, position;
{
FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
struct x_display *d = f->display.x;
int top = XINT (window->top);
int left = WINDOW_VERTICAL_SCROLLBAR_COLUMN (window);
int height = WINDOW_VERTICAL_SCROLLBAR_HEIGHT (window);
/* Where should this scrollbar be, pixelwise? */
int pixel_top = (d->internal_border_width + top * FONT_HEIGHT (d->font));