/* * This is the only callback provided for horizontal scrollbars. It * should be able to handle all of the scrollbar events in * scroll_action (see lwlib.h). The client data will be of type * scroll_event (see lwlib.h). */ static void x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id, XtPointer client_data) { scroll_event *data = (scroll_event *) client_data; struct device *d = get_device_from_display (XtDisplay (widget)); struct frame *f = x_any_window_to_frame (d, XtWindow (widget)); Lisp_Object win, frame; struct window_mirror *mirror; if (!f) return; mirror = find_scrollbar_window_mirror (f, id); if (!mirror) return; win = real_window (mirror, 1); if (NILP (win)) return; frame = WINDOW_FRAME (XWINDOW (win)); /* It seems that this is necessary whenever signal_special_Xt_user_event() is called. #### Why??? */ DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); switch (data->action) { case SCROLLBAR_LINE_UP: signal_special_Xt_user_event (frame, Qscrollbar_char_left, win); break; case SCROLLBAR_LINE_DOWN: signal_special_Xt_user_event (frame, Qscrollbar_char_right, win); break; case SCROLLBAR_PAGE_UP: signal_special_Xt_user_event (frame, Qscrollbar_page_left, win); break; case SCROLLBAR_PAGE_DOWN: signal_special_Xt_user_event (frame, Qscrollbar_page_right, win); break; case SCROLLBAR_TOP: signal_special_Xt_user_event (frame, Qscrollbar_to_left, win); break; case SCROLLBAR_BOTTOM: signal_special_Xt_user_event (frame, Qscrollbar_to_right, win); break; case SCROLLBAR_CHANGE: inhibit_slider_size_change = 0; break; case SCROLLBAR_DRAG: inhibit_slider_size_change = 1; /* #### Fix the damn toolkit code so they all work the same way. Lucid is the one mostly wrong.*/ #if defined (LWLIB_SCROLLBARS_LUCID) || defined (LWLIB_SCROLLBARS_ATHENA3D) signal_special_Xt_user_event (frame, Qscrollbar_horizontal_drag, (Fcons (win, make_int (data->slider_value)))); #else signal_special_Xt_user_event (frame, Qscrollbar_horizontal_drag, (Fcons (win, make_int (data->slider_value - 1)))); #endif break; default: break; } }
void popup_selection_callback(Widget widget, LWLIB_ID ignored_id, XtPointer client_data) { Lisp_Object data, image_instance, callback, callback_ex; Lisp_Object frame, event; int update_subwindows_p = 0; struct device *d = get_device_from_display(XtDisplay(widget)); struct frame *f = x_any_widget_or_parent_to_frame(d, widget); /* set in lwlib to the time stamp associated with the most recent menu operation */ extern Time x_focus_timestamp_really_sucks_fix_me_better; if (!f) return; if (((EMACS_INT) client_data) == 0) return; VOID_TO_LISP(data, client_data); XSETFRAME(frame, f); #if 0 /* #### What the hell? I can't understand why this call is here, and doing it is really courting disaster in the new event model, since popup_selection_callback is called from within next_event_internal() and Faccept_process_output() itself calls next_event_internal(). --Ben */ /* Flush the X and process input */ Faccept_process_output(Qnil, Qnil, Qnil); #endif if (((EMACS_INT) client_data) == -1) { event = Fmake_event(Qnil, Qnil); XEVENT(event)->event_type = misc_user_event; XEVENT(event)->channel = frame; XEVENT(event)->event.eval.function = Qrun_hooks; XEVENT(event)->event.eval.object = Qmenu_no_selection_hook; } else { image_instance = XCAR(data); callback = XCAR(XCDR(data)); callback_ex = XCDR(XCDR(data)); update_subwindows_p = 1; /* It is possible for a widget action to cause it to get out of sync with its instantiator. Thus it is necessary to signal this possibility. */ if (IMAGE_INSTANCEP(image_instance)) XIMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(image_instance) = 1; if (!NILP(callback_ex) && !UNBOUNDP(callback_ex)) { event = Fmake_event(Qnil, Qnil); XEVENT(event)->event_type = misc_user_event; XEVENT(event)->channel = frame; XEVENT(event)->event.eval.function = Qeval; XEVENT(event)->event.eval.object = list4(Qfuncall, callback_ex, image_instance, event); } else if (NILP(callback) || UNBOUNDP(callback)) event = Qnil; else { Lisp_Object fn, arg; event = Fmake_event(Qnil, Qnil); get_gui_callback(callback, &fn, &arg); XEVENT(event)->event_type = misc_user_event; XEVENT(event)->channel = frame; XEVENT(event)->event.eval.function = fn; XEVENT(event)->event.eval.object = arg; } } /* This is the timestamp used for asserting focus so we need to get an up-to-date value event if no events have been dispatched to emacs */ #if defined(HAVE_MENUBARS) DEVICE_X_MOUSE_TIMESTAMP(d) = x_focus_timestamp_really_sucks_fix_me_better; #else DEVICE_X_MOUSE_TIMESTAMP(d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP(d); #endif if (!NILP(event)) enqueue_Xt_dispatch_event(event); /* The result of this evaluation could cause other instances to change so enqueue an update callback to check this. */ if (update_subwindows_p && !NILP(event)) enqueue_magic_eval_event(update_widget_instances, frame); }
/* * This is the only callback provided for vertical scrollbars. It * should be able to handle all of the scrollbar events in * scroll_action (see lwlib.h). The client data will be of type * scroll_event (see lwlib.h). */ static void x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id, XtPointer client_data) { /* This function can GC */ scroll_event *data = (scroll_event *) client_data; struct device *d = get_device_from_display (XtDisplay (widget)); struct frame *f = x_any_window_to_frame (d, XtWindow (widget)); Lisp_Object win, frame; struct scrollbar_instance *instance; struct window_mirror *mirror; if (!f) return; mirror = find_scrollbar_window_mirror (f, id); if (!mirror) return; win = real_window (mirror, 1); if (NILP (win)) return; instance = mirror->scrollbar_vertical_instance; frame = WINDOW_FRAME (XWINDOW (win)); /* It seems that this is necessary whenever signal_special_Xt_user_event() is called. #### Why??? */ DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); switch (data->action) { case SCROLLBAR_LINE_UP: signal_special_Xt_user_event (frame, Qscrollbar_line_up, win); break; case SCROLLBAR_LINE_DOWN: signal_special_Xt_user_event (frame, Qscrollbar_line_down, win); break; /* The Athena scrollbar paging behavior is that of xterms. Depending on where you click the size of the page varies. Motif always does a standard Emacs page. */ case SCROLLBAR_PAGE_UP: #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID) && \ !defined (LWLIB_SCROLLBARS_ATHENA3D) { double tmp = ((double) data->slider_value / (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height); double line = tmp * (double) window_displayed_height (XWINDOW (win)); if (line > -1.0) line = -1.0; signal_special_Xt_user_event (frame, Qscrollbar_page_up, Fcons (win, make_int ((int) line))); } #else signal_special_Xt_user_event (frame, Qscrollbar_page_up, Fcons (win, Qnil)); #endif break; case SCROLLBAR_PAGE_DOWN: #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID) && \ !defined (LWLIB_SCROLLBARS_ATHENA3D) { double tmp = ((double) data->slider_value / (double) SCROLLBAR_X_POS_DATA(instance).scrollbar_height); double line = tmp * (double) window_displayed_height (XWINDOW (win)); if (SCROLLBAR_X_POS_DATA(instance).maximum > (SCROLLBAR_X_POS_DATA(instance).slider_size + SCROLLBAR_X_POS_DATA(instance).slider_position)) { if (line < 1.0) line = 1.0; signal_special_Xt_user_event (frame, Qscrollbar_page_down, Fcons (win, make_int ((int) line))); } } #else signal_special_Xt_user_event (frame, Qscrollbar_page_down, Fcons (win, Qnil)); #endif break; case SCROLLBAR_TOP: signal_special_Xt_user_event (frame, Qscrollbar_to_top, win); break; case SCROLLBAR_BOTTOM: signal_special_Xt_user_event (frame, Qscrollbar_to_bottom, win); break; case SCROLLBAR_CHANGE: inhibit_slider_size_change = 0; #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) vertical_drag_in_progress = 0; SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value; SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) = XINT (Fwindow_start (win)); #else stupid_vertical_scrollbar_drag_hack = 0; #endif break; case SCROLLBAR_DRAG: { int value; inhibit_slider_size_change = 1; #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID) /* Doing drags with Motif-like scrollbars is a mess, since we want to avoid having the window position jump when you first grab the scrollbar, but we also want to ensure that you can scroll all the way to the top or bottom of the buffer. This can all be replaced with something sane when we get line-based scrolling. */ vertical_drag_in_progress = 1; if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) < 0) { SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value; SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) = XINT (Fwindow_start (win)); } /* Could replace this piecewise linear scrolling with a quadratic through the three points, but I'm not sure that would feel any nicer in practice. */ if (data->slider_value < SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)) { /* We've dragged up; slide linearly from original position to window-start=data.minimum, slider-value=data.minimum. */ if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) <= SCROLLBAR_X_POS_DATA (instance).minimum) { /* shouldn't get here, but just in case */ value = SCROLLBAR_X_POS_DATA (instance).minimum; } else { value = (int) (SCROLLBAR_X_POS_DATA (instance).minimum + (((double) (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) - SCROLLBAR_X_POS_DATA (instance).minimum) * (data->slider_value - SCROLLBAR_X_POS_DATA (instance).minimum)) / (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) - SCROLLBAR_X_POS_DATA (instance).minimum))); } } else { /* We've dragged down; slide linearly from original position to window-start=data.maximum, slider-value=data.maximum. */ if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) >= (SCROLLBAR_X_POS_DATA (instance).maximum - SCROLLBAR_X_POS_DATA (instance).slider_size)) { /* avoid divide by zero */ value = SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance); } else { value = (int) (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) + (((double) (SCROLLBAR_X_POS_DATA (instance).maximum - SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)) * (data->slider_value - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))) / (SCROLLBAR_X_POS_DATA (instance).maximum - SCROLLBAR_X_POS_DATA (instance).slider_size - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)))); } } #else stupid_vertical_scrollbar_drag_hack = 0; value = data->slider_value; #endif if (value >= SCROLLBAR_X_POS_DATA (instance).maximum) value = SCROLLBAR_X_POS_DATA (instance).maximum - 1; if (value < SCROLLBAR_X_POS_DATA (instance).minimum) value = SCROLLBAR_X_POS_DATA (instance).minimum; signal_special_Xt_user_event (frame, Qscrollbar_vertical_drag, Fcons (win, make_int (value))); } break; } }