+construct_scroll_bar_click (bar, part, bufp)
+ struct scroll_bar *bar;
+ int part;
+ struct input_event *bufp;
+{
+ bufp->kind = SCROLL_BAR_CLICK_EVENT;
+ bufp->frame_or_window = bar->window;
+ bufp->arg = Qnil;
+ bufp->part = part;
+ bufp->code = 0;
+ XSETINT (bufp->x, 0);
+ XSETINT (bufp->y, 0);
+ bufp->modifiers = 0;
+}
+
+static OSErr
+get_control_part_bounds (ch, part_code, rect)
+ ControlHandle ch;
+ ControlPartCode part_code;
+ Rect *rect;
+{
+ RgnHandle region = NewRgn ();
+ OSStatus err;
+
+ err = GetControlRegion (ch, part_code, region);
+ if (err == noErr)
+ GetRegionBounds (region, rect);
+ DisposeRgn (region);
+
+ return err;
+}
+
+static void
+x_scroll_bar_handle_press (bar, part_code, bufp)
+ struct scroll_bar *bar;
+ ControlPartCode part_code;
+ struct input_event *bufp;
+{
+ int part = control_part_code_to_scroll_bar_part (part_code);
+
+ if (part < 0)
+ return;
+
+ if (part != scroll_bar_handle)
+ {
+ construct_scroll_bar_click (bar, part, bufp);
+ HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), part_code);
+ set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
+ }
+
+ last_scroll_bar_part = part;
+ bar->dragging = Qnil;
+ tracked_scroll_bar = bar;
+}
+
+static void
+x_scroll_bar_handle_release (bar, bufp)
+ struct scroll_bar *bar;
+ struct input_event *bufp;
+{
+ if (last_scroll_bar_part != scroll_bar_handle
+ || !GC_NILP (bar->dragging))
+ construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
+
+ HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), 0);
+ set_scroll_bar_timer (kEventDurationForever);
+
+ last_scroll_bar_part = -1;
+ bar->dragging = Qnil;
+ tracked_scroll_bar = NULL;
+}
+
+static void
+x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
+ WindowPtr win;
+ struct scroll_bar *bar;
+ Point mouse_pos;
+ struct input_event *bufp;
+{
+ ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
+
+ if (last_scroll_bar_part == scroll_bar_handle)
+ {
+ int top, top_range;
+ Rect r;
+
+ get_control_part_bounds (SCROLL_BAR_CONTROL_HANDLE (bar),
+ kControlIndicatorPart, &r);
+
+ if (GC_NILP (bar->dragging))
+ XSETINT (bar->dragging, mouse_pos.v - r.top);
+
+ top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
+ top_range = (XINT (bar->track_height) - (r.bottom - r.top)) *
+ (1.0 + (float) GetControlViewSize (ch) / GetControl32BitMaximum (ch))
+ + .5;
+
+ if (top < 0)
+ top = 0;
+ if (top > top_range)
+ top = top_range;
+
+ construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
+ XSETINT (bufp->x, top);
+ XSETINT (bufp->y, top_range);
+ }
+ else
+ {
+ ControlPartCode part_code;
+ int unhilite_p = 0, part;
+
+ if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
+ unhilite_p = 1;
+ else
+ {
+ part = control_part_code_to_scroll_bar_part (part_code);
+
+ switch (last_scroll_bar_part)
+ {
+ case scroll_bar_above_handle:
+ case scroll_bar_below_handle:
+ if (part != scroll_bar_above_handle
+ && part != scroll_bar_below_handle)
+ unhilite_p = 1;
+ break;
+
+ case scroll_bar_up_arrow:
+ case scroll_bar_down_arrow:
+ if (part != scroll_bar_up_arrow
+ && part != scroll_bar_down_arrow)
+ unhilite_p = 1;
+ break;
+ }
+ }
+
+ if (unhilite_p)
+ HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), 0);
+ else if (part != last_scroll_bar_part
+ || scroll_bar_timer_event_posted_p)
+ {
+ construct_scroll_bar_click (bar, part, bufp);
+ last_scroll_bar_part = part;
+ HiliteControl (SCROLL_BAR_CONTROL_HANDLE (bar), part_code);
+ set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
+ }
+ }
+}
+
+/* Set the thumb size and position of scroll bar BAR. We are currently
+ displaying PORTION out of a whole WHOLE, and our position POSITION. */
+
+static void
+x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
+ struct scroll_bar *bar;
+ int portion, position, whole;
+{
+ ControlHandle ch = SCROLL_BAR_CONTROL_HANDLE (bar);
+
+ int value, viewsize, maximum;
+
+ if (whole == 0 || XINT (bar->track_height) == 0)
+ value = 0, viewsize = 1, maximum = 0;
+ else
+ {
+ value = position;
+ viewsize = portion;
+ maximum = max (0, whole - portion);
+ }
+
+ BLOCK_INPUT;
+
+ SetControl32BitMinimum (ch, 0);
+ SetControl32BitMaximum (ch, maximum);
+ SetControl32BitValue (ch, value);
+ SetControlViewSize (ch, viewsize);
+
+ UNBLOCK_INPUT;
+}
+
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
+
+\f
+/************************************************************************
+ Scroll bars, general
+ ************************************************************************/
+
+/* Create a scroll bar and return the scroll bar vector for it. W is
+ the Emacs window on which to create the scroll bar. TOP, LEFT,
+ WIDTH and HEIGHT are the pixel coordinates and dimensions of the
+ scroll bar. */
+
+static struct scroll_bar *
+x_scroll_bar_create (w, top, left, width, height, disp_top, disp_height)
+ struct window *w;
+ int top, left, width, height, disp_top, disp_height;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct scroll_bar *bar
+ = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
+ Rect r;
+ ControlHandle ch;
+
+ BLOCK_INPUT;
+
+ r.left = left;
+ r.top = disp_top;
+ r.right = left + width;
+ r.bottom = disp_top + disp_height;
+
+#if TARGET_API_MAC_CARBON
+ ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
+ 0, 0, 0, kControlScrollBarProc, (long) bar);
+#else
+ ch = NewControl (FRAME_MAC_WINDOW (f), &r, "\p", width < disp_height,
+ 0, 0, 0, scrollBarProc, (long) bar);
+#endif
+ SET_SCROLL_BAR_CONTROL_HANDLE (bar, ch);
+
+ XSETWINDOW (bar->window, w);
+ XSETINT (bar->top, top);
+ XSETINT (bar->left, left);
+ XSETINT (bar->width, width);
+ XSETINT (bar->height, height);
+ XSETINT (bar->start, 0);
+ XSETINT (bar->end, 0);
+ bar->dragging = Qnil;
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ bar->track_top = Qnil;
+ bar->track_height = Qnil;
+#endif
+
+ /* Add bar to its frame's list of scroll bars. */
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
+ if (!NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+
+ UNBLOCK_INPUT;
+ return bar;
+}
+
+
+/* Draw BAR's handle in the proper position.
+
+ If the handle is already drawn from START to END, don't bother
+ redrawing it, unless REBUILD is non-zero; in that case, always
+ redraw it. (REBUILD is handy for drawing the handle after expose
+ events.)
+
+ Normally, we want to constrain the start and end of the handle to
+ fit inside its rectangle, but if the user is dragging the scroll
+ bar handle, we want to let them drag it down all the way, so that
+ the bar's top is as far down as it goes; otherwise, there's no way
+ to move to the very end of the buffer. */
+
+#ifndef USE_TOOLKIT_SCROLL_BARS
+
+static void
+x_scroll_bar_set_handle (bar, start, end, rebuild)