예제 #1
0
/*
 * 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;
    }
}
예제 #2
0
파일: gui-x.c 프로젝트: hroptatyr/sxemacs
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);
}
예제 #3
0
/*
 * 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;

    }
}