462
|
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"
|
809
|
16 #include "device.h"
|
|
17 #include "glyphs.h"
|
462
|
18 #include "window.h"
|
|
19 #include "faces.h"
|
778
|
20 #include "event-gtk.h"
|
876
|
21 #include "frame-impl.h"
|
|
22 #include "console-gtk-impl.h"
|
|
23 #include "device-impl.h"
|
462
|
24
|
|
25 extern Lisp_Object Vmodeline_face;
|
|
26 extern Lisp_Object Vscrollbar_on_left_p;
|
|
27
|
|
28 EXFUN (Fmake_image_instance, 4);
|
|
29
|
|
30 static void gtk_xemacs_class_init (GtkXEmacsClass *klass);
|
|
31 static void gtk_xemacs_init (GtkXEmacs *xemacs);
|
|
32 static void gtk_xemacs_size_allocate (GtkWidget *widget, GtkAllocation *allocaction);
|
|
33 static void gtk_xemacs_draw (GtkWidget *widget, GdkRectangle *area);
|
|
34 static void gtk_xemacs_paint (GtkWidget *widget, GdkRectangle *area);
|
|
35 static void gtk_xemacs_size_request (GtkWidget *widget, GtkRequisition *requisition);
|
|
36 static void gtk_xemacs_realize (GtkWidget *widget);
|
|
37 static void gtk_xemacs_style_set (GtkWidget *widget, GtkStyle *previous_style);
|
|
38 static gint gtk_xemacs_expose (GtkWidget *widget, GdkEventExpose *event);
|
|
39
|
|
40 guint
|
|
41 gtk_xemacs_get_type (void)
|
|
42 {
|
|
43 static guint xemacs_type = 0;
|
|
44
|
|
45 if (!xemacs_type)
|
|
46 {
|
|
47 static const GtkTypeInfo xemacs_info =
|
|
48 {
|
|
49 "GtkXEmacs",
|
|
50 sizeof (GtkXEmacs),
|
|
51 sizeof (GtkXEmacsClass),
|
|
52 (GtkClassInitFunc) gtk_xemacs_class_init,
|
|
53 (GtkObjectInitFunc) gtk_xemacs_init,
|
|
54 /* reserved_1 */ NULL,
|
|
55 /* reserved_2 */ NULL,
|
|
56 (GtkClassInitFunc) NULL,
|
|
57 };
|
|
58
|
|
59 xemacs_type = gtk_type_unique (gtk_fixed_get_type (), &xemacs_info);
|
|
60 }
|
|
61
|
|
62 return xemacs_type;
|
|
63 }
|
|
64
|
|
65 static GtkWidgetClass *parent_class;
|
|
66
|
|
67 static void
|
1204
|
68 gtk_xemacs_class_init (GtkXEmacsClass *class_)
|
462
|
69 {
|
|
70 GtkWidgetClass *widget_class;
|
|
71
|
1204
|
72 widget_class = (GtkWidgetClass*) class_;
|
462
|
73 parent_class = (GtkWidgetClass *) gtk_type_class (gtk_fixed_get_type ());
|
|
74
|
|
75 widget_class->size_allocate = gtk_xemacs_size_allocate;
|
|
76 widget_class->size_request = gtk_xemacs_size_request;
|
|
77 widget_class->draw = gtk_xemacs_draw;
|
|
78 widget_class->expose_event = gtk_xemacs_expose;
|
|
79 widget_class->realize = gtk_xemacs_realize;
|
|
80 widget_class->button_press_event = emacs_gtk_button_event_handler;
|
|
81 widget_class->button_release_event = emacs_gtk_button_event_handler;
|
|
82 widget_class->key_press_event = emacs_gtk_key_event_handler;
|
|
83 widget_class->key_release_event = emacs_gtk_key_event_handler;
|
|
84 widget_class->motion_notify_event = emacs_gtk_motion_event_handler;
|
|
85 widget_class->style_set = gtk_xemacs_style_set;
|
|
86 }
|
|
87
|
|
88 static void
|
|
89 gtk_xemacs_init (GtkXEmacs *xemacs)
|
|
90 {
|
|
91 GTK_WIDGET_SET_FLAGS (xemacs, GTK_CAN_FOCUS);
|
|
92 }
|
|
93
|
|
94 GtkWidget*
|
|
95 gtk_xemacs_new (struct frame *f)
|
|
96 {
|
|
97 GtkXEmacs *xemacs;
|
|
98
|
2054
|
99 xemacs = (GtkXEmacs*) gtk_type_new (gtk_xemacs_get_type ());
|
462
|
100 xemacs->f = f;
|
|
101
|
|
102 return GTK_WIDGET (xemacs);
|
|
103 }
|
|
104
|
|
105 static void
|
|
106 __nuke_background_items (GtkWidget *widget)
|
|
107 {
|
|
108 /* This bit of voodoo is here to get around the annoying flicker
|
|
109 when GDK tries to futz with our background pixmap as well as
|
|
110 XEmacs doing it
|
|
111
|
|
112 We do NOT set the background of this widget window, that way
|
|
113 there is NO flickering, etc. The downside is the XEmacs frame
|
|
114 appears as 'seethru' when XEmacs is too busy to redraw the
|
|
115 frame.
|
|
116
|
|
117 Well, wait, we do... otherwise there sre weird 'seethru' areas
|
|
118 even when XEmacs does a full redisplay. Most noticable in some
|
|
119 areas of the modeline, or in the right-hand-side of the window
|
|
120 between the scrollbar ad n the edge of the window.
|
|
121 */
|
|
122 if (widget->window)
|
|
123 {
|
|
124 gdk_window_set_back_pixmap (widget->window, NULL, 0);
|
|
125 gdk_window_set_back_pixmap (widget->parent->window, NULL, 0);
|
|
126 gdk_window_set_background (widget->parent->window,
|
|
127 &widget->style->bg[GTK_STATE_NORMAL]);
|
|
128 gdk_window_set_background (widget->window,
|
|
129 &widget->style->bg[GTK_STATE_NORMAL]);
|
|
130 }
|
|
131 }
|
|
132
|
|
133 extern Lisp_Object xemacs_gtk_convert_color(GdkColor *c, GtkWidget *w);
|
|
134
|
|
135 /* From objects-gtk.c */
|
|
136 extern Lisp_Object __get_gtk_font_truename (GdkFont *gdk_font, int expandp);
|
|
137
|
|
138 #define convert_font(f) __get_gtk_font_truename (f, 0)
|
|
139
|
778
|
140 #ifdef SMASH_FACE_FALLBACKS
|
462
|
141 static void
|
|
142 smash_face_fallbacks (struct frame *f, GtkStyle *style)
|
|
143 {
|
|
144 #define FROB(face,prop,slot) do { \
|
|
145 Lisp_Object fallback = Qnil; \
|
|
146 Lisp_Object specifier = Fget (face, prop, Qnil); \
|
|
147 struct Lisp_Specifier *sp = NULL; \
|
|
148 if (NILP (specifier)) continue; \
|
|
149 sp = XSPECIFIER (specifier); \
|
|
150 fallback = sp->fallback; \
|
|
151 if (EQ (Fcar (Fcar (Fcar (fallback))), Qgtk)) \
|
|
152 fallback = XCDR (fallback); \
|
|
153 if (! NILP (slot)) \
|
|
154 fallback = acons (list1 (Qgtk), \
|
|
155 slot, \
|
|
156 fallback); \
|
|
157 set_specifier_fallback (specifier, fallback); \
|
|
158 } while (0);
|
|
159 #define FROB_FACE(face,fg_slot,bg_slot) \
|
|
160 do { \
|
|
161 FROB (face, Qforeground, xemacs_gtk_convert_color (&style->fg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f))); \
|
|
162 FROB (face, Qbackground, xemacs_gtk_convert_color (&style->bg_slot[GTK_STATE_NORMAL], FRAME_GTK_SHELL_WIDGET (f))); \
|
|
163 if (style->rc_style && style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL]) \
|
|
164 { \
|
|
165 FROB (Vdefault_face, Qbackground_pixmap, \
|
|
166 Fmake_image_instance (build_string (style->rc_style->bg_pixmap_name[GTK_STATE_NORMAL]), \
|
|
167 f->device, Qnil, make_int (5))); \
|
|
168 } \
|
|
169 else \
|
|
170 { \
|
|
171 FROB (Vdefault_face, Qbackground_pixmap, Qnil); \
|
|
172 } \
|
|
173 } while (0)
|
|
174
|
|
175 FROB (Vdefault_face, Qfont, convert_font (style->font));
|
|
176 FROB_FACE (Vdefault_face, fg, bg);
|
|
177 FROB_FACE (Vgui_element_face, text, mid);
|
|
178
|
|
179 #undef FROB
|
|
180 #undef FROB_FACE
|
|
181 }
|
778
|
182 #endif /* SMASH_FACE_FALLBACKS */
|
462
|
183
|
|
184 #ifdef HAVE_SCROLLBARS
|
|
185 static void
|
|
186 smash_scrollbar_specifiers (struct frame *f, GtkStyle *style)
|
|
187 {
|
|
188 Lisp_Object frame;
|
|
189 int slider_size = 0;
|
|
190 int hsize, vsize;
|
|
191 GtkRangeClass *klass;
|
|
192
|
793
|
193 frame = wrap_frame (f);
|
462
|
194
|
|
195 klass = (GtkRangeClass *) gtk_type_class (GTK_TYPE_SCROLLBAR);
|
|
196 slider_size = klass->slider_width;
|
|
197 hsize = slider_size + (style->klass->ythickness * 2);
|
|
198 vsize = slider_size + (style->klass->xthickness * 2);
|
|
199
|
|
200 style = gtk_style_attach (style,
|
|
201 GTK_WIDGET (DEVICE_GTK_APP_SHELL (XDEVICE (FRAME_DEVICE (f))))->window);
|
|
202
|
|
203 Fadd_spec_to_specifier (Vscrollbar_width, make_int (vsize), frame, Qnil, Qnil);
|
|
204 Fadd_spec_to_specifier (Vscrollbar_height, make_int (hsize), frame, Qnil, Qnil);
|
|
205 }
|
|
206 #endif /* HAVE_SCROLLBARS */
|
|
207
|
744
|
208 #ifdef HAVE_TOOLBARS
|
|
209 extern Lisp_Object Vtoolbar_shadow_thickness;
|
|
210
|
|
211 static void
|
|
212 smash_toolbar_specifiers(struct frame *f, GtkStyle *style)
|
|
213 {
|
|
214 Lisp_Object frame;
|
|
215 GtkStyleClass *klass = (GtkStyleClass *) style->klass;
|
|
216
|
793
|
217 frame = wrap_frame (f);
|
744
|
218
|
|
219 Fadd_spec_to_specifier (Vtoolbar_shadow_thickness, make_int (klass->xthickness),
|
|
220 Qnil, list2 (Qgtk, Qdefault), Qprepend);
|
|
221 }
|
|
222 #endif /* HAVE_TOOLBARS */
|
|
223
|
462
|
224 static void
|
|
225 gtk_xemacs_realize (GtkWidget *widget)
|
|
226 {
|
|
227 parent_class->realize (widget);
|
|
228 gtk_xemacs_style_set (widget, gtk_widget_get_style (widget));
|
|
229 }
|
|
230
|
|
231 static void
|
|
232 gtk_xemacs_style_set (GtkWidget *widget, GtkStyle *previous_style)
|
|
233 {
|
|
234 GtkStyle *new_style = gtk_widget_get_style (widget);
|
|
235 GtkXEmacs *x = GTK_XEMACS (widget);
|
|
236
|
|
237 parent_class->style_set (widget, previous_style);
|
|
238
|
|
239 if (x->f)
|
|
240 {
|
|
241 __nuke_background_items (widget);
|
778
|
242 #ifdef SMASH_FACE_FALLBACKS
|
462
|
243 smash_face_fallbacks (x->f, new_style);
|
|
244 #endif
|
744
|
245 #ifdef HAVE_SCROLLBARS
|
462
|
246 smash_scrollbar_specifiers (x->f, new_style);
|
744
|
247 #endif
|
|
248 #ifdef HAVE_TOOLBARS
|
|
249 smash_toolbar_specifiers (x->f, new_style);
|
|
250 #endif
|
462
|
251 }
|
|
252 }
|
|
253
|
|
254 static void
|
|
255 gtk_xemacs_size_request (GtkWidget *widget, GtkRequisition *requisition)
|
|
256 {
|
|
257 GtkXEmacs *x = GTK_XEMACS (widget);
|
|
258 struct frame *f = GTK_XEMACS_FRAME (x);
|
|
259 int width, height;
|
|
260
|
|
261 if (f)
|
|
262 {
|
|
263 char_to_pixel_size (f, FRAME_WIDTH (f), FRAME_HEIGHT (f),
|
|
264 &width, &height);
|
|
265 requisition->width = width;
|
|
266 requisition->height = height;
|
|
267 }
|
|
268 else
|
|
269 {
|
|
270 parent_class->size_request (widget, requisition);
|
|
271 }
|
|
272 }
|
|
273
|
2168
|
274 /* Assign a size and position to the child widgets. This differs from the
|
|
275 super class method in that for all widgets except the scrollbars the size
|
|
276 and position are not caclulated here. This is because these widgets have
|
|
277 this function performed for them by the redisplay code (see
|
|
278 gtk_map_subwindow()). If the superclass method is called then the widgets
|
|
279 can change size and position as the two pieces of code move the widgets at
|
|
280 random.
|
|
281 */
|
462
|
282 static void
|
|
283 gtk_xemacs_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
|
|
284 {
|
|
285 GtkXEmacs *x = GTK_XEMACS (widget);
|
2168
|
286 GtkFixed *fixed = GTK_FIXED (widget);
|
462
|
287 struct frame *f = GTK_XEMACS_FRAME (x);
|
|
288 int columns, rows;
|
2168
|
289 GList *children;
|
|
290 guint16 border_width;
|
462
|
291
|
2168
|
292 widget->allocation = *allocation;
|
|
293 if (GTK_WIDGET_REALIZED (widget))
|
|
294 gdk_window_move_resize (widget->window,
|
|
295 allocation->x,
|
|
296 allocation->y,
|
|
297 allocation->width,
|
|
298 allocation->height);
|
|
299
|
|
300 border_width = GTK_CONTAINER (fixed)->border_width;
|
|
301
|
|
302 children = fixed->children;
|
|
303 while (children)
|
|
304 {
|
2336
|
305 GtkFixedChild* child = (GtkFixedChild*) children->data;
|
2168
|
306 children = children->next;
|
|
307
|
|
308 /*
|
|
309 Scrollbars are the only widget that is managed by GTK. See
|
|
310 comments in gtk_create_scrollbar_instance().
|
|
311 */
|
|
312 if (GTK_WIDGET_VISIBLE (child->widget) &&
|
|
313 gtk_type_is_a(GTK_OBJECT_TYPE(child->widget), GTK_TYPE_SCROLLBAR))
|
|
314 {
|
|
315 GtkAllocation child_allocation;
|
|
316 GtkRequisition child_requisition;
|
|
317
|
|
318 gtk_widget_get_child_requisition (child->widget, &child_requisition);
|
|
319 child_allocation.x = child->x + border_width;
|
|
320 child_allocation.y = child->y + border_width;
|
|
321 child_allocation.width = child_requisition.width;
|
|
322 child_allocation.height = child_requisition.height;
|
|
323 gtk_widget_size_allocate (child->widget, &child_allocation);
|
|
324 }
|
|
325 }
|
462
|
326
|
|
327 if (f)
|
|
328 {
|
|
329 f->pixwidth = allocation->width;
|
|
330 f->pixheight = allocation->height;
|
|
331
|
|
332 pixel_to_char_size (f,
|
|
333 allocation->width,
|
|
334 allocation->height, &columns, &rows);
|
|
335
|
|
336 change_frame_size (f, rows, columns, 1);
|
|
337 }
|
|
338 }
|
|
339
|
|
340 static void
|
|
341 gtk_xemacs_paint (GtkWidget *widget, GdkRectangle *area)
|
|
342 {
|
|
343 GtkXEmacs *x = GTK_XEMACS (widget);
|
|
344 struct frame *f = GTK_XEMACS_FRAME (x);
|
2195
|
345
|
|
346 if (GTK_WIDGET_DRAWABLE (widget))
|
|
347 redisplay_redraw_exposed_area (f, area->x, area->y, area->width,
|
|
348 area->height);
|
462
|
349 }
|
|
350
|
|
351 static void
|
|
352 gtk_xemacs_draw (GtkWidget *widget, GdkRectangle *area)
|
|
353 {
|
|
354 GtkFixed *fixed = GTK_FIXED (widget);
|
|
355 GtkFixedChild *child;
|
|
356 GdkRectangle child_area;
|
|
357 GList *children;
|
|
358
|
|
359 /* I need to manually iterate over the children instead of just
|
|
360 chaining to parent_class->draw() because it calls
|
|
361 gtk_fixed_paint() directly, which clears the background window,
|
|
362 which causes A LOT of flashing. */
|
|
363
|
2195
|
364 if (GTK_WIDGET_DRAWABLE (widget))
|
|
365 {
|
|
366 gtk_xemacs_paint (widget, area);
|
462
|
367
|
2195
|
368 children = fixed->children;
|
462
|
369
|
2195
|
370 while (children)
|
|
371 {
|
|
372 child = (GtkFixedChild*) children->data;
|
|
373 children = children->next;
|
|
374 /* #### This is what causes the scrollbar flickering!
|
|
375 Evidently the scrollbars pretty much take care of drawing
|
|
376 themselves in most cases. Then we come along and tell them
|
|
377 to redraw again!
|
462
|
378
|
2195
|
379 But if we just leave it out, then they do not get drawn
|
|
380 correctly the first time!
|
462
|
381
|
2195
|
382 Scrollbar flickering has been greatly helped by the
|
|
383 optimizations in scrollbar-gtk.c /
|
|
384 gtk_update_scrollbar_instance_status (), so this is not that
|
|
385 big a deal anymore.
|
|
386 */
|
|
387 if (gtk_widget_intersect (child->widget, area, &child_area))
|
|
388 {
|
|
389 gtk_widget_draw (child->widget, &child_area);
|
|
390 }
|
|
391 }
|
|
392 }
|
462
|
393 }
|
|
394
|
|
395 static gint
|
|
396 gtk_xemacs_expose (GtkWidget *widget, GdkEventExpose *event)
|
|
397 {
|
|
398 GtkXEmacs *x = GTK_XEMACS (widget);
|
|
399 struct frame *f = GTK_XEMACS_FRAME (x);
|
|
400 GdkRectangle *a = &event->area;
|
|
401
|
2195
|
402 if (GTK_WIDGET_DRAWABLE (widget))
|
|
403 {
|
|
404 /* This takes care of drawing the scrollbars, etc */
|
|
405 parent_class->expose_event (widget, event);
|
462
|
406
|
2195
|
407 /* Now draw the actual frame data */
|
|
408 if (!check_for_ignored_expose (f, a->x, a->y, a->width, a->height) &&
|
|
409 !find_matching_subwindow (f, a->x, a->y, a->width, a->height))
|
|
410 redisplay_redraw_exposed_area (f, a->x, a->y, a->width, a->height);
|
|
411 return (TRUE);
|
|
412 }
|
462
|
413 }
|
|
414
|
|
415 Lisp_Object
|
2286
|
416 xemacs_gtk_convert_color(GdkColor *c, GtkWidget *UNUSED (w))
|
462
|
417 {
|
|
418 char color_buf[255];
|
|
419
|
|
420 sprintf (color_buf, "#%04x%04x%04x", c->red, c->green, c->blue);
|
|
421
|
|
422 return (build_string (color_buf));
|
|
423 }
|