Beispiel #1
0
static void
gtk_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
{
  Lisp_Object frame;
  int x, y, width, height, vert;

  get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
  XSETFRAME (frame, f);

  /* The thickness_change parameter is used by the toolbar resize routines
     to clear any excess toolbar if the size shrinks. */
  if (thickness_change < 0)
    {
      if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
	{
	  x = x + width + thickness_change;
	  width = -thickness_change;
	}
      else
	{
	  y = y + height + thickness_change;
	  height = -thickness_change;
	}
    }

  SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);

  redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
  gdk_flush ();
}
Beispiel #2
0
void
w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
{
  if (get_menu_item_info)
    {
      struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
      Lisp_Object frame, help;

      /* No help echo on owner-draw menu items, or when the keyboard
	 is used to navigate the menus, since tooltips are distracting
	 if they pop up elsewhere.  */
      if ((flags & MF_OWNERDRAW) || (flags & MF_POPUP)
	  || !(flags & MF_MOUSESELECT)
	  /* Ignore any dwItemData for menu items whose flags don't
	     have the MF_HILITE bit set.  These are dwItemData that
	     Windows sends our way, but they aren't pointers to our
	     Lisp_String objects, so trying to create Lisp_Strings out
	     of them below and pass that to the keyboard queue will
	     crash Emacs when we try to display those "strings".  It
	     is unclear why we get these dwItemData, or what they are:
	     sometimes they point to a wchar_t string that is the menu
	     title, sometimes to someting that doesn't look like text
	     at all.  (The problematic data also comes with the 0x0800
	     bit set, but this bit is not documented, so we don't want
	     to depend on it.)  */
	  || !(flags & MF_HILITE))
	help = Qnil;
      else
	{
	  MENUITEMINFO info;

	  memset (&info, 0, sizeof (info));
	  info.cbSize = sizeof (info);
	  info.fMask = MIIM_DATA;
	  get_menu_item_info (menu, item, FALSE, &info);

	  help =
	    info.dwItemData
	    ? make_lisp_ptr ((void *) info.dwItemData, Lisp_String)
	    : Qnil;
	}

      /* Store the help echo in the keyboard buffer as the X toolkit
	 version does, rather than directly showing it. This seems to
	 solve the GC problems that were present when we based the
	 Windows code on the non-toolkit version.  */
      if (f)
	{
	  XSETFRAME (frame, f);
	  kbd_buffer_store_help_event (frame, help);
	}
      else
	/* X version has a loop through frames here, which doesn't
	   appear to do anything, unless it has some side effect.  */
	show_help_echo (help, Qnil, Qnil, Qnil);
    }
}
Beispiel #3
0
/*
 * Return value is Qt if we have dispatched the command,
 * or Qnil if id has not been mapped to a callback.
 * Window procedure may try other targets to route the
 * command if we return nil
 */
Lisp_Object
mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, LPARAM id)
{
  /* Try to map the command id through the proper hash table */
  Lisp_Object callback, callback_ex, image_instance, frame, event;

  XSETFRAME (frame, f);

  /* #### make_int should assert that --kkm */
  assert (XINT (make_int (id)) == id);

  image_instance = Fgethash (make_int (id), 
			     FRAME_MSWINDOWS_WIDGET_HASH_TABLE1 (f), Qnil);
  /* 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;
  callback = Fgethash (make_int (id), 
		       FRAME_MSWINDOWS_WIDGET_HASH_TABLE2 (f), Qnil);
  callback_ex = Fgethash (make_int (id), 
			  FRAME_MSWINDOWS_WIDGET_HASH_TABLE3 (f), Qnil);

  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)->timestamp = GetTickCount ();
      XEVENT (event)->event.eval.function = Qeval;
      XEVENT (event)->event.eval.object =
	list4 (Qfuncall, callback_ex, image_instance, event);
    }
  else if (NILP (callback) || UNBOUNDP (callback))
    return 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)->timestamp = GetTickCount ();
      XEVENT (event)->event.eval.function = fn;
      XEVENT (event)->event.eval.object = arg;
    }

  mswindows_enqueue_dispatch_event (event);
  /* The result of this evaluation could cause other instances to change so 
     enqueue an update callback to check this. */
  enqueue_magic_eval_event (update_widget_instances, frame);
  return Qt;
}
Beispiel #4
0
static int
do_mouse_event (MOUSE_EVENT_RECORD *event,
		struct input_event *emacs_ev)
{
  static DWORD button_state = 0;
  DWORD but_change, mask;
  int i;

  if (event->dwEventFlags == MOUSE_MOVED)
    {
      /* For movement events we just note that the mouse has moved
	 so that emacs will generate drag events.  */
      mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
      return 0;
    }

  /* It looks like the console code sends us a mouse event with
     dwButtonState == 0 when a window is activated.  Ignore this case.  */
  if (event->dwButtonState == button_state)
    return 0;

  emacs_ev->kind = MOUSE_CLICK_EVENT;

  /* Find out what button has changed state since the last button event.  */
  but_change = button_state ^ event->dwButtonState;
  mask = 1;
  for (i = 0; mask; i++, mask <<= 1)
    if (but_change & mask)
      {
        if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
          emacs_ev->code = emacs_button_translation[i];
        else
          emacs_ev->code = i;
	break;
      }

  button_state = event->dwButtonState;
  emacs_ev->timestamp = GetTickCount ();
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
    ((event->dwButtonState & mask) ? down_modifier : up_modifier);

  XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
  XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
/* for Mule 2.2 (Based on Emacs 19.28 */
#ifdef MULE
  XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
#else
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
#endif

  return 1;
}
Beispiel #5
0
static GdkGC *get_toolbar_gc (struct frame *f)
{
  Lisp_Object fg, bg;
  Lisp_Object frame;

  XSETFRAME (frame, f);

  fg = Fspecifier_instance (Fget (Vtoolbar_face, Qforeground, Qnil), frame, Qnil, Qnil);
  bg = Fspecifier_instance (Fget (Vtoolbar_face, Qbackground, Qnil), frame, Qnil, Qnil);
				   
  /* Need to swap the foreground/background here or most themes look bug ugly */
  return (gtk_get_gc (XDEVICE (FRAME_DEVICE (f)), Qnil, bg, fg, Qnil, Qnil));
}
void
x_clear_frame_selections (FRAME_PTR f)
{
  Lisp_Object frame;
  Lisp_Object rest;
  struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
  struct terminal *t = dpyinfo->terminal;

  XSETFRAME (frame, f);

  /* Delete elements from the beginning of Vselection_alist.  */
  while (CONSP (t->Vselection_alist)
	 && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
    {
      /* Run the `x-lost-selection-functions' abnormal hook.  */
      Lisp_Object args[2];
      args[0] = Qx_lost_selection_functions;
      args[1] = Fcar (Fcar (t->Vselection_alist));
      if (x_selection_owner_p (args[1], dpyinfo))
	Frun_hook_with_args (2, args);

      tset_selection_alist (t, XCDR (t->Vselection_alist));
    }

  /* Delete elements after the beginning of Vselection_alist.  */
  for (rest = t->Vselection_alist; CONSP (rest); rest = XCDR (rest))
    if (CONSP (XCDR (rest))
	&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
      {
	Lisp_Object args[2];
	args[0] = Qx_lost_selection_functions;
	args[1] = XCAR (XCAR (XCDR (rest)));
	if (x_selection_owner_p (args[1], dpyinfo))
	  Frun_hook_with_args (2, args);
	XSETCDR (rest, XCDR (XCDR (rest)));
	break;
      }
}
Beispiel #7
0
Datei: menu.c Projekt: ueno/emacs
void
find_and_call_menu_selection (struct frame *f, int menu_bar_items_used,
			      Lisp_Object vector, void *client_data)
{
  Lisp_Object prefix, entry;
  Lisp_Object *subprefix_stack;
  int submenu_depth = 0;
  int i;
  USE_SAFE_ALLOCA;

  entry = Qnil;
  SAFE_NALLOCA (subprefix_stack, 1, menu_bar_items_used);
  prefix = Qnil;
  i = 0;

  while (i < menu_bar_items_used)
    {
      if (EQ (AREF (vector, i), Qnil))
	{
	  subprefix_stack[submenu_depth++] = prefix;
	  prefix = entry;
	  i++;
	}
      else if (EQ (AREF (vector, i), Qlambda))
	{
	  prefix = subprefix_stack[--submenu_depth];
	  i++;
	}
      else if (EQ (AREF (vector, i), Qt))
	{
	  prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
	  i += MENU_ITEMS_PANE_LENGTH;
	}
      else
	{
	  entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
	  /* Treat the pointer as an integer.  There's no problem
	     as long as pointers have enough bits to hold small integers.  */
	  if ((intptr_t) client_data == i)
	    {
	      int j;
	      struct input_event buf;
	      Lisp_Object frame;
	      EVENT_INIT (buf);

	      XSETFRAME (frame, f);
	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = frame;
	      kbd_buffer_store_event (&buf);

	      for (j = 0; j < submenu_depth; j++)
		if (!NILP (subprefix_stack[j]))
		  {
		    buf.kind = MENU_BAR_EVENT;
		    buf.frame_or_window = frame;
		    buf.arg = subprefix_stack[j];
		    kbd_buffer_store_event (&buf);
		  }

	      if (!NILP (prefix))
		{
		  buf.kind = MENU_BAR_EVENT;
		  buf.frame_or_window = frame;
		  buf.arg = prefix;
		  kbd_buffer_store_event (&buf);
		}

	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = entry;
	      kbd_buffer_store_event (&buf);

	      break;
	    }
	  i += MENU_ITEMS_ITEM_LENGTH;
	}
    }

  SAFE_FREE ();
}
Beispiel #8
0
static int
do_mouse_event (MOUSE_EVENT_RECORD *event,
		struct input_event *emacs_ev)
{
  static DWORD button_state = 0;
  static Lisp_Object last_mouse_window;
  DWORD but_change, mask;
  int i;

  if (event->dwEventFlags == MOUSE_MOVED)
    {
      FRAME_PTR f = SELECTED_FRAME ();
      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
      int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;

      mouse_moved_to (mx, my);

      if (f->mouse_moved)
	{
	  if (hlinfo->mouse_face_hidden)
	    {
	      hlinfo->mouse_face_hidden = 0;
	      clear_mouse_face (hlinfo);
	    }

	  /* Generate SELECT_WINDOW_EVENTs when needed.  */
	  if (!NILP (Vmouse_autoselect_window))
	    {
	      Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
								  0, 0);
	      /* A window will be selected only when it is not
		 selected now, and the last mouse movement event was
		 not in it.  A minibuffer window will be selected iff
		 it is active.  */
	      if (WINDOWP (mouse_window)
		  && !EQ (mouse_window, last_mouse_window)
		  && !EQ (mouse_window, selected_window))
		{
		  struct input_event event;

		  EVENT_INIT (event);
		  event.kind = SELECT_WINDOW_EVENT;
		  event.frame_or_window = mouse_window;
		  event.arg = Qnil;
		  event.timestamp = movement_time;
		  kbd_buffer_store_event (&event);
		}
	      last_mouse_window = mouse_window;
	    }
	  else
	    last_mouse_window = Qnil;

	  previous_help_echo_string = help_echo_string;
	  help_echo_string = help_echo_object = help_echo_window = Qnil;
	  help_echo_pos = -1;
	  note_mouse_highlight (f, mx, my);
	  /* If the contents of the global variable help_echo has
	     changed (inside note_mouse_highlight), generate a HELP_EVENT.  */
	  if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
	    gen_help_event (help_echo_string, selected_frame, help_echo_window,
			    help_echo_object, help_echo_pos);
	}
      return 0;
    }

  /* It looks like the console code sends us a mouse event with
     dwButtonState == 0 when a window is activated.  Ignore this case.  */
  if (event->dwButtonState == button_state)
    return 0;

  emacs_ev->kind = MOUSE_CLICK_EVENT;

  /* Find out what button has changed state since the last button event.  */
  but_change = button_state ^ event->dwButtonState;
  mask = 1;
  for (i = 0; mask; i++, mask <<= 1)
    if (but_change & mask)
      {
        if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
          emacs_ev->code = emacs_button_translation[i];
        else
          emacs_ev->code = i;
	break;
      }

  button_state = event->dwButtonState;
  emacs_ev->timestamp = GetTickCount ();
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
    ((event->dwButtonState & mask) ? down_modifier : up_modifier);

  XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
  XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
/* for Mule 2.2 (Based on Emacs 19.28 */
#ifdef MULE
  XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
#else
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
#endif

  return 1;
}
Beispiel #9
0
/* return code -1 means that event_queue_ptr won't be incremented.
   In other word, this event makes two key codes.   (by himi)       */
static int
key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
{
  static int mod_key_state = 0;
  int wParam;

  *isdead = 0;

  /* Skip key-up events.  */
  if (!event->bKeyDown)
    {
      switch (event->wVirtualKeyCode)
	{
	case VK_LWIN:
	  mod_key_state &= ~LEFT_WIN_PRESSED;
	  break;
	case VK_RWIN:
	  mod_key_state &= ~RIGHT_WIN_PRESSED;
	  break;
	case VK_APPS:
	  mod_key_state &= ~APPS_PRESSED;
	  break;
	}
      return 0;
    }

  /* Ignore keystrokes we fake ourself; see below.  */
  if (faked_key == event->wVirtualKeyCode)
    {
      faked_key = 0;
      return 0;
    }

  /* To make it easier to debug this code, ignore modifier keys!  */
  switch (event->wVirtualKeyCode)
    {
    case VK_LWIN:
      if (NILP (Vw32_pass_lwindow_to_system))
	{
	  /* Prevent system from acting on keyup (which opens the Start
	     menu if no other key was pressed) by simulating a press of
	     Space which we will ignore.  */
	  if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
	    {
	      if (NUMBERP (Vw32_phantom_key_code))
		faked_key = XUINT (Vw32_phantom_key_code) & 255;
	      else
		faked_key = VK_SPACE;
	      keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
	    }
	}
      mod_key_state |= LEFT_WIN_PRESSED;
      if (!NILP (Vw32_lwindow_modifier))
	return 0;
      break;
    case VK_RWIN:
      if (NILP (Vw32_pass_rwindow_to_system))
	{
	  if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
	    {
	      if (NUMBERP (Vw32_phantom_key_code))
		faked_key = XUINT (Vw32_phantom_key_code) & 255;
	      else
		faked_key = VK_SPACE;
	      keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
	    }
	}
      mod_key_state |= RIGHT_WIN_PRESSED;
      if (!NILP (Vw32_rwindow_modifier))
	return 0;
      break;
    case VK_APPS:
      mod_key_state |= APPS_PRESSED;
      if (!NILP (Vw32_apps_modifier))
	return 0;
      break;
    case VK_CAPITAL:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_enable_caps_lock))
	goto disable_lock_key;
      return 0;
    case VK_NUMLOCK:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_enable_num_lock))
	goto disable_lock_key;
      return 0;
    case VK_SCROLL:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_scroll_lock_modifier))
	goto disable_lock_key;
      return 0;
    disable_lock_key:
      /* Ensure the appropriate lock key state is off (and the
	 indicator light as well).  */
      wParam = event->wVirtualKeyCode;
      if (GetAsyncKeyState (wParam) & 0x8000)
	{
	  /* Fake another press of the relevant key.  Apparently, this
	     really is the only way to turn off the indicator.  */
	  faked_key = wParam;
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | 0, 0);
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
	}
      break;
    case VK_MENU:
    case VK_CONTROL:
    case VK_SHIFT:
      return 0;
    case VK_CANCEL:
      /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
	 which is confusing for purposes of key binding; convert
	 VK_CANCEL events into VK_PAUSE events.  */
      event->wVirtualKeyCode = VK_PAUSE;
      break;
    case VK_PAUSE:
      /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
	 for purposes of key binding; convert these back into
	 VK_NUMLOCK events, at least when we want to see NumLock key
	 presses.  (Note that there is never any possibility that
	 VK_PAUSE with Ctrl really is C-Pause as per above.)  */
      if (NILP (Vw32_enable_num_lock)
	  && (event->dwControlKeyState
	      & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
	event->wVirtualKeyCode = VK_NUMLOCK;
      break;
    }

  /* Recognize state of Windows and Apps keys.  */
  event->dwControlKeyState |= mod_key_state;

  /* Distinguish numeric keypad keys from extended keys.  */
  event->wVirtualKeyCode =
    map_keypad_keys (event->wVirtualKeyCode,
		     (event->dwControlKeyState & ENHANCED_KEY));

  if (lispy_function_keys[event->wVirtualKeyCode] == 0)
    {
      if (!NILP (Vw32_recognize_altgr)
	  && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
	  && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
	{
	  /* Don't try to interpret AltGr key chords; ToAscii seems not
	     to process them correctly.  */
	}
      /* Handle key chords including any modifiers other than shift
         directly, in order to preserve as much modifier information as
         possible.  */
      else if (event->dwControlKeyState
	       & (  RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
		  | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
		  | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
		  | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
		  | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
		  | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
	{
	  /* Don't translate modified alphabetic keystrokes, so the user
	     doesn't need to constantly switch layout to type control or
	     meta keystrokes when the normal layout translates
	     alphabetic characters to non-ascii characters.  */
	  if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
	    {
	      event->uChar.AsciiChar = event->wVirtualKeyCode;
	      if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
		event->uChar.AsciiChar += ('a' - 'A');
	    }
	  /* Try to handle unrecognized keystrokes by determining the
             base character (ie. translating the base key plus shift
             modifier).  */
	  else if (event->uChar.AsciiChar == 0)
	    w32_kbd_patch_key (event, -1);
	}

      if (event->uChar.AsciiChar == 0)
	{
	  emacs_ev->kind = NO_EVENT;
	  return 0;
	}
      else if (event->uChar.AsciiChar > 0)
	{
	  /* Pure ASCII characters < 128.  */
	  emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
	  emacs_ev->code = event->uChar.AsciiChar;
	}
      else if (event->uChar.UnicodeChar > 0
	       && w32_console_unicode_input)
	{
	  /* Unicode codepoint; only valid if we are using Unicode
	     console input mode.  */
	  emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
	  emacs_ev->code = event->uChar.UnicodeChar;
	}
      else
	{
	  /* Fallback handling of non-ASCII characters for non-Unicode
	     versions of Windows, and for non-Unicode input on NT
	     family of Windows.  Only characters in the current
	     console codepage are supported by this fallback.  */
	  wchar_t code;
	  char dbcs[2];
          int cpId;

	  /* Get the current console input codepage to interpret this
	     key with.  Note that the system defaults for the OEM
	     codepage could have been changed by calling SetConsoleCP
	     or w32-set-console-codepage, so using GetLocaleInfo to
	     get LOCALE_IDEFAULTCODEPAGE is not TRT here.  */
          cpId = GetConsoleCP ();

	  dbcs[0] = dbcs_lead;
	  dbcs[1] = event->uChar.AsciiChar;
	  if (dbcs_lead)
	    {
	      dbcs_lead = 0;
	      if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1))
		{
		  /* Garbage  */
		  DebPrint (("Invalid DBCS sequence: %d %d\n",
			     dbcs[0], dbcs[1]));
		  emacs_ev->kind = NO_EVENT;
		}
	    }
	  else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
	    {
	      dbcs_lead = dbcs[1];
	      emacs_ev->kind = NO_EVENT;
	    }
	  else
	    {
	      if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1))
		{
		  /* Garbage  */
		  DebPrint (("Invalid character: %d\n", dbcs[1]));
		  emacs_ev->kind = NO_EVENT;
		}
	    }
	  emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
	  emacs_ev->code = code;
	}
    }
  else
    {
      /* Function keys and other non-character keys.  */
      emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
      emacs_ev->code = event->wVirtualKeyCode;
    }

  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
					       event->wVirtualKeyCode);
  emacs_ev->timestamp = GetTickCount ();
  return 1;
}
Beispiel #10
0
static int
do_mouse_event (MOUSE_EVENT_RECORD *event,
		struct input_event *emacs_ev)
{
  static DWORD button_state = 0;
  static Lisp_Object last_mouse_window;
  DWORD but_change, mask, flags = event->dwEventFlags;
  int i;

  switch (flags)
    {
    case MOUSE_MOVED:
      {
	struct frame *f = get_frame ();
	Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
	int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;

	mouse_moved_to (mx, my);

	if (f->mouse_moved)
	  {
	    if (hlinfo->mouse_face_hidden)
	      {
		hlinfo->mouse_face_hidden = 0;
		clear_mouse_face (hlinfo);
	      }

	    /* Generate SELECT_WINDOW_EVENTs when needed.  */
	    if (!NILP (Vmouse_autoselect_window))
	      {
		Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
								    0, 0);
		/* A window will be selected only when it is not
		   selected now, and the last mouse movement event was
		   not in it.  A minibuffer window will be selected iff
		   it is active.  */
		if (WINDOWP (mouse_window)
		    && !EQ (mouse_window, last_mouse_window)
		    && !EQ (mouse_window, selected_window))
		  {
		    struct input_event event;

		    EVENT_INIT (event);
		    event.kind = SELECT_WINDOW_EVENT;
		    event.frame_or_window = mouse_window;
		    event.arg = Qnil;
		    event.timestamp = movement_time;
		    kbd_buffer_store_event (&event);
		  }
		last_mouse_window = mouse_window;
	      }
	    else
	      last_mouse_window = Qnil;

	    previous_help_echo_string = help_echo_string;
	    help_echo_string = help_echo_object = help_echo_window = Qnil;
	    help_echo_pos = -1;
	    note_mouse_highlight (f, mx, my);
	    /* If the contents of the global variable help_echo has
	       changed (inside note_mouse_highlight), generate a HELP_EVENT.  */
	    if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
	      gen_help_event (help_echo_string, selected_frame,
			      help_echo_window, help_echo_object,
			      help_echo_pos);
	  }
	/* We already called kbd_buffer_store_event, so indicate the
	   the caller it shouldn't.  */
	return 0;
      }
    case MOUSE_WHEELED:
    case MOUSE_HWHEELED:
      {
	struct frame *f = get_frame ();
	int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
	bool down_p = (event->dwButtonState & 0x10000000) != 0;

	emacs_ev->kind =
	  flags == MOUSE_HWHEELED ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
	emacs_ev->code = 0;
	emacs_ev->modifiers = down_p ? down_modifier : up_modifier;
	emacs_ev->modifiers |=
	  w32_kbd_mods_to_emacs (event->dwControlKeyState, 0);
	XSETINT (emacs_ev->x, mx);
	XSETINT (emacs_ev->y, my);
	XSETFRAME (emacs_ev->frame_or_window, f);
	emacs_ev->arg = Qnil;
	emacs_ev->timestamp = GetTickCount ();
	return 1;
      }
    case DOUBLE_CLICK:
    default:	/* mouse pressed or released */
      /* It looks like the console code sends us a button-release
	 mouse event with dwButtonState == 0 when a window is
	 activated and when the mouse is first clicked.  Ignore this
	 case.  */
      if (event->dwButtonState == button_state)
	return 0;

      emacs_ev->kind = MOUSE_CLICK_EVENT;

      /* Find out what button has changed state since the last button
	 event.  */
      but_change = button_state ^ event->dwButtonState;
      mask = 1;
      for (i = 0; mask; i++, mask <<= 1)
	if (but_change & mask)
	  {
	    if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
	      emacs_ev->code = emacs_button_translation[i];
	    else
	      emacs_ev->code = i;
	    break;
	  }

      button_state = event->dwButtonState;
      emacs_ev->modifiers =
	w32_kbd_mods_to_emacs (event->dwControlKeyState, 0)
	| ((event->dwButtonState & mask) ? down_modifier : up_modifier);

      XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
      XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
      XSETFRAME (emacs_ev->frame_or_window, get_frame ());
      emacs_ev->arg = Qnil;
      emacs_ev->timestamp = GetTickCount ();

      return 1;
    }
}
Beispiel #11
0
void
set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
{
  HMENU menubar_widget = f->output_data.w32->menubar_widget;
  Lisp_Object items;
  widget_value *wv, *first_wv, *prev_wv = 0;
  int i, last_i;
  int *submenu_start, *submenu_end;
  int *submenu_top_level_items, *submenu_n_panes;

  /* We must not change the menubar when actually in use.  */
  if (f->output_data.w32->menubar_active)
    return;

  XSETFRAME (Vmenu_updating_frame, f);

  if (! menubar_widget)
    deep_p = true;

  if (deep_p)
    {
      /* Make a widget-value tree representing the entire menu trees.  */

      struct buffer *prev = current_buffer;
      Lisp_Object buffer;
      ptrdiff_t specpdl_count = SPECPDL_INDEX ();
      int previous_menu_items_used = f->menu_bar_items_used;
      Lisp_Object *previous_items
	= (Lisp_Object *) alloca (previous_menu_items_used
				  * word_size);

      /* If we are making a new widget, its contents are empty,
	 do always reinitialize them.  */
      if (! menubar_widget)
	previous_menu_items_used = 0;

      buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
      specbind (Qinhibit_quit, Qt);
      /* Don't let the debugger step into this code
	 because it is not reentrant.  */
      specbind (Qdebug_on_next_call, Qnil);

      record_unwind_save_match_data ();

      if (NILP (Voverriding_local_map_menu_flag))
	{
	  specbind (Qoverriding_terminal_local_map, Qnil);
	  specbind (Qoverriding_local_map, Qnil);
	}

      set_buffer_internal_1 (XBUFFER (buffer));

      /* Run the hooks.  */
      safe_run_hooks (Qactivate_menubar_hook);
      safe_run_hooks (Qmenu_bar_update_hook);
      fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));

      items = FRAME_MENU_BAR_ITEMS (f);

      /* Save the frame's previous menu bar contents data.  */
      if (previous_menu_items_used)
	memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
		previous_menu_items_used * word_size);

      /* Fill in menu_items with the current menu bar contents.
	 This can evaluate Lisp code.  */
      save_menu_items ();

      menu_items = f->menu_bar_vector;
      menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
      submenu_start = (int *) alloca (ASIZE (items) * sizeof (int));
      submenu_end = (int *) alloca (ASIZE (items) * sizeof (int));
      submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int));
      submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int));
      init_menu_items ();
      for (i = 0; i < ASIZE (items); i += 4)
	{
	  Lisp_Object key, string, maps;

	  last_i = i;

	  key = AREF (items, i);
	  string = AREF (items, i + 1);
	  maps = AREF (items, i + 2);
	  if (NILP (string))
	    break;

	  submenu_start[i] = menu_items_used;

	  menu_items_n_panes = 0;
	  submenu_top_level_items[i]
	    = parse_single_submenu (key, string, maps);
	  submenu_n_panes[i] = menu_items_n_panes;

	  submenu_end[i] = menu_items_used;
	}

      finish_menu_items ();

      /* Convert menu_items into widget_value trees
	 to display the menu.  This cannot evaluate Lisp code.  */

      wv = make_widget_value ("menubar", NULL, true, Qnil);
      wv->button_type = BUTTON_TYPE_NONE;
      first_wv = wv;

      for (i = 0; i < last_i; i += 4)
	{
	  menu_items_n_panes = submenu_n_panes[i];
	  wv = digest_single_submenu (submenu_start[i], submenu_end[i],
				      submenu_top_level_items[i]);
	  if (prev_wv)
	    prev_wv->next = wv;
	  else
	    first_wv->contents = wv;
	  /* Don't set wv->name here; GC during the loop might relocate it.  */
	  wv->enabled = true;
	  wv->button_type = BUTTON_TYPE_NONE;
	  prev_wv = wv;
	}

      set_buffer_internal_1 (prev);

      /* If there has been no change in the Lisp-level contents
	 of the menu bar, skip redisplaying it.  Just exit.  */

      for (i = 0; i < previous_menu_items_used; i++)
	if (menu_items_used == i
	    || (!EQ (previous_items[i], AREF (menu_items, i))))
	  break;
      if (i == menu_items_used && i == previous_menu_items_used && i != 0)
	{
	  free_menubar_widget_value_tree (first_wv);
	  discard_menu_items ();
          unbind_to (specpdl_count, Qnil);
	  return;
	}

      fset_menu_bar_vector (f, menu_items);
      f->menu_bar_items_used = menu_items_used;

      /* This undoes save_menu_items.  */
      unbind_to (specpdl_count, Qnil);

      /* Now GC cannot happen during the lifetime of the widget_value,
	 so it's safe to store data from a Lisp_String, as long as
	 local copies are made when the actual menu is created.
	 Windows takes care of this for normal string items, but
	 not for owner-drawn items or additional item-info.  */
      wv = first_wv->contents;
      for (i = 0; i < ASIZE (items); i += 4)
	{
	  Lisp_Object string;
	  string = AREF (items, i + 1);
	  if (NILP (string))
	    break;
	  wv->name = SSDATA (string);
	  update_submenu_strings (wv->contents);
	  wv = wv->next;
	}
    }
  else
    {
      /* Make a widget-value tree containing
	 just the top level menu bar strings.  */

      wv = make_widget_value ("menubar", NULL, true, Qnil);
      wv->button_type = BUTTON_TYPE_NONE;
      first_wv = wv;

      items = FRAME_MENU_BAR_ITEMS (f);
      for (i = 0; i < ASIZE (items); i += 4)
	{
	  Lisp_Object string;

	  string = AREF (items, i + 1);
	  if (NILP (string))
	    break;

	  wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
	  wv->button_type = BUTTON_TYPE_NONE;
	  /* This prevents lwlib from assuming this
	     menu item is really supposed to be empty.  */
	  /* The EMACS_INT cast avoids a warning.
	     This value just has to be different from small integers.  */
	  wv->call_data = (void *) (EMACS_INT) (-1);

	  if (prev_wv)
	    prev_wv->next = wv;
	  else
	    first_wv->contents = wv;
	  prev_wv = wv;
	}

      /* Forget what we thought we knew about what is in the
	 detailed contents of the menu bar menus.
	 Changing the top level always destroys the contents.  */
      f->menu_bar_items_used = 0;
    }

  /* Create or update the menu bar widget.  */

  block_input ();

  if (menubar_widget)
    {
      /* Empty current menubar, rather than creating a fresh one.  */
      while (DeleteMenu (menubar_widget, 0, MF_BYPOSITION))
	;
    }
  else
    {
      menubar_widget = CreateMenu ();
    }
  fill_in_menu (menubar_widget, first_wv->contents);

  free_menubar_widget_value_tree (first_wv);

  {
    HMENU old_widget = f->output_data.w32->menubar_widget;

    f->output_data.w32->menubar_widget = menubar_widget;
    SetMenu (FRAME_W32_WINDOW (f), f->output_data.w32->menubar_widget);
    /* Causes flicker when menu bar is updated
    DrawMenuBar (FRAME_W32_WINDOW (f)); */

    /* Force the window size to be recomputed so that the frame's text
       area remains the same, if menubar has just been created.  */
    if (old_widget == NULL)
      {
	windows_or_buffers_changed = 23;
	adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
      }
  }

  unblock_input ();
}
Beispiel #12
0
void
menubar_selection_callback (struct frame *f, void * client_data)
{
  Lisp_Object prefix, entry;
  Lisp_Object vector;
  Lisp_Object *subprefix_stack;
  int submenu_depth = 0;
  int i;

  if (!f)
    return;
  entry = Qnil;
  subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
  vector = f->menu_bar_vector;
  prefix = Qnil;
  i = 0;
  while (i < f->menu_bar_items_used)
    {
      if (EQ (AREF (vector, i), Qnil))
	{
	  subprefix_stack[submenu_depth++] = prefix;
	  prefix = entry;
	  i++;
	}
      else if (EQ (AREF (vector, i), Qlambda))
	{
	  prefix = subprefix_stack[--submenu_depth];
	  i++;
	}
      else if (EQ (AREF (vector, i), Qt))
	{
	  prefix = AREF (vector, i + MENU_ITEMS_PANE_PREFIX);
	  i += MENU_ITEMS_PANE_LENGTH;
	}
      else
	{
	  entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
	  /* The UINT_PTR cast avoids a warning.  There's no problem
	     as long as pointers have enough bits to hold small integers.  */
	  if ((int) (UINT_PTR) client_data == i)
	    {
	      int j;
	      struct input_event buf;
	      Lisp_Object frame;
	      EVENT_INIT (buf);

	      XSETFRAME (frame, f);
	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = frame;
	      kbd_buffer_store_event (&buf);

	      for (j = 0; j < submenu_depth; j++)
		if (!NILP (subprefix_stack[j]))
		  {
		    buf.kind = MENU_BAR_EVENT;
		    buf.frame_or_window = frame;
		    buf.arg = subprefix_stack[j];
		    kbd_buffer_store_event (&buf);
		  }

	      if (!NILP (prefix))
		{
		  buf.kind = MENU_BAR_EVENT;
		  buf.frame_or_window = frame;
		  buf.arg = prefix;
		  kbd_buffer_store_event (&buf);
		}

	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = entry;
	      /* Free memory used by owner-drawn and help-echo strings.  */
	      w32_free_menu_strings (FRAME_W32_WINDOW (f));
	      kbd_buffer_store_event (&buf);

	      f->output_data.w32->menubar_active = 0;
	      return;
	    }
	  i += MENU_ITEMS_ITEM_LENGTH;
	}
    }
  /* Free memory used by owner-drawn and help-echo strings.  */
  w32_free_menu_strings (FRAME_W32_WINDOW (f));
  f->output_data.w32->menubar_active = 0;
}
Beispiel #13
0
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);
}
Beispiel #14
0
void
find_and_call_menu_selection (FRAME_PTR f, int menu_bar_items_used, Lisp_Object vector, void *client_data)
{
  Lisp_Object prefix, entry;
  Lisp_Object *subprefix_stack;
  int submenu_depth = 0;
  int i;

  entry = Qnil;
  subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
  prefix = Qnil;
  i = 0;

  while (i < menu_bar_items_used)
    {
      if (EQ (XVECTOR (vector)->contents[i], Qnil))
	{
	  subprefix_stack[submenu_depth++] = prefix;
	  prefix = entry;
	  i++;
	}
      else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
	{
	  prefix = subprefix_stack[--submenu_depth];
	  i++;
	}
      else if (EQ (XVECTOR (vector)->contents[i], Qt))
	{
	  prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
	  i += MENU_ITEMS_PANE_LENGTH;
	}
      else
	{
	  entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
	  /* The EMACS_INT cast avoids a warning.  There's no problem
	     as long as pointers have enough bits to hold small integers.  */
	  if ((int) (EMACS_INT) client_data == i)
	    {
	      int j;
	      struct input_event buf;
	      Lisp_Object frame;
	      EVENT_INIT (buf);

	      XSETFRAME (frame, f);
	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = frame;
	      kbd_buffer_store_event (&buf);

	      for (j = 0; j < submenu_depth; j++)
		if (!NILP (subprefix_stack[j]))
		  {
		    buf.kind = MENU_BAR_EVENT;
		    buf.frame_or_window = frame;
		    buf.arg = subprefix_stack[j];
		    kbd_buffer_store_event (&buf);
		  }

	      if (!NILP (prefix))
		{
		  buf.kind = MENU_BAR_EVENT;
		  buf.frame_or_window = frame;
		  buf.arg = prefix;
		  kbd_buffer_store_event (&buf);
		}

	      buf.kind = MENU_BAR_EVENT;
	      buf.frame_or_window = frame;
	      buf.arg = entry;
	      kbd_buffer_store_event (&buf);

	      return;
	    }
	  i += MENU_ITEMS_ITEM_LENGTH;
	}
    }
}
Beispiel #15
0
static void
gtk_output_toolbar_button (struct frame *f, Lisp_Object button)
{
  int shadow_thickness = 2;
  int x_adj, y_adj, width_adj, height_adj;
  GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
  GdkGC *background_gc = get_toolbar_gc (f);
  Lisp_Object instance, frame, window, glyph;
  struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
  struct Lisp_Image_Instance *p;
  struct window *w;
  int vertical = tb->vertical;
  int border_width = tb->border_width;

  if (vertical)
    {
      x_adj = border_width;
      width_adj = - 2 * border_width;
      y_adj = 0;
      height_adj = 0;
    }
  else
    {
      x_adj = 0;
      width_adj = 0;
      y_adj = border_width;
      height_adj = - 2 * border_width;
    }

  XSETFRAME (frame, f);
  window = FRAME_LAST_NONMINIBUF_WINDOW (f);
  w = XWINDOW (window);

  glyph = get_toolbar_button_glyph (w, tb);

  if (tb->enabled)
    {
      if (tb->down)
	{
	  shadow_thickness = -2;
	}
      else
	{
	  shadow_thickness = 2;
	}
    }
  else
    {
      shadow_thickness = 0;
    }

  background_gc = get_toolbar_gc (f);

  /* Clear the entire area. */
  gdk_draw_rectangle (x_win, background_gc, TRUE,
		      tb->x + x_adj,
		      tb->y + y_adj,
		      tb->width + width_adj,
		      tb->height + height_adj);

  /* Draw the outline. */
  if (shadow_thickness)
    gtk_output_shadows (f, tb->x + x_adj, tb->y + y_adj,
			tb->width + width_adj, tb->height + height_adj,
			shadow_thickness);

  /* Do the border. */
  gdk_draw_rectangle (x_win, background_gc, TRUE, tb->x, tb->y,
		      (vertical ? border_width : tb->width),
		      (vertical ? tb->height : border_width));

  gdk_draw_rectangle (x_win, background_gc, TRUE,
		      (vertical ? tb->x + tb->width - border_width : tb->x),
		      (vertical ? tb->y : tb->y + tb->height - border_width),
		      (vertical ? border_width : tb->width),
		      (vertical ? tb->height : border_width));

  background_gc = get_toolbar_gc (f);

  /* #### It is currently possible for users to trash us by directly
     changing the toolbar glyphs.  Avoid crashing in that case. */
  if (GLYPHP (glyph))
    instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
  else
    instance = Qnil;

  if (IMAGE_INSTANCEP (instance))
    {
      int width = tb->width + width_adj - shadow_thickness * 2;
      int height = tb->height + height_adj - shadow_thickness * 2;
      int x_offset = x_adj + shadow_thickness;
      int y_offset = y_adj + shadow_thickness;

      p = XIMAGE_INSTANCE (instance);

      if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
	{
	  if (width > (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p))
	    {
	      x_offset += ((int) (width - IMAGE_INSTANCE_PIXMAP_WIDTH (p))
			   / 2);
	      width = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
	    }
	  if (height > (int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
	    {
	      y_offset += ((int) (height - IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
			   / 2);
	      height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
	    }

	  gtk_output_gdk_pixmap (f, XIMAGE_INSTANCE (instance), tb->x + x_offset,
				 tb->y + y_offset, 0, 0, 0, 0, width, height,
				 0, 0, 0, background_gc);
	}
      else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_TEXT)
	{
	  /* #### We need to make the face used configurable. */
	  struct face_cachel *cachel =
	    WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
	  struct display_line dl;
	  Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING (p);
	  unsigned char charsets[NUM_LEADING_BYTES];
	  Emchar_dynarr *buf;
	  struct font_metric_info fm;

	  /* This could be true if we were called via the Expose event
             handler.  Mark the button as dirty and return
             immediately. */
	  if (f->window_face_cache_reset)
	    {
	      tb->dirty = 1;
	      MARK_TOOLBAR_CHANGED;
	      return;
	    }
	  buf = Dynarr_new (Emchar);
	  convert_bufbyte_string_into_emchar_dynarr
	    (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
	  find_charsets_in_emchar_string (charsets, Dynarr_atp (buf, 0),
					  Dynarr_length (buf));
	  ensure_face_cachel_complete (cachel, window, charsets);
	  face_cachel_charset_font_metric_info (cachel, charsets, &fm);

	  dl.ascent = fm.ascent;
	  dl.descent = fm.descent;
	  dl.ypos = tb->y + y_offset + fm.ascent;

	  if (fm.ascent + fm.descent <= height)
	    {
	      dl.ypos += (height - fm.ascent - fm.descent) / 2;
	      dl.clip = 0;
	    }
	  else
	    {
	      dl.clip = fm.ascent + fm.descent - height;
	    }

	  gtk_output_string (w, &dl, buf, tb->x + x_offset, 0, 0, width,
			     DEFAULT_INDEX, 0, 0, 0, 0);
	  Dynarr_free (buf);
	}

      /* We silently ignore the image if it isn't a pixmap or text. */
    }

  tb->dirty = 0;
}
Beispiel #16
0
static void
gtk_output_toolbar (struct frame *f, enum toolbar_pos pos)
{
  int x, y, bar_width, bar_height, vert;
  int max_pixpos, right_size, right_start, blank_size;
  int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
  Lisp_Object button, window;
  GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
  GdkGC *background_gc = get_toolbar_gc (f);

  get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
  window = FRAME_LAST_NONMINIBUF_WINDOW (f);

  /* Do the border */
  gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
		      (vert ? bar_width : border_width),
		      (vert ? border_width : bar_height));
  gdk_draw_rectangle (x_win, background_gc, TRUE,
		      (vert ? x : x + bar_width - border_width),
		      (vert ? y + bar_height - border_width : y),
		      (vert ? bar_width : border_width),
		      (vert ? border_width : bar_height));

  if (vert)
    {
      max_pixpos = y + bar_height - border_width;
      y += border_width;
    }
  else
    {
      max_pixpos = x + bar_width - border_width;
      x += border_width;
    }

  button = FRAME_TOOLBAR_BUTTONS (f, pos);
  right_size = 0;

  /* First loop over all of the buttons to determine how much room we
     need for left hand and right hand buttons.  This loop will also
     make sure that all instances are instantiated so when we actually
     output them they will come up immediately. */
  while (!NILP (button))
    {
      struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
      int size = gtk_get_button_size (f, window, tb, vert, pos);

      if (tb->pushright)
	right_size += size;

      button = tb->next;
    }

  button = FRAME_TOOLBAR_BUTTONS (f, pos);

  /* Loop over the left buttons, updating and outputting them. */
  GTK_OUTPUT_BUTTONS_LOOP (1);

  /* Now determine where the right buttons start. */
  right_start = max_pixpos - right_size;
  if (right_start < (vert ? y : x))
    right_start = (vert ? y : x);

  /* Output the blank which goes from the end of the left buttons to
     the start of the right. */
  blank_size = right_start - (vert ? y : x);
  if (blank_size)
    {
      int height, width;

      if (vert)
	{
	  width = bar_width;
	  height = blank_size;
	}
      else
	{
	  width = blank_size;
	  height = bar_height;
	}

      /*
       * Use a 3D pushright separator only if there isn't a toolbar
       * border.  A flat separator meshes with the border and looks
       * better.
       */
      gtk_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
				     border_width, vert);

      if (vert)
	y += height;
      else
	x += width;
    }

  /* Loop over the right buttons, updating and outputting them. */
  GTK_OUTPUT_BUTTONS_LOOP (0);

  if (!vert)
    {
      Lisp_Object frame;

      XSETFRAME (frame, f);
      redisplay_clear_region (frame,
			      DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
			      bar_height);
    }

  SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);

  gdk_flush ();
}