Initial revision
[chise/xemacs-chise.git.1] / src / gtk-xemacs.c
1 /* gtk-xemacs.c
2 **
3 ** Description: A widget to encapsulate a XEmacs 'text widget'
4 **
5 ** Created by: William M. Perry
6 ** Copyright (c) 2000 William M. Perry <wmperry@gnu.org>
7 **
8 */
9
10 #include <config.h>
11
12 #include "lisp.h"
13 #include "console-gtk.h"
14 #include "objects-gtk.h"
15 #include "gtk-xemacs.h"
16 #include "window.h"
17 #include "faces.h"
18
19 extern Lisp_Object Vmodeline_face;
20 extern Lisp_Object Vscrollbar_on_left_p;
21
22 EXFUN (Fmake_image_instance, 4);
23
24 static void gtk_xemacs_class_init       (GtkXEmacsClass *klass);
25 static void gtk_xemacs_init             (GtkXEmacs *xemacs);
26 static void gtk_xemacs_size_allocate    (GtkWidget *widget, GtkAllocation *allocaction);
27 static void gtk_xemacs_draw             (GtkWidget *widget, GdkRectangle *area);
28 static void gtk_xemacs_paint            (GtkWidget *widget, GdkRectangle *area);
29 static void gtk_xemacs_size_request     (GtkWidget *widget, GtkRequisition *requisition);
30 static void gtk_xemacs_realize          (GtkWidget *widget);
31 static void gtk_xemacs_style_set        (GtkWidget *widget, GtkStyle *previous_style);
32 static gint gtk_xemacs_expose           (GtkWidget *widget, GdkEventExpose *event);
33
34 guint
35 gtk_xemacs_get_type (void)
36 {
37   static guint xemacs_type = 0;
38
39   if (!xemacs_type)
40     {
41       static const GtkTypeInfo xemacs_info =
42       {
43         "GtkXEmacs",
44         sizeof (GtkXEmacs),
45         sizeof (GtkXEmacsClass),
46         (GtkClassInitFunc) gtk_xemacs_class_init,
47         (GtkObjectInitFunc) gtk_xemacs_init,
48         /* reserved_1 */ NULL,
49         /* reserved_2 */ NULL,
50         (GtkClassInitFunc) NULL,
51       };
52
53       xemacs_type = gtk_type_unique (gtk_fixed_get_type (), &xemacs_info);
54     }
55
56   return xemacs_type;
57 }
58
59 static GtkWidgetClass *parent_class;
60
61 extern gint emacs_gtk_button_event_handler(GtkWidget *widget, GdkEventButton *event);
62 extern gint emacs_gtk_key_event_handler(GtkWidget *widget, GdkEventKey *event);
63 extern gint emacs_gtk_motion_event_handler(GtkWidget *widget, GdkEventMotion *event);
64
65 static void
66 gtk_xemacs_class_init (GtkXEmacsClass *class)
67 {
68   GtkWidgetClass *widget_class;
69
70   widget_class = (GtkWidgetClass*) class;
71   parent_class = (GtkWidgetClass *) gtk_type_class (gtk_fixed_get_type ());
72
73   widget_class->size_allocate = gtk_xemacs_size_allocate;
74   widget_class->size_request = gtk_xemacs_size_request;
75   widget_class->draw = gtk_xemacs_draw;
76   widget_class->expose_event = gtk_xemacs_expose;
77   widget_class->realize = gtk_xemacs_realize;
78   widget_class->button_press_event = emacs_gtk_button_event_handler;
79   widget_class->button_release_event = emacs_gtk_button_event_handler;
80   widget_class->key_press_event = emacs_gtk_key_event_handler;
81   widget_class->key_release_event = emacs_gtk_key_event_handler;
82   widget_class->motion_notify_event = emacs_gtk_motion_event_handler;
83   widget_class->style_set = gtk_xemacs_style_set;
84 }
85
86 static void
87 gtk_xemacs_init (GtkXEmacs *xemacs)
88 {
89     GTK_WIDGET_SET_FLAGS (xemacs, GTK_CAN_FOCUS);
90 }
91
92 GtkWidget*
93 gtk_xemacs_new (struct frame *f)
94 {
95   GtkXEmacs *xemacs;
96
97   xemacs = gtk_type_new (gtk_xemacs_get_type ());
98   xemacs->f = f;
99
100   return GTK_WIDGET (xemacs);
101 }
102
103 static void
104 __nuke_background_items (GtkWidget *widget)
105 {
106   /* This bit of voodoo is here to get around the annoying flicker
107      when GDK tries to futz with our background pixmap as well as
108      XEmacs doing it
109
110      We do NOT set the background of this widget window, that way
111      there is NO flickering, etc.  The downside is the XEmacs frame
112      appears as 'seethru' when XEmacs is too busy to redraw the
113      frame.
114
115      Well, wait, we do... otherwise there sre weird 'seethru' areas
116      even when XEmacs does a full redisplay.  Most noticable in some
117      areas of the modeline, or in the right-hand-side of the window
118      between the scrollbar ad n the edge of the window.
119   */
120   if (widget->window)
121     {
122       gdk_window_set_back_pixmap (widget->window, NULL, 0);
123       gdk_window_set_back_pixmap (widget->parent->window, NULL, 0);
124       gdk_window_set_background (widget->parent->window,
125                                  &widget->style->bg[GTK_STATE_NORMAL]);
126       gdk_window_set_background (widget->window,
127                                  &widget->style->bg[GTK_STATE_NORMAL]);
128     }
129 }
130
131 extern Lisp_Object xemacs_gtk_convert_color(GdkColor *c, GtkWidget *w);
132
133 /* From objects-gtk.c */
134 extern Lisp_Object __get_gtk_font_truename (GdkFont *gdk_font, int expandp);
135
136 #define convert_font(f) __get_gtk_font_truename (f, 0)
137
138 static void
139 smash_face_fallbacks (struct frame *f, GtkStyle *style)
140 {
141 #define FROB(face,prop,slot) do {                                                       \
142                                 Lisp_Object fallback = Qnil;                            \
143                                 Lisp_Object specifier = Fget (face, prop, Qnil);        \
144                                 struct Lisp_Specifier *sp = NULL;                       \
145                                 if (NILP (specifier)) continue;                         \
146                                 sp = XSPECIFIER (specifier);                            \
147                                 fallback = sp->fallback;                                \
148                                 if (EQ (Fcar (Fcar (Fcar (fallback))), Qgtk))           \
149                                         fallback = XCDR (fallback);                     \
150                                 if (! NILP (slot))                                      \
151                                         fallback = acons (list1 (Qgtk),                 \
152                                                                   slot,                 \
153                                                                   fallback);            \
154                                 set_specifier_fallback (specifier, fallback);           \
155                              } while (0);
156 #define FROB_FACE(face,fg_slot,bg_slot) \
157 do {                                                                                    \
158         FROB (face, Qforeground, xemacs_gtk_convert_color (&style->fg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f)));     \
159         FROB (face, Qbackground, xemacs_gtk_convert_color (&style->bg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f)));     \
160         if (style->rc_style && style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL])       \
161         {                                                                               \
162                 FROB (Vdefault_face, Qbackground_pixmap,                                \
163                         Fmake_image_instance (build_string (style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL]), \
164                                           f->device, Qnil, make_int (5)));                      \
165         }                                                                               \
166         else                                                                            \
167         {                                                                               \
168                 FROB (Vdefault_face, Qbackground_pixmap, Qnil);                         \
169         }                                                                               \
170 } while (0)
171
172   FROB (Vdefault_face, Qfont, convert_font (style->font));
173   FROB_FACE (Vdefault_face, fg, bg);
174   FROB_FACE (Vgui_element_face, text, mid);
175
176 #undef FROB
177 #undef FROB_FACE
178 }
179
180 #ifdef HAVE_SCROLLBARS
181 static void
182 smash_scrollbar_specifiers (struct frame *f, GtkStyle *style)
183 {
184   Lisp_Object frame;
185   int slider_size = 0;
186   int hsize, vsize;
187   GtkRangeClass *klass;
188
189   XSETFRAME (frame, f);
190
191   klass = (GtkRangeClass *) gtk_type_class (GTK_TYPE_SCROLLBAR);
192   slider_size = klass->slider_width;
193   hsize = slider_size + (style->klass->ythickness * 2);
194   vsize = slider_size + (style->klass->xthickness * 2);
195
196   style = gtk_style_attach (style,
197                             GTK_WIDGET (DEVICE_GTK_APP_SHELL (XDEVICE (FRAME_DEVICE (f))))->window);
198
199   Fadd_spec_to_specifier (Vscrollbar_width, make_int (vsize), frame, Qnil, Qnil);
200   Fadd_spec_to_specifier (Vscrollbar_height, make_int (hsize), frame, Qnil, Qnil);
201 }
202 #else
203 #define smash_scrollbar_specifiers(x,y)
204 #endif /* HAVE_SCROLLBARS */
205
206 static void
207 gtk_xemacs_realize (GtkWidget *widget)
208 {
209   parent_class->realize (widget);
210   gtk_xemacs_style_set (widget, gtk_widget_get_style (widget));
211 }
212
213 static void
214 gtk_xemacs_style_set (GtkWidget *widget, GtkStyle *previous_style)
215 {
216   GtkStyle *new_style = gtk_widget_get_style (widget);
217   GtkXEmacs *x = GTK_XEMACS (widget);
218
219   parent_class->style_set (widget, previous_style);
220
221   if (x->f)
222     {
223       __nuke_background_items (widget);
224 #if 0
225       smash_face_fallbacks (x->f, new_style);
226 #endif
227       smash_scrollbar_specifiers (x->f, new_style);
228     }
229 }
230
231 static void
232 gtk_xemacs_size_request (GtkWidget *widget, GtkRequisition *requisition)
233 {
234     GtkXEmacs *x = GTK_XEMACS (widget);
235     struct frame *f = GTK_XEMACS_FRAME (x);
236     int width, height;
237
238     if (f)
239       {
240         char_to_pixel_size (f, FRAME_WIDTH (f), FRAME_HEIGHT (f),
241                             &width, &height);
242         requisition->width = width;
243         requisition->height = height;
244       }
245     else
246       {
247         parent_class->size_request (widget, requisition);
248       }
249 }
250
251 static void
252 gtk_xemacs_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
253 {
254     GtkXEmacs *x = GTK_XEMACS (widget);
255     struct frame *f = GTK_XEMACS_FRAME (x);
256     int columns, rows;
257
258     parent_class->size_allocate(widget, allocation);
259
260     if (f)
261       {
262         f->pixwidth = allocation->width;
263         f->pixheight = allocation->height;
264
265         pixel_to_char_size (f,
266                             allocation->width,
267                             allocation->height, &columns, &rows);
268
269         change_frame_size (f, rows, columns, 1);
270       }
271 }
272
273 static void
274 gtk_xemacs_paint (GtkWidget *widget, GdkRectangle *area)
275 {
276     GtkXEmacs *x = GTK_XEMACS (widget);
277     struct frame *f = GTK_XEMACS_FRAME (x);
278     gtk_redraw_exposed_area (f, area->x, area->y, area->width, area->height);
279 }
280
281 static void
282 gtk_xemacs_draw (GtkWidget *widget, GdkRectangle *area)
283 {
284     GtkFixed *fixed = GTK_FIXED (widget);
285     GtkFixedChild *child;
286     GdkRectangle child_area;
287     GList *children;
288
289     /* I need to manually iterate over the children instead of just
290        chaining to parent_class->draw() because it calls
291        gtk_fixed_paint() directly, which clears the background window,
292        which causes A LOT of flashing. */
293
294     gtk_xemacs_paint (widget, area);
295
296     children = fixed->children;
297
298     while (children)
299       {
300         child = children->data;
301         children = children->next;
302         /* #### This is what causes the scrollbar flickering!
303            Evidently the scrollbars pretty much take care of drawing
304            themselves in most cases.  Then we come along and tell them
305            to redraw again!
306
307            But if we just leave it out, then they do not get drawn
308            correctly the first time!
309
310            Scrollbar flickering has been greatly helped by the
311            optimizations in scrollbar-gtk.c /
312            gtk_update_scrollbar_instance_status (), so this is not that
313            big a deal anymore.
314         */
315         if (gtk_widget_intersect (child->widget, area, &child_area))
316           {
317             gtk_widget_draw (child->widget, &child_area);
318           }
319       }
320 }
321
322 static gint
323 gtk_xemacs_expose (GtkWidget *widget, GdkEventExpose *event)
324 {
325     GtkXEmacs *x = GTK_XEMACS (widget);
326     struct frame *f = GTK_XEMACS_FRAME (x);
327     GdkRectangle *a = &event->area;
328
329     /* This takes care of drawing the scrollbars, etc */
330     parent_class->expose_event (widget, event);
331
332     /* Now draw the actual frame data */
333     if (!check_for_ignored_expose (f, a->x, a->y, a->width, a->height) &&
334         !find_matching_subwindow (f, a->x, a->y, a->width, a->height))
335       gtk_redraw_exposed_area (f, a->x, a->y, a->width, a->height);
336     return (TRUE);
337 }
338
339 Lisp_Object
340 xemacs_gtk_convert_color(GdkColor *c, GtkWidget *w)
341 {
342   char color_buf[255];
343
344   sprintf (color_buf, "#%04x%04x%04x", c->red, c->green, c->blue);
345
346   return (build_string (color_buf));
347 }