view lwlib/lwlib-utils.c @ 107648:babfb0a156a1

Initial support for bidirectional editing. Makefile.in (obj): Include bidi.o. (bidi.o): New target. makefile.w32-in (OBJ1): Add $(BLD)/bidi.$(O). ($(BLD)/bidi.$(O)): New target. bidi.c: New file. buffer.h (struct buffer): New members bidi_display_reordering and bidi_paragraph_direction. buffer.c (init_buffer_once): Initialize bidi_display_reordering and bidi_paragraph_direction. (syms_of_buffer): Declare Lisp variables bidi-display-reordering and bidi-paragraph-direction. (Fbuffer_swap_text): Swap the values of bidi_display_reordering and bidi_paragraph_direction. dispextern.h (BIDI_MAXLEVEL, BIDI_AT_BASE_LEVEL): New macros. (bidi_type_t, bidi_dir_t): New types. (bidi_saved_info, bidi_stack, bidi_it): New structures. (struct it): New members bidi_p, bidi_it, paragraph_embedding, prev_stop, base_level_stop, and eol_pos. (bidi_init_it, bidi_get_next_char_visually): New prototypes. (IT_STACK_SIZE): Enlarge to 5. (struct glyph_row): New member reversed_p. <string_buffer_position>: Update prototype. (PRODUCE_GLYPHS): Set the reversed_p flag in the iterator's glyph_row if bidi_it.paragraph_dir == R2L. (struct glyph): New members resolved_level and bidi_type. dispnew.c (direct_output_forward_char): Give up if we need bidi processing or buffer's direction is right-to-left. (prepare_desired_row): Preserve the reversed_p flag. (row_equal_p): Compare the reversed_p attributes as well. xdisp.c (init_iterator): Initialize it->bidi_p. Call bidi_init_it and set it->paragraph_embedding from the current buffer's value of bidi_paragraph_direction. (reseat_1): Initialize bidi_it.first_elt. (set_iterator_to_next, next_element_from_buffer): Use the value of paragraph_embedding to determine the paragraph direction. (set_iterator_to_next): Under bidi reordering, call bidi_get_next_char_visually. Call bidi_paragraph_init if the new_paragraph flag is set in the bidi iterator. (next_element_from_buffer): If bidi_it.first_elt is set, initialize paragraph direction and find the first character to display in the visual order. If reseated to a middle of a line, prime the bidi iterator starting at the line's beginning. Handle the situation where we overstepped stop_charpos due to non-linearity of the bidi iteration. Likewise for when we back up beyond the previous stop_charpos. When moving across stop_charpos, record it in prev_stop. (display_line): Set row->end and it->start for the next row to the next character in logical order. Always extend reversed_p rows to the end of line, even if they end at ZV. Copy the reversed_p flag to the next glyph row. Keep calling set_cursor_from_row for bidi-reordered rows even if we already have a possible candidate for cursor position. Set row_end after all the row's glyphs have been produced, by looping over the glyphs. Record the position after EOL in it->eol_pos, and use it to set end_pos of the last row produced for a continued line. <Qright_to_left, Qleft_to_right>: New variables. (syms_of_xdisp): Initialize and staticpro them. (string_buffer_position_lim): New function. (string_buffer_position): Most of code moved to string_buffer_position_lim. Last argument and return value are now EMACS_INT; all callers changed. (set_cursor_from_row): Rewritten to support bidirectional text and reversed glyph rows. (text_outside_line_unchanged_p, try_window_id): Disable optimizations if we are reordering bidirectional text and the paragraph direction can be affected by the change. (append_glyph, append_composite_glyph) (produce_image_glyph, append_stretch_glyph): Set the resolved_level and bidi_type members of each glyph. (append_glyph): If the glyph row is reversed, prepend the glyph rather than appending it. (handle_stop_backwards): New function. (reseat_1, pop_it, push_it): Set prev_stop and base_level_stop. (reseat): call handle_stop_backwards to recompute prev_stop and base_level_stop for the new position. (handle_invisible_prop): Under bidi iteration, skip invisible text using bidi_get_next_char_visually. If we are `reseat'ed, init the paragraph direction. Update IT->prev_stop after skipping invisible text. (move_it_in_display_line_to): New variables prev_method and prev_pos. Compare for strict equality in BUFFER_POS_REACHED_P. (try_cursor_movement): Examine all the candidate rows that occlude point, to return the best match. If rows are bidi-reordered and point moved backwards, back up to the row that is not a continuation line, and start looking for a suitable row from there. term.c (append_glyph): Reverse glyphs by pre-pending them, rather than appending, if the glyph_row's reversed_p flag is set. Set the resolved_level and bidi_type members of each glyph. .gdbinit (pbiditype): New command. (pgx): Use it to display bidi level and type of the glyph. (pitx): Display some bidi information about the iterator. (prowlims, pmtxrows): New commands. files.el: Make bidi-display-reordering safe variable for boolean values. mule.texi (International): Mention support of bidirectional editing. (Bidirectional Editing): New section. HELLO: Reorder Arabic and Hebrew into logical order, and insert RLM before the opening paren, to make the display more reasonable. Add setting for bidi-display-reordering in the local variables section. NEWS: Mention initial support for bidirectional editing.
author Eli Zaretskii <eliz@gnu.org>
date Tue, 30 Mar 2010 05:13:07 -0400
parents 1d1d5d9bd884
children 384b3408c143 376148b31b5e
line wrap: on
line source

/* Defines some widget utility functions.
Copyright (C) 1992 Lucid, Inc.
Copyright (C) 1994, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
  2010 Free Software Foundation, Inc.

This file is part of the Lucid Widget Library.

The Lucid Widget Library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

The Lucid Widget Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.  */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* Definitions of these in config.h can cause
   declaration conflicts later on between declarations for index
   and declarations for strchr.  This file doesn't use
   index and rindex, so cancel them.  */
#undef index
#undef rindex

#include <setjmp.h>
#include "../src/lisp.h"

#include <X11/Xatom.h>
#include <X11/IntrinsicP.h>
#include <X11/ObjectP.h>
#include "lwlib-utils.h"
#include "lwlib.h"

/* Redisplay the contents of the widget, without first clearing it. */
void
XtNoClearRefreshWidget (widget)
     Widget widget;
{
  XEvent event;

  event.type = Expose;
  event.xexpose.serial = 0;
  event.xexpose.send_event = 0;
  event.xexpose.display = XtDisplay (widget);
  event.xexpose.window = XtWindow (widget);
  event.xexpose.x = 0;
  event.xexpose.y = 0;
  event.xexpose.width = widget->core.width;
  event.xexpose.height = widget->core.height;
  event.xexpose.count = 0;

  (*widget->core.widget_class->core_class.expose)
    (widget, &event, (Region)NULL);
}


/*
 * Apply a function to all the subwidgets of a given widget recursively.
*/
void
XtApplyToWidgets (w, proc, arg)
     Widget w;
     XtApplyToWidgetsProc proc;
     XtPointer arg;
{
  if (XtIsComposite (w))
    {
      CompositeWidget cw = (CompositeWidget) w;
      /* We have to copy the children list before mapping over it, because
	 the procedure might add/delete elements, which would lose badly.
	 */
      int nkids = cw->composite.num_children;
      Widget *kids = (Widget *) malloc (sizeof (Widget) * nkids);
      int i;
      lwlib_bcopy ((char *) cw->composite.children, (char *) kids,
		   sizeof (Widget) * nkids);
      for (i = 0; i < nkids; i++)
/* This prevent us from using gadgets, why is it here? */
/*	if (XtIsWidget (kids [i])) */
	  {
	    /* do the kiddies first in case we're destroying */
	    XtApplyToWidgets (kids [i], proc, arg);
	    proc (kids [i], arg);
	  }
      free (kids);
    }
}


/*
 * Apply a function to all the subwidgets of a given widget recursively.
 * Stop as soon as the function returns non NULL and returns this as a value.
 */
void *
XtApplyUntilToWidgets (w, proc, arg)
     Widget w;
     XtApplyUntilToWidgetsProc proc;
     XtPointer arg;
{
  void* result;
  if (XtIsComposite (w))
    {
      CompositeWidget cw = (CompositeWidget)w;
      int i;
      for (i = 0; i < cw->composite.num_children; i++)
	if (XtIsWidget (cw->composite.children [i])){
	  result = proc (cw->composite.children [i], arg);
	  if (result)
	    return result;
	  result = XtApplyUntilToWidgets (cw->composite.children [i], proc,
					  arg);
	  if (result)
	    return result;
	}
    }
  return NULL;
}


/*
 * Returns a copy of the list of all children of a composite widget
 */
Widget *
XtCompositeChildren (widget, number)
     Widget widget;
     unsigned int* number;
{
  CompositeWidget cw = (CompositeWidget)widget;
  Widget* result;
  int n;
  int i;

  if (!XtIsComposite (widget))
    {
      *number = 0;
      return NULL;
    }
  n = cw->composite.num_children;
  result = (Widget*)XtMalloc (n * sizeof (Widget));
  *number = n;
  for (i = 0; i < n; i++)
    result [i] = cw->composite.children [i];
  return result;
}

Boolean
XtWidgetBeingDestroyedP (widget)
     Widget widget;
{
  return widget->core.being_destroyed;
}

void
XtSafelyDestroyWidget (widget)
     Widget widget;
{
#if 0

  /* this requires IntrinsicI.h (actually, InitialI.h) */

  XtAppContext app = XtWidgetToApplicationContext(widget);

  if (app->dispatch_level == 0)
    {
      app->dispatch_level = 1;
      XtDestroyWidget (widget);
      /* generates an event so that the event loop will be called */
      XChangeProperty (XtDisplay (widget), XtWindow (widget),
		       XA_STRING, XA_STRING, 32, PropModeAppend, NULL, 0);
      app->dispatch_level = 0;
    }
  else
    XtDestroyWidget (widget);

#else
  abort ();
#endif
}

/* arch-tag: f21f0a1f-2a4e-44e1-8715-7f234fe2d159
   (do not change this comment) */