Mercurial > hg > xemacs-beta
diff src/gtk-xemacs.c @ 462:0784d089fdc9 r21-2-46
Import from CVS: tag r21-2-46
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:44:37 +0200 |
parents | |
children | 8ae895c67ce7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gtk-xemacs.c Mon Aug 13 11:44:37 2007 +0200 @@ -0,0 +1,347 @@ +/* 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 "window.h" +#include "faces.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; + +extern gint emacs_gtk_button_event_handler(GtkWidget *widget, GdkEventButton *event); +extern gint emacs_gtk_key_event_handler(GtkWidget *widget, GdkEventKey *event); +extern gint emacs_gtk_motion_event_handler(GtkWidget *widget, GdkEventMotion *event); + +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 = 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) + +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 +} + +#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; + + XSETFRAME (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); +} +#else +#define smash_scrollbar_specifiers(x,y) +#endif /* HAVE_SCROLLBARS */ + +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); +#if 0 + smash_face_fallbacks (x->f, new_style); +#endif + smash_scrollbar_specifiers (x->f, new_style); + } +} + +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); + } +} + +static void +gtk_xemacs_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + GtkXEmacs *x = GTK_XEMACS (widget); + struct frame *f = GTK_XEMACS_FRAME (x); + int columns, rows; + + parent_class->size_allocate(widget, 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); + gtk_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. */ + + gtk_xemacs_paint (widget, area); + + children = fixed->children; + + while (children) + { + child = 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; + + /* 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)) + gtk_redraw_exposed_area (f, a->x, a->y, a->width, a->height); + return (TRUE); +} + +Lisp_Object +xemacs_gtk_convert_color(GdkColor *c, GtkWidget *w) +{ + char color_buf[255]; + + sprintf (color_buf, "#%04x%04x%04x", c->red, c->green, c->blue); + + return (build_string (color_buf)); +}