view src/gtk-xemacs.c @ 4690:257b468bf2ca

Move the #'query-coding-region implementation to C. This is necessary because there is no reasonable way to access the corresponding mswindows-multibyte functionality from Lisp, and we need such functionality if we're going to have a reliable and portable #'query-coding-region implementation. However, this change doesn't yet provide #'query-coding-region for the mswindow-multibyte coding systems, there should be no functional differences between an XEmacs with this change and one without it. src/ChangeLog addition: 2009-09-19 Aidan Kehoe <kehoea@parhasard.net> Move the #'query-coding-region implementation to C. This is necessary because there is no reasonable way to access the corresponding mswindows-multibyte functionality from Lisp, and we need such functionality if we're going to have a reliable and portable #'query-coding-region implementation. However, this change doesn't yet provide #'query-coding-region for the mswindow-multibyte coding systems, there should be no functional differences between an XEmacs with this change and one without it. * mule-coding.c (struct fixed_width_coding_system): Add a new coding system type, fixed_width, and implement it. It uses the CCL infrastructure but has a much simpler creation API, and its own query_method, formerly in lisp/mule/mule-coding.el. * unicode.c: Move the Unicode query method implementation here from unicode.el. * lisp.h: Declare Fmake_coding_system_internal, Fcopy_range_table here. * intl-win32.c (complex_vars_of_intl_win32): Use Fmake_coding_system_internal, not Fmake_coding_system. * general-slots.h: Add Qsucceeded, Qunencodable, Qinvalid_sequence here. * file-coding.h (enum coding_system_variant): Add fixed_width_coding_system here. (struct coding_system_methods): Add query_method and query_lstream_method to the coding system methods. Provide flags for the query methods. Declare the default query method; initialise it correctly in INITIALIZE_CODING_SYSTEM_TYPE. * file-coding.c (default_query_method): New function, the default query method for coding systems that do not set it. Moved from coding.el. (make_coding_system_1): Accept new elements in PROPS in #'make-coding-system; aliases, a list of aliases; safe-chars and safe-charsets (these were previously accepted but not saved); and category. (Fmake_coding_system_internal): New function, what used to be #'make-coding-system--on Mule builds, we've now moved some of the functionality of this to Lisp. (Fcoding_system_canonical_name_p): Move this earlier in the file, since it's now called from within make_coding_system_1. (Fquery_coding_region): Move the implementation of this here, from coding.el. (complex_vars_of_file_coding): Call Fmake_coding_system_internal, not Fmake_coding_system; specify safe-charsets properties when we're a mule build. * extents.h (mouse_highlight_priority, Fset_extent_priority, Fset_extent_face, Fmap_extents): Make these available to other C files. lisp/ChangeLog addition: 2009-09-19 Aidan Kehoe <kehoea@parhasard.net> Move the #'query-coding-region implementation to C. * coding.el: Consolidate code that depends on the presence or absence of Mule at the end of this file. (default-query-coding-region, query-coding-region): Move these functions to C. (default-query-coding-region-safe-charset-skip-chars-map): Remove this variable, the corresponding C variable is Vdefault_query_coding_region_chartab_cache in file-coding.c. (query-coding-string): Update docstring to reflect actual multiple values, be more careful about not modifying a range table that we're currently mapping over. (encode-coding-char): Make the implementation of this simpler. (featurep 'mule): Autoload #'make-coding-system from mule/make-coding-system.el if we're a mule build; provide an appropriate compiler macro. Do various non-mule compatibility things if we're not a mule build. * update-elc.el (additional-dump-dependencies): Add mule/make-coding-system as a dump time dependency if we're a mule build. * unicode.el (ccl-encode-to-ucs-2): (decode-char): (encode-char): Move these earlier in the file, for the sake of some byte compile warnings. (unicode-query-coding-region): Move this to unicode.c * mule/make-coding-system.el: New file, not dumped. Contains the functionality to rework the arguments necessary for fixed-width coding systems, and contains the implementation of #'make-coding-system, which now calls #'make-coding-system-internal. * mule/vietnamese.el (viscii): * mule/latin.el (iso-8859-2): (windows-1250): (iso-8859-3): (iso-8859-4): (iso-8859-14): (iso-8859-15): (iso-8859-16): (iso-8859-9): (macintosh): (windows-1252): * mule/hebrew.el (iso-8859-8): * mule/greek.el (iso-8859-7): (windows-1253): * mule/cyrillic.el (iso-8859-5): (koi8-r): (koi8-u): (windows-1251): (alternativnyj): (koi8-ru): (koi8-t): (koi8-c): (koi8-o): * mule/arabic.el (iso-8859-6): (windows-1256): Move all these coding systems to being of type fixed-width, not of type CCL. This allows the distinct query-coding-region for them to be in C, something which will eventually allow us to implement query-coding-region for the mswindows-multibyte coding systems. * mule/general-late.el (posix-charset-to-coding-system-hash): Document why we're pre-emptively persuading the byte compiler that the ELC for this file needs to be written using escape-quoted. Call #'set-unicode-query-skip-chars-args, now the Unicode query-coding-region implementation is in C. * mule/thai-xtis.el (tis-620): Don't bother checking whether we're XEmacs or not here. * mule/mule-coding.el: Move the eight bit fixed-width functionality from this file to make-coding-system.el. tests/ChangeLog addition: 2009-09-19 Aidan Kehoe <kehoea@parhasard.net> * automated/mule-tests.el: Check a coding system's type, not an 8-bit-fixed property, for whether that coding system should be treated as a fixed-width coding system. * automated/query-coding-tests.el: Don't test the query coding functionality for mswindows-multibyte coding systems, it's not yet implemented.
author Aidan Kehoe <kehoea@parhasard.net>
date Sat, 19 Sep 2009 22:53:13 +0100
parents dbd2a866e38a
children db7068430402
line wrap: on
line source

/* gtk-xemacs.c
**
** Description: A widget to encapsulate a XEmacs 'text widget'
**
** Created by: William M. Perry
** Copyright (c) 2000 William M. Perry <wmperry@gnu.org>
**
*/

#include <config.h>

#include "lisp.h"
#include "console-gtk.h"
#include "objects-gtk.h"
#include "gtk-xemacs.h"
#include "device.h"
#include "glyphs.h"
#include "window.h"
#include "faces.h"
#include "event-gtk.h"
#include "frame-impl.h"
#include "console-gtk-impl.h"
#include "device-impl.h"

extern Lisp_Object Vmodeline_face;
extern Lisp_Object Vscrollbar_on_left_p;

EXFUN (Fmake_image_instance, 4);

static void gtk_xemacs_class_init	(GtkXEmacsClass *klass);
static void gtk_xemacs_init		(GtkXEmacs *xemacs);
static void gtk_xemacs_size_allocate	(GtkWidget *widget, GtkAllocation *allocaction);
static void gtk_xemacs_draw		(GtkWidget *widget, GdkRectangle *area);
static void gtk_xemacs_paint		(GtkWidget *widget, GdkRectangle *area);
static void gtk_xemacs_size_request	(GtkWidget *widget, GtkRequisition *requisition);
static void gtk_xemacs_realize		(GtkWidget *widget);
static void gtk_xemacs_style_set        (GtkWidget *widget, GtkStyle *previous_style);
static gint gtk_xemacs_expose		(GtkWidget *widget, GdkEventExpose *event);

guint
gtk_xemacs_get_type (void)
{
  static guint xemacs_type = 0;

  if (!xemacs_type)
    {
      static const GtkTypeInfo xemacs_info =
      {
	"GtkXEmacs",
	sizeof (GtkXEmacs),
	sizeof (GtkXEmacsClass),
	(GtkClassInitFunc) gtk_xemacs_class_init,
	(GtkObjectInitFunc) gtk_xemacs_init,
	/* reserved_1 */ NULL,
        /* reserved_2 */ NULL,
        (GtkClassInitFunc) NULL,
      };

      xemacs_type = gtk_type_unique (gtk_fixed_get_type (), &xemacs_info);
    }

  return xemacs_type;
}

static GtkWidgetClass *parent_class;

static void
gtk_xemacs_class_init (GtkXEmacsClass *class_)
{
  GtkWidgetClass *widget_class;

  widget_class = (GtkWidgetClass*) class_;
  parent_class = (GtkWidgetClass *) gtk_type_class (gtk_fixed_get_type ());

  widget_class->size_allocate = gtk_xemacs_size_allocate;
  widget_class->size_request = gtk_xemacs_size_request;
  widget_class->draw = gtk_xemacs_draw;
  widget_class->expose_event = gtk_xemacs_expose;
  widget_class->realize = gtk_xemacs_realize;
  widget_class->button_press_event = emacs_gtk_button_event_handler;
  widget_class->button_release_event = emacs_gtk_button_event_handler;
  widget_class->key_press_event = emacs_gtk_key_event_handler;
  widget_class->key_release_event = emacs_gtk_key_event_handler;
  widget_class->motion_notify_event = emacs_gtk_motion_event_handler;
  widget_class->style_set = gtk_xemacs_style_set;
}

static void
gtk_xemacs_init (GtkXEmacs *xemacs)
{
    GTK_WIDGET_SET_FLAGS (xemacs, GTK_CAN_FOCUS);
}

GtkWidget*
gtk_xemacs_new (struct frame *f)
{
  GtkXEmacs *xemacs;

  xemacs = (GtkXEmacs*) gtk_type_new (gtk_xemacs_get_type ());
  xemacs->f = f;

  return GTK_WIDGET (xemacs);
}

static void
__nuke_background_items (GtkWidget *widget)
{
  /* This bit of voodoo is here to get around the annoying flicker
     when GDK tries to futz with our background pixmap as well as
     XEmacs doing it

     We do NOT set the background of this widget window, that way
     there is NO flickering, etc.  The downside is the XEmacs frame
     appears as 'seethru' when XEmacs is too busy to redraw the
     frame.

     Well, wait, we do... otherwise there sre weird 'seethru' areas
     even when XEmacs does a full redisplay.  Most noticable in some
     areas of the modeline, or in the right-hand-side of the window
     between the scrollbar ad n the edge of the window.
  */
  if (widget->window)
    {
      gdk_window_set_back_pixmap (widget->window, NULL, 0);
      gdk_window_set_back_pixmap (widget->parent->window, NULL, 0);
      gdk_window_set_background (widget->parent->window,
				 &widget->style->bg[GTK_STATE_NORMAL]);
      gdk_window_set_background (widget->window,
				 &widget->style->bg[GTK_STATE_NORMAL]);
    }
}

extern Lisp_Object xemacs_gtk_convert_color(GdkColor *c, GtkWidget *w);

/* From objects-gtk.c */
extern Lisp_Object __get_gtk_font_truename (GdkFont *gdk_font, int expandp);

#define convert_font(f) __get_gtk_font_truename (f, 0)

#ifdef SMASH_FACE_FALLBACKS
static void
smash_face_fallbacks (struct frame *f, GtkStyle *style)
{
#define FROB(face,prop,slot) do { 							\
				Lisp_Object fallback = Qnil;				\
				Lisp_Object specifier = Fget (face, prop, Qnil);	\
   				struct Lisp_Specifier *sp = NULL;			\
 				if (NILP (specifier)) continue;				\
 				sp = XSPECIFIER (specifier);				\
 				fallback = sp->fallback;				\
 				if (EQ (Fcar (Fcar (Fcar (fallback))), Qgtk))		\
 					fallback = XCDR (fallback);			\
 				if (! NILP (slot))					\
 					fallback = acons (list1 (Qgtk),			\
 								  slot,			\
 								  fallback);		\
 				set_specifier_fallback (specifier, fallback);		\
			     } while (0);
#define FROB_FACE(face,fg_slot,bg_slot) \
do {											\
	FROB (face, Qforeground, xemacs_gtk_convert_color (&style->fg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f)));	\
	FROB (face, Qbackground, xemacs_gtk_convert_color (&style->bg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f)));	\
	if (style->rc_style && style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL])	\
	{										\
		FROB (Vdefault_face, Qbackground_pixmap,				\
			Fmake_image_instance (build_string (style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL]), \
					  f->device, Qnil, make_int (5)));			\
	}										\
	else										\
	{										\
		FROB (Vdefault_face, Qbackground_pixmap, Qnil);				\
	}										\
} while (0)

  FROB (Vdefault_face, Qfont, convert_font (style->font));
  FROB_FACE (Vdefault_face, fg, bg);
  FROB_FACE (Vgui_element_face, text, mid);

#undef FROB
#undef FROB_FACE
}
#endif /* SMASH_FACE_FALLBACKS */

#ifdef HAVE_SCROLLBARS
static void
smash_scrollbar_specifiers (struct frame *f, GtkStyle *style)
{
  Lisp_Object frame;
  int slider_size = 0;
  int hsize, vsize;
  GtkRangeClass *klass;

  frame = wrap_frame (f);

  klass = (GtkRangeClass *) gtk_type_class (GTK_TYPE_SCROLLBAR);
  slider_size = klass->slider_width;
  hsize = slider_size + (style->klass->ythickness * 2);
  vsize = slider_size + (style->klass->xthickness * 2);

  style = gtk_style_attach (style,
			    GTK_WIDGET (DEVICE_GTK_APP_SHELL (XDEVICE (FRAME_DEVICE (f))))->window);

  Fadd_spec_to_specifier (Vscrollbar_width, make_int (vsize), frame, Qnil, Qnil);
  Fadd_spec_to_specifier (Vscrollbar_height, make_int (hsize), frame, Qnil, Qnil);
}
#endif /* HAVE_SCROLLBARS */

#ifdef HAVE_TOOLBARS
extern Lisp_Object Vtoolbar_shadow_thickness;

static void
smash_toolbar_specifiers(struct frame *f, GtkStyle *style)
{
  Lisp_Object frame;
  GtkStyleClass *klass = (GtkStyleClass *) style->klass;

  frame = wrap_frame (f);

  Fadd_spec_to_specifier (Vtoolbar_shadow_thickness, make_int (klass->xthickness),
			  Qnil, list2 (Qgtk, Qdefault), Qprepend);
}
#endif /* HAVE_TOOLBARS */

static void
gtk_xemacs_realize (GtkWidget *widget)
{
  parent_class->realize (widget);
  gtk_xemacs_style_set (widget, gtk_widget_get_style (widget));
}

static void
gtk_xemacs_style_set (GtkWidget *widget, GtkStyle *previous_style)
{
  GtkStyle *new_style = gtk_widget_get_style (widget);
  GtkXEmacs *x = GTK_XEMACS (widget);

  parent_class->style_set (widget, previous_style);

  if (x->f)
    {
      __nuke_background_items (widget);
#ifdef SMASH_FACE_FALLBACKS
      smash_face_fallbacks (x->f, new_style);
#endif
#ifdef HAVE_SCROLLBARS
      smash_scrollbar_specifiers (x->f, new_style);
#endif
#ifdef HAVE_TOOLBARS
      smash_toolbar_specifiers (x->f, new_style);
#endif
    }
}

static void
gtk_xemacs_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
    GtkXEmacs *x = GTK_XEMACS (widget);
    struct frame *f = GTK_XEMACS_FRAME (x);
    int width, height;

    if (f)
      {
	char_to_pixel_size (f, FRAME_WIDTH (f), FRAME_HEIGHT (f),
			    &width, &height);
	requisition->width = width;
	requisition->height = height;
      }
    else
      {
	parent_class->size_request (widget, requisition);
      }
}

/* Assign a size and position to the child widgets.  This differs from the
   super class method in that for all widgets except the scrollbars the size
   and position are not caclulated here.  This is because these widgets have
   this function performed for them by the redisplay code (see
   gtk_map_subwindow()). If the superclass method is called then the widgets
   can change size and position as the two pieces of code move the widgets at
   random.
*/
static void
gtk_xemacs_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
    GtkXEmacs *x = GTK_XEMACS (widget);
    GtkFixed *fixed = GTK_FIXED (widget);
    struct frame *f = GTK_XEMACS_FRAME (x);
    int columns, rows;
    GList *children;
    guint16 border_width;

    widget->allocation = *allocation;
    if (GTK_WIDGET_REALIZED (widget))
      gdk_window_move_resize (widget->window,
			      allocation->x, 
			      allocation->y,
			      allocation->width, 
			      allocation->height);

    border_width = GTK_CONTAINER (fixed)->border_width;
  
    children = fixed->children;
    while (children)
      {
	GtkFixedChild* child = (GtkFixedChild*) children->data;
	children = children->next;
      
	/*
	  Scrollbars are the only widget that is managed by GTK.  See
	  comments in gtk_create_scrollbar_instance().
	*/
	if (GTK_WIDGET_VISIBLE (child->widget) &&
	    gtk_type_is_a(GTK_OBJECT_TYPE(child->widget), GTK_TYPE_SCROLLBAR))
	  {
	    GtkAllocation child_allocation;
	    GtkRequisition child_requisition;

	    gtk_widget_get_child_requisition (child->widget, &child_requisition);
	    child_allocation.x = child->x + border_width;
	    child_allocation.y = child->y + border_width;
	    child_allocation.width = child_requisition.width;
	    child_allocation.height = child_requisition.height;
	    gtk_widget_size_allocate (child->widget, &child_allocation);
	  }
      }

    if (f)
      {
	f->pixwidth = allocation->width;
	f->pixheight = allocation->height;

	pixel_to_char_size (f,
			    allocation->width,
			    allocation->height, &columns, &rows);

	change_frame_size (f, rows, columns, 1);
      }
}

static void
gtk_xemacs_paint (GtkWidget *widget, GdkRectangle *area)
{
    GtkXEmacs *x = GTK_XEMACS (widget);
    struct frame *f = GTK_XEMACS_FRAME (x);

    if (GTK_WIDGET_DRAWABLE (widget))
      redisplay_redraw_exposed_area (f, area->x, area->y, area->width,
				     area->height);
}

static void
gtk_xemacs_draw (GtkWidget *widget, GdkRectangle *area)
{
    GtkFixed *fixed = GTK_FIXED (widget);
    GtkFixedChild *child;
    GdkRectangle child_area;
    GList *children;

    /* I need to manually iterate over the children instead of just
       chaining to parent_class->draw() because it calls
       gtk_fixed_paint() directly, which clears the background window,
       which causes A LOT of flashing. */

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      gtk_xemacs_paint (widget, area);

      children = fixed->children;

      while (children)
	{
	  child = (GtkFixedChild*) children->data;
	  children = children->next;
	  /* #### This is what causes the scrollbar flickering!
	     Evidently the scrollbars pretty much take care of drawing
	     themselves in most cases.  Then we come along and tell them
	     to redraw again!

	     But if we just leave it out, then they do not get drawn
	     correctly the first time!

	     Scrollbar flickering has been greatly helped by the
	     optimizations in scrollbar-gtk.c /
	     gtk_update_scrollbar_instance_status (), so this is not that
	     big a deal anymore.
	  */
	  if (gtk_widget_intersect (child->widget, area, &child_area))
	    {
	      gtk_widget_draw (child->widget, &child_area);
	    }
	}
    }
}

static gint
gtk_xemacs_expose (GtkWidget *widget, GdkEventExpose *event)
{
    GtkXEmacs *x = GTK_XEMACS (widget);
    struct frame *f = GTK_XEMACS_FRAME (x);
    GdkRectangle *a = &event->area;

  if (GTK_WIDGET_DRAWABLE (widget))
    {
      /* This takes care of drawing the scrollbars, etc */
      parent_class->expose_event (widget, event);

      /* Now draw the actual frame data */
      if (!check_for_ignored_expose (f, a->x, a->y, a->width, a->height) &&
	  !find_matching_subwindow (f, a->x, a->y, a->width, a->height))
	redisplay_redraw_exposed_area (f, a->x, a->y, a->width, a->height);
      return (TRUE);
    }

  return FALSE;
}

Lisp_Object
xemacs_gtk_convert_color(GdkColor *c, GtkWidget *UNUSED (w))
{
  char color_buf[255];

  sprintf (color_buf, "#%04x%04x%04x", c->red, c->green, c->blue);

  return (build_string (color_buf));
}