(traverse_intervals): Use less stack space.
[bpt/emacs.git] / src / widget.c
1 /* The emacs frame widget.
2 Copyright (C) 1992, 1993, 2000 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Emacs 19 face widget ported by Fred Pierresteguy */
22
23 /* This file has been censored by the Communications Decency Act.
24 That law was passed under the guise of a ban on pornography, but
25 it bans far more than that. This file did not contain pornography,
26 but it was censored nonetheless.
27
28 For information on US government censorship of the Internet, and
29 what you can do to bring back freedom of the press, see the web
30 site http://www.vtw.org/
31 */
32
33 #include <config.h>
34 #include <stdio.h>
35 #include "lisp.h"
36 #include "xterm.h"
37
38 #include "keyboard.h"
39 #include "frame.h"
40 #include "window.h"
41
42 #include "dispextern.h"
43 #include "blockinput.h"
44
45 #include <X11/StringDefs.h>
46 #include <X11/IntrinsicP.h>
47 #include <X11/cursorfont.h>
48 #include "widgetprv.h"
49 #include <X11/ObjectP.h>
50 #include <X11/Shell.h>
51 #include <X11/ShellP.h>
52 #include "../lwlib/lwlib.h"
53
54 #include <signal.h>
55 #include "syssignal.h"
56
57 #define max(a, b) ((a) > (b) ? (a) : (b))
58
59 /* This sucks: this is the first default that x-faces.el tries. This won't
60 be used unless neither the "Emacs.EmacsFrame" resource nor the
61 "Emacs.EmacsFrame" resource is set; the frame
62 may have the wrong default size if this font doesn't exist, but some other
63 font that x-faces.el does. The workaround is to specify some font in the
64 resource database; I don't know a solution other than duplicating the font-
65 searching code from x-faces.el in this file.
66
67 This also means that if "Emacs.EmacsFrame" is specified as a non-
68 existent font, then Xt is going to substitute "XtDefaultFont" for it,
69 which is a different size than this one. The solution for this is to
70 make x-faces.el try to use XtDefaultFont. The problem with that is that
71 XtDefaultFont is almost certainly variable-width.
72
73 #### Perhaps we could have this code explicitly set XtDefaultFont to this?
74 */
75 #define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
76
77
78 static void EmacsFrameInitialize (/*Widget, Widget, ArgList, Cardinal * */);
79 static void EmacsFrameDestroy (/* Widget */);
80 static void EmacsFrameRealize (/* Widget, XtValueMask*, XSetWindowAttributes* */);
81 void EmacsFrameResize (/* Widget widget */);
82 static Boolean EmacsFrameSetValues (/* Widget, Widget, Widget,
83 ArgList, Cardinal * */);
84 static XtGeometryResult EmacsFrameQueryGeometry (/* Widget, XtWidgetGeometry*,
85 XtWidgetGeometry* */);
86
87
88 #undef XtOffset
89 #define XtOffset(p_type,field) \
90 ((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
91 #define offset(field) XtOffset(EmacsFrame, emacs_frame.field)
92
93 static XtResource resources[] = {
94 {XtNgeometry, XtCGeometry, XtRString, sizeof(String),
95 offset (geometry), XtRString, (XtPointer) 0},
96 {XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
97 offset (iconic), XtRImmediate, (XtPointer) False},
98
99 {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
100 offset (frame), XtRImmediate, 0},
101
102 {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
103 offset (minibuffer), XtRImmediate, (XtPointer)0},
104 {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
105 offset (unsplittable), XtRImmediate, (XtPointer)0},
106 {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
107 offset (internal_border_width), XtRImmediate, (XtPointer)4},
108 {XtNinterline, XtCInterline, XtRInt, sizeof (int),
109 offset (interline), XtRImmediate, (XtPointer)0},
110 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
111 offset(font),XtRString, DEFAULT_FACE_FONT},
112 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
113 offset(foreground_pixel), XtRString, "XtDefaultForeground"},
114 {XtNcursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
115 offset(cursor_color), XtRString, "XtDefaultForeground"},
116 {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
117 offset (bar_cursor), XtRImmediate, (XtPointer)0},
118 {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
119 offset (visual_bell), XtRImmediate, (XtPointer)0},
120 {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
121 offset (bell_volume), XtRImmediate, (XtPointer)0},
122 };
123
124 #undef offset
125
126 /*
127 static XtActionsRec
128 emacsFrameActionsTable [] = {
129 {"keypress", key_press},
130 {"focus_in", emacs_frame_focus_handler},
131 {"focus_out", emacs_frame_focus_handler},
132 };
133
134 static char
135 emacsFrameTranslations [] = "\
136 <KeyPress>: keypress()\n\
137 <FocusIn>: focus_in()\n\
138 <FocusOut>: focus_out()\n\
139 ";
140 */
141
142 EmacsFrameClassRec emacsFrameClassRec = {
143 { /* core fields */
144 /* superclass */ &widgetClassRec,
145 /* class_name */ "EmacsFrame",
146 /* widget_size */ sizeof(EmacsFrameRec),
147 /* class_initialize */ 0,
148 /* class_part_initialize */ 0,
149 /* class_inited */ FALSE,
150 /* initialize */ EmacsFrameInitialize,
151 /* initialize_hook */ 0,
152 /* realize */ EmacsFrameRealize,
153 /* actions */ 0, /*emacsFrameActionsTable*/
154 /* num_actions */ 0, /*XtNumber (emacsFrameActionsTable)*/
155 /* resources */ resources,
156 /* resource_count */ XtNumber(resources),
157 /* xrm_class */ NULLQUARK,
158 /* compress_motion */ TRUE,
159 /* compress_exposure */ TRUE,
160 /* compress_enterleave */ TRUE,
161 /* visible_interest */ FALSE,
162 /* destroy */ EmacsFrameDestroy,
163 /* resize */ EmacsFrameResize,
164 /* expose */ XtInheritExpose,
165 /* set_values */ EmacsFrameSetValues,
166 /* set_values_hook */ 0,
167 /* set_values_almost */ XtInheritSetValuesAlmost,
168 /* get_values_hook */ 0,
169 /* accept_focus */ XtInheritAcceptFocus,
170 /* version */ XtVersion,
171 /* callback_private */ 0,
172 /* tm_table */ 0, /*emacsFrameTranslations*/
173 /* query_geometry */ EmacsFrameQueryGeometry,
174 /* display_accelerator */ XtInheritDisplayAccelerator,
175 /* extension */ 0
176 }
177 };
178
179 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
180
181 static void
182 get_default_char_pixel_size (ew, pixel_width, pixel_height)
183 EmacsFrame ew;
184 int* pixel_width;
185 int* pixel_height;
186 {
187 struct frame* f = ew->emacs_frame.frame;
188 *pixel_width = FONT_WIDTH (f->output_data.x->font);
189 *pixel_height = f->output_data.x->line_height;
190 }
191
192 static void
193 pixel_to_char_size (ew, pixel_width, pixel_height, char_width, char_height)
194 EmacsFrame ew;
195 Dimension pixel_width;
196 Dimension pixel_height;
197 int* char_width;
198 int* char_height;
199 {
200 struct frame* f = ew->emacs_frame.frame;
201 *char_width = PIXEL_TO_CHAR_WIDTH (f, (int) pixel_width);
202 *char_height = PIXEL_TO_CHAR_HEIGHT (f, (int) pixel_height);
203 }
204
205 static void
206 char_to_pixel_size (ew, char_width, char_height, pixel_width, pixel_height)
207 EmacsFrame ew;
208 int char_width;
209 int char_height;
210 Dimension* pixel_width;
211 Dimension* pixel_height;
212 {
213 struct frame* f = ew->emacs_frame.frame;
214 *pixel_width = CHAR_TO_PIXEL_WIDTH (f, char_width);
215 *pixel_height = CHAR_TO_PIXEL_HEIGHT (f, char_height);
216 }
217
218 static void
219 round_size_to_char (ew, in_width, in_height, out_width, out_height)
220 EmacsFrame ew;
221 Dimension in_width;
222 Dimension in_height;
223 Dimension* out_width;
224 Dimension* out_height;
225 {
226 int char_width;
227 int char_height;
228 pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
229 char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
230 }
231
232 static Widget
233 get_wm_shell (w)
234 Widget w;
235 {
236 Widget wmshell;
237
238 for (wmshell = XtParent (w);
239 wmshell && !XtIsWMShell (wmshell);
240 wmshell = XtParent (wmshell));
241
242 return wmshell;
243 }
244
245 #if 0 /* Currently not used. */
246
247 static void
248 mark_shell_size_user_specified (wmshell)
249 Widget wmshell;
250 {
251 if (! XtIsWMShell (wmshell)) abort ();
252 /* This is kind of sleazy, but I can't see how else to tell it to make it
253 mark the WM_SIZE_HINTS size as user specified when appropriate. */
254 ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
255 }
256
257 #endif
258
259
260 /* Can't have static frame locals because of some broken compilers.
261 Normally, initializing a variable like this doesn't work in emacs,
262 but it's ok in this file because it must come after lastfile (and
263 thus have its data not go into text space) because Xt needs to
264 write to initialized data objects too.
265 */
266 #if 0
267 static Boolean first_frame_p = True;
268 #endif
269
270 static void
271 set_frame_size (ew)
272 EmacsFrame ew;
273 {
274 /* The widget hierarchy is
275
276 argv[0] emacsShell pane Frame-NAME
277 ApplicationShell EmacsShell Paned EmacsFrame
278
279 We accept geometry specs in this order:
280
281 *Frame-NAME.geometry
282 *EmacsFrame.geometry
283 Emacs.geometry
284
285 Other possibilities for widget hierarchies might be
286
287 argv[0] frame pane Frame-NAME
288 ApplicationShell EmacsShell Paned EmacsFrame
289 or
290 argv[0] Frame-NAME pane Frame-NAME
291 ApplicationShell EmacsShell Paned EmacsFrame
292 or
293 argv[0] Frame-NAME pane emacsTextPane
294 ApplicationShell EmacsFrame Paned EmacsTextPane
295
296 With the current setup, the text-display-area is the part which is
297 an emacs "frame", since that's the only part managed by emacs proper
298 (the menubar and the parent of the menubar and all that sort of thing
299 are managed by lwlib.)
300
301 The EmacsShell widget is simply a replacement for the Shell widget
302 which is able to deal with using an externally-supplied window instead
303 of always creating its own. It is not actually emacs specific, and
304 should possibly have class "Shell" instead of "EmacsShell" to simplify
305 the resources.
306
307 */
308
309 /* Hairily merged geometry */
310 unsigned int w = ew->emacs_frame.frame->width;
311 unsigned int h = ew->emacs_frame.frame->height;
312
313 Widget wmshell = get_wm_shell ((Widget) ew);
314 /* Each Emacs shell is now independent and top-level. */
315
316 if (! XtIsSubclass (wmshell, shellWidgetClass)) abort ();
317
318 /* We don't need this for the moment. The geometry is computed in
319 xfns.c. */
320 #if 0
321 /* If the EmacsFrame doesn't have a geometry but the shell does,
322 treat that as the geometry of the frame. (Is this bogus?
323 I'm not sure.) */
324 if (ew->emacs_frame.geometry == 0)
325 XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, NULL);
326
327 /* If the Shell is iconic, then the EmacsFrame is iconic. (Is
328 this bogus? I'm not sure.) */
329 if (!ew->emacs_frame.iconic)
330 XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, NULL);
331
332
333 {
334 char *geom = 0;
335 XtVaGetValues (app_shell, XtNgeometry, &geom, NULL);
336 if (geom)
337 app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
338 }
339
340 if (ew->emacs_frame.geometry)
341 frame_flags = XParseGeometry (ew->emacs_frame.geometry,
342 &frame_x, &frame_y,
343 &frame_w, &frame_h);
344
345 if (first_frame_p)
346 {
347 /* If this is the first frame created:
348 ====================================
349
350 - Use the ApplicationShell's size/position, if specified.
351 (This is "Emacs.geometry", or the "-geometry" command line arg.)
352 - Else use the EmacsFrame's size/position.
353 (This is "*Frame-NAME.geometry")
354
355 - If the AppShell is iconic, the frame should be iconic.
356
357 AppShell comes first so that -geometry always applies to the first
358 frame created, even if there is an "every frame" entry in the
359 resource database.
360 */
361 if (app_flags & (XValue | YValue))
362 {
363 x = app_x; y = app_y;
364 flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
365 }
366 else if (frame_flags & (XValue | YValue))
367 {
368 x = frame_x; y = frame_y;
369 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
370 }
371
372 if (app_flags & (WidthValue | HeightValue))
373 {
374 w = app_w; h = app_h;
375 flags |= (app_flags & (WidthValue | HeightValue));
376 }
377 else if (frame_flags & (WidthValue | HeightValue))
378 {
379 w = frame_w; h = frame_h;
380 flags |= (frame_flags & (WidthValue | HeightValue));
381 }
382
383 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
384 if (!ew->emacs_frame.iconic)
385 XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, NULL);
386
387 first_frame_p = False;
388 }
389 else
390 {
391 /* If this is not the first frame created:
392 ========================================
393
394 - use the EmacsFrame's size/position if specified
395 - Otherwise, use the ApplicationShell's size, but not position.
396
397 So that means that one can specify the position of the first frame
398 with "Emacs.geometry" or `-geometry'; but can only specify the
399 position of subsequent frames with "*Frame-NAME.geometry".
400
401 AppShell comes second so that -geometry does not apply to subsequent
402 frames when there is an "every frame" entry in the resource db,
403 but does apply to the first frame.
404 */
405 if (frame_flags & (XValue | YValue))
406 {
407 x = frame_x; y = frame_y;
408 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
409 }
410
411 if (frame_flags & (WidthValue | HeightValue))
412 {
413 w = frame_w; h = frame_h;
414 flags |= (frame_flags & (WidthValue | HeightValue));
415 }
416 else if (app_flags & (WidthValue | HeightValue))
417 {
418 w = app_w;
419 h = app_h;
420 flags |= (app_flags & (WidthValue | HeightValue));
421 }
422 }
423 #endif /* 0 */
424 {
425 struct frame* frame = ew->emacs_frame.frame;
426 Dimension pixel_width, pixel_height;
427
428 /* Take into account the size of the scrollbar. Always use the
429 number of columns occupied by the scroll bar here otherwise we
430 might end up with a frame width that is not a multiple of the
431 frame's character width which is bad for vertically split
432 windows. */
433 frame->output_data.x->vertical_scroll_bar_extra
434 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (frame)
435 ? 0
436 : (FRAME_SCROLL_BAR_COLS (frame)
437 * FONT_WIDTH (frame->output_data.x->font)));
438
439 frame->output_data.x->flags_areas_extra
440 = FRAME_FLAGS_AREA_WIDTH (frame);
441
442 change_frame_size (frame, h, w, 1, 0, 0);
443 char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
444 ew->core.width = pixel_width;
445 ew->core.height = pixel_height;
446
447 #if 0 /* xfns.c takes care of this now. */
448 /* If a position was specified, assign it to the shell widget.
449 (Else WM won't do anything with it.)
450 */
451 if (flags & (XValue | YValue))
452 {
453 /* the tricky things with the sign is to make sure that
454 -0 is printed -0. */
455 int len;
456 char *tem;
457 sprintf (shell_position, "=%c%d%c%d",
458 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
459 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
460 len = strlen (shell_position) + 1;
461 tem = (char *) xmalloc (len);
462 strncpy (tem, shell_position, len);
463 XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
464 }
465 else if (flags & (WidthValue | HeightValue))
466 {
467 int len;
468 char *tem;
469 sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
470 len = strlen (shell_position) + 1;
471 tem = (char *) xmalloc (len);
472 strncpy (tem, shell_position, len);
473 XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
474 }
475
476 /* If the geometry spec we're using has W/H components, mark the size
477 in the WM_SIZE_HINTS as user specified. */
478 if (flags & (WidthValue | HeightValue))
479 mark_shell_size_user_specified (wmshell);
480
481 /* Also assign the iconic status of the frame to the Shell, so that
482 the WM sees it. */
483 XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, NULL);
484 #endif /* 0 */
485 }
486 }
487
488 /* Nonzero tells update_wm_hints not to do anything
489 (the caller should call update_wm_hints explicitly later.) */
490 int update_hints_inhibit;
491
492 static void
493 update_wm_hints (ew)
494 EmacsFrame ew;
495 {
496 Widget wmshell = get_wm_shell ((Widget)ew);
497 int cw;
498 int ch;
499 Dimension rounded_width;
500 Dimension rounded_height;
501 int char_width;
502 int char_height;
503 int base_width;
504 int base_height;
505 int min_rows = 0, min_cols = 0;
506
507 if (update_hints_inhibit)
508 return;
509
510 #if 0
511 check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
512 #endif
513
514 pixel_to_char_size (ew, ew->core.width, ew->core.height,
515 &char_width, &char_height);
516 char_to_pixel_size (ew, char_width, char_height,
517 &rounded_width, &rounded_height);
518 get_default_char_pixel_size (ew, &cw, &ch);
519
520 base_width = (wmshell->core.width - ew->core.width
521 + (rounded_width - (char_width * cw)));
522 base_height = (wmshell->core.height - ew->core.height
523 + (rounded_height - (char_height * ch)));
524
525 /* This is kind of sleazy, but I can't see how else to tell it to
526 make it mark the WM_SIZE_HINTS size as user specified.
527 */
528 /* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
529
530 XtVaSetValues (wmshell,
531 XtNbaseWidth, (XtArgVal) base_width,
532 XtNbaseHeight, (XtArgVal) base_height,
533 XtNwidthInc, (XtArgVal) cw,
534 XtNheightInc, (XtArgVal) ch,
535 XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
536 XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
537 NULL);
538 }
539
540 #if 0
541
542 static void
543 create_frame_gcs (ew)
544 EmacsFrame ew;
545 {
546 struct frame *s = ew->emacs_frame.frame;
547
548 s->output_data.x->normal_gc
549 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
550 (unsigned long)0, (XGCValues *)0);
551 s->output_data.x->reverse_gc
552 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
553 (unsigned long)0, (XGCValues *)0);
554 s->output_data.x->cursor_gc
555 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
556 (unsigned long)0, (XGCValues *)0);
557 s->output_data.x->black_relief.gc = 0;
558 s->output_data.x->white_relief.gc = 0;
559 }
560
561 #endif /* 0 */
562
563 static char setup_frame_cursor_bits[] =
564 {
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
569 };
570
571 static void
572 setup_frame_gcs (ew)
573 EmacsFrame ew;
574 {
575 XGCValues gc_values;
576 struct frame* s = ew->emacs_frame.frame;
577 Pixmap blank_stipple, blank_tile;
578
579 /* We have to initialize all of our GCs to have a stipple/tile, otherwise
580 XGetGCValues returns uninitialized data when we query the stipple
581 (instead of None or something sensible) and it makes things hard.
582
583 This should be fixed for real by not querying the GCs but instead having
584 some GC-based cache instead of the current face-based cache which doesn't
585 effectively cache all of the GC settings we need to use.
586 */
587
588 blank_stipple
589 = XCreateBitmapFromData (XtDisplay (ew),
590 RootWindowOfScreen (XtScreen (ew)),
591 setup_frame_cursor_bits, 2, 2);
592
593 /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
594 never actually get used as a background tile!
595 */
596 blank_tile
597 = XCreatePixmapFromBitmapData (XtDisplay(ew),
598 RootWindowOfScreen (XtScreen (ew)),
599 setup_frame_cursor_bits, 2, 2,
600 (unsigned long)0, (unsigned long)1,
601 ew->core.depth);
602
603 /* Normal video */
604 gc_values.font = ew->emacs_frame.font->fid;
605 gc_values.foreground = ew->emacs_frame.foreground_pixel;
606 gc_values.background = ew->core.background_pixel;
607 gc_values.graphics_exposures = False;
608 gc_values.stipple = blank_stipple;
609 gc_values.tile = blank_tile;
610 XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
611 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
612 | GCStipple | GCTile),
613 &gc_values);
614
615 /* Reverse video style. */
616 gc_values.font = ew->emacs_frame.font->fid;
617 gc_values.foreground = ew->core.background_pixel;
618 gc_values.background = ew->emacs_frame.foreground_pixel;
619 gc_values.graphics_exposures = False;
620 gc_values.stipple = blank_stipple;
621 gc_values.tile = blank_tile;
622 XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
623 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
624 | GCStipple | GCTile),
625 &gc_values);
626
627 /* Cursor has to have an empty stipple. */
628 gc_values.font = ew->emacs_frame.font->fid;
629 gc_values.foreground = ew->core.background_pixel;
630 gc_values.background = ew->emacs_frame.cursor_color;
631 gc_values.graphics_exposures = False;
632 gc_values.tile = blank_tile;
633 gc_values.stipple
634 = XCreateBitmapFromData (XtDisplay (ew),
635 RootWindowOfScreen (XtScreen (ew)),
636 setup_frame_cursor_bits, 16, 16);
637 XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
638 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
639 | GCStipple | GCTile),
640 &gc_values);
641 }
642
643 static void
644 update_various_frame_slots (ew)
645 EmacsFrame ew;
646 {
647 struct x_output *x = ew->emacs_frame.frame->output_data.x;
648 x->pixel_height = ew->core.height + x->menubar_height;
649 x->pixel_width = ew->core.width;
650 x->internal_border_width = ew->emacs_frame.internal_border_width;
651
652 }
653
654 static void
655 update_from_various_frame_slots (ew)
656 EmacsFrame ew;
657 {
658 struct x_output *x = ew->emacs_frame.frame->output_data.x;
659 ew->core.height = x->pixel_height - x->menubar_height;
660 ew->core.width = x->pixel_width;
661 ew->core.background_pixel = x->background_pixel;
662 ew->emacs_frame.internal_border_width = x->internal_border_width;
663 ew->emacs_frame.font = x->font;
664 ew->emacs_frame.foreground_pixel = x->foreground_pixel;
665 ew->emacs_frame.cursor_color = x->cursor_pixel;
666 ew->core.border_pixel = x->border_pixel;
667 }
668
669 static void
670 EmacsFrameInitialize (request, new, dum1, dum2)
671 Widget request;
672 Widget new;
673 ArgList dum1;
674 Cardinal *dum2;
675 {
676 EmacsFrame ew = (EmacsFrame)new;
677
678 if (!ew->emacs_frame.frame)
679 {
680 fprintf (stderr,
681 "can't create an emacs frame widget without a frame\n");
682 exit (1);
683 }
684
685 #if 0 /* done in xfns.c */
686 /* If the "Emacs.EmacsFrame.{default,Face}.{attributeFont,AttributeFont}"
687 resource is set, then it always overrides "Emacs.EmacsFrame.{font,Font}".
688 It's unfortunate that we have to do this, but we need to know the font
689 size for frame-sizing purposes before the faces get initialized. If
690 the "default.attributeFont" isn't set, then we use the font of this
691 EmacsFrame itself, defaulting to XtDefaultFont. Up in the lisp code,
692 the "default" face will use the frame's font if its own is not set,
693 so everything stays in sync -- it's not possible for the frame's font
694 and the default face's font to be different.
695 */
696 {
697 XFontStruct *f = 0;
698 XtResource face_res;
699 face_res.resource_name = "attributeFont";
700 face_res.resource_class = "AttributeFont";
701 face_res.resource_type = XtRFontStruct;
702 face_res.resource_size = sizeof (XFontStruct *);
703 face_res.resource_offset = 0;
704 face_res.default_type = XtRImmediate;
705 face_res.default_addr = 0;
706 XtGetSubresources ((Widget) ew, (XtPointer) &f, "default", "Face",
707 &face_res, 1, NULL, 0);
708
709 if (f)
710 ew->emacs_frame.font = f;
711 else if (! ew->emacs_frame.font)
712 {
713 fprintf (stderr, "emacs frame widget could not load a font\n");
714 exit (1);
715 }
716 }
717
718 /* Update the font field in frame */
719 ew->emacs_frame.frame->output_data.x->font = ew->emacs_frame.font;
720 #endif
721
722 update_from_various_frame_slots (ew);
723 set_frame_size (ew);
724 /*create_frame_gcs (ew);
725 setup_frame_gcs (ew);
726 update_various_frame_slots (ew); */
727 }
728
729
730 static void
731 EmacsFrameRealize (widget, mask, attrs)
732 Widget widget;
733 XtValueMask *mask;
734 XSetWindowAttributes *attrs;
735 {
736 EmacsFrame ew = (EmacsFrame)widget;
737
738 /* This used to contain SubstructureRedirectMask, but this turns out
739 to be a problem with XIM on Solaris, and events from that mask
740 don't seem to be used. Let's check that. */
741 attrs->event_mask = (STANDARD_EVENT_SET
742 | PropertyChangeMask
743 | SubstructureNotifyMask);
744 *mask |= CWEventMask;
745 XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
746 attrs);
747 update_wm_hints (ew);
748 }
749
750 extern void free_frame_faces (/* struct frame * */);
751
752 static void
753 EmacsFrameDestroy (widget)
754 Widget widget;
755 {
756 EmacsFrame ew = (EmacsFrame) widget;
757 struct frame* s = ew->emacs_frame.frame;
758
759 if (! s) abort ();
760 if (! s->output_data.x) abort ();
761 if (! s->output_data.x->normal_gc) abort ();
762
763 BLOCK_INPUT;
764 x_free_gcs (s);
765 if (s->output_data.x->white_relief.gc)
766 XFreeGC (XtDisplay (widget), s->output_data.x->white_relief.gc);
767 if (s->output_data.x->black_relief.gc)
768 XFreeGC (XtDisplay (widget), s->output_data.x->black_relief.gc);
769 UNBLOCK_INPUT;
770 }
771
772 void
773 EmacsFrameResize (widget)
774 Widget widget;
775 {
776 EmacsFrame ew = (EmacsFrame)widget;
777 struct frame *f = ew->emacs_frame.frame;
778 int columns;
779 int rows;
780
781 pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
782 change_frame_size (f, rows, columns, 0, 1, 0);
783 update_wm_hints (ew);
784 update_various_frame_slots (ew);
785
786 cancel_mouse_face (f);
787 }
788
789 static Boolean
790 EmacsFrameSetValues (cur_widget, req_widget, new_widget, dum1, dum2)
791 Widget cur_widget;
792 Widget req_widget;
793 Widget new_widget;
794 ArgList dum1;
795 Cardinal *dum2;
796 {
797 EmacsFrame cur = (EmacsFrame)cur_widget;
798 EmacsFrame new = (EmacsFrame)new_widget;
799
800 Boolean needs_a_refresh = False;
801 Boolean has_to_recompute_size;
802 Boolean has_to_recompute_gcs;
803 Boolean has_to_update_hints;
804
805 int char_width, char_height;
806 Dimension pixel_width;
807 Dimension pixel_height;
808
809 has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
810 || (cur->emacs_frame.foreground_pixel
811 != new->emacs_frame.foreground_pixel)
812 || (cur->core.background_pixel
813 != new->core.background_pixel)
814 );
815
816 has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
817 && cur->core.width == new->core.width
818 && cur->core.height == new->core.height);
819
820 has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);
821
822 if (has_to_recompute_gcs)
823 {
824 setup_frame_gcs (new);
825 needs_a_refresh = True;
826 }
827
828 if (has_to_recompute_size)
829 {
830 pixel_width = new->core.width;
831 pixel_height = new->core.height;
832 pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
833 &char_height);
834 char_to_pixel_size (new, char_width, char_height, &pixel_width,
835 &pixel_height);
836 new->core.width = pixel_width;
837 new->core.height = pixel_height;
838
839 change_frame_size (new->emacs_frame.frame, char_height, char_width,
840 1, 0, 0);
841 needs_a_refresh = True;
842 }
843
844 if (has_to_update_hints)
845 update_wm_hints (new);
846
847 update_various_frame_slots (new);
848
849 /* #### This doesn't work, I haven't been able to find ANY kludge that
850 will let (x-create-frame '((iconic . t))) work. It seems that changes
851 to wm_shell's iconic slot have no effect after it has been realized,
852 and calling XIconifyWindow doesn't work either (even though the window
853 has been created.) Perhaps there is some property we could smash
854 directly, but I'm sick of this for now.
855 */
856 if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
857 {
858 Widget wmshell = get_wm_shell ((Widget) cur);
859 XtVaSetValues (wmshell, XtNiconic,
860 (XtArgVal) new->emacs_frame.iconic, NULL);
861 }
862
863 return needs_a_refresh;
864 }
865
866 static XtGeometryResult
867 EmacsFrameQueryGeometry (widget, request, result)
868 Widget widget;
869 XtWidgetGeometry* request;
870 XtWidgetGeometry* result;
871 {
872 EmacsFrame ew = (EmacsFrame)widget;
873
874 int mask = request->request_mode;
875 Dimension ok_width, ok_height;
876
877 if (mask & (CWWidth | CWHeight))
878 {
879 round_size_to_char (ew,
880 (mask & CWWidth) ? request->width : ew->core.width,
881 ((mask & CWHeight) ? request->height
882 : ew->core.height),
883 &ok_width, &ok_height);
884 if ((mask & CWWidth) && (ok_width != request->width))
885 {
886 result->request_mode |= CWWidth;
887 result->width = ok_width;
888 }
889 if ((mask & CWHeight) && (ok_height != request->height))
890 {
891 result->request_mode |= CWHeight;
892 result->height = ok_height;
893 }
894 }
895 return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
896 }
897
898 /* Special entrypoints */
899 void
900 EmacsFrameSetCharSize (widget, columns, rows)
901 Widget widget;
902 int columns;
903 int rows;
904 {
905 EmacsFrame ew = (EmacsFrame) widget;
906 Dimension pixel_width, pixel_height;
907 struct frame *f = ew->emacs_frame.frame;
908
909 if (columns < 3) columns = 3; /* no way buddy */
910
911 check_frame_size (f, &rows, &columns);
912 f->output_data.x->vertical_scroll_bar_extra
913 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
914 ? 0
915 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
916
917 f->output_data.x->flags_areas_extra
918 = FRAME_FLAGS_AREA_WIDTH (f);
919
920 char_to_pixel_size (ew, columns, rows, &pixel_width, &pixel_height);
921
922 #if 0 /* This doesn't seem to be right. The frame gets too wide. --gerd. */
923 /* Something is really strange here wrt to the border width:
924 Apparently, XtNwidth and XtNheight include the border, so we have
925 to add it here. But the XtNborderWidth set for the widgets has
926 no similarity to what f->output_data.x->border_width is set to. */
927 XtVaGetValues (widget, XtNborderWidth, &border_width, NULL);
928 pixel_height += 2 * border_width;
929 pixel_width += 2 * border_width;
930 #endif
931
932 /* Manually change the height and width of all our widgets,
933 adjusting each widget by the same increments. */
934 if (ew->core.width != pixel_width
935 || ew->core.height != pixel_height)
936 {
937 int hdelta = pixel_height - ew->core.height;
938 int wdelta = pixel_width - ew->core.width;
939 int column_widget_height = f->output_data.x->column_widget->core.height;
940 int column_widget_width = f->output_data.x->column_widget->core.width;
941 int outer_widget_height = f->output_data.x->widget->core.height;
942 int outer_widget_width = f->output_data.x->widget->core.width;
943 int old_left = f->output_data.x->widget->core.x;
944 int old_top = f->output_data.x->widget->core.y;
945
946 /* Input is blocked here, and Xt waits for some event to
947 occur. */
948
949 lw_refigure_widget (f->output_data.x->column_widget, False);
950 update_hints_inhibit = 1;
951
952 /* Xt waits for a ConfigureNotify event from the window manager
953 in EmacsFrameSetCharSize when the shell widget is resized.
954 For some window managers like fvwm2 2.2.5 and KDE 2.1 this
955 event doesn't arrive for an unknown reason and Emacs hangs in
956 Xt when the default font is changed. Tell Xt not to wait,
957 depending on the value of the frame parameter
958 `wait-for-wm'. */
959 XtVaSetValues (f->output_data.x->widget,
960 XtNwaitForWm, (XtArgVal) f->output_data.x->wait_for_wm,
961 NULL);
962
963 /* Workaround: When a SIGIO or SIGALRM occurs while Xt is
964 waiting for a ConfigureNotify event (see above), this leads
965 to Xt waiting indefinitely instead of using its default
966 timeout (5 seconds). */
967 turn_on_atimers (0);
968 #ifdef SIGIO
969 sigblock (sigmask (SIGIO));
970 #endif
971
972 /* Do parents first, otherwise LessTif's geometry management
973 enters an infinite loop (as of 2000-01-15). This is fixed in
974 later versions of LessTif (as of 2001-03-13); I'll leave it
975 as is because I think it can't do any harm. */
976 XtVaSetValues (f->output_data.x->widget,
977 XtNheight, (XtArgVal) (outer_widget_height + hdelta),
978 XtNwidth, (XtArgVal) (outer_widget_width + wdelta),
979 NULL);
980 XtVaSetValues (f->output_data.x->column_widget,
981 XtNheight, (XtArgVal) (column_widget_height + hdelta),
982 XtNwidth, (XtArgVal) column_widget_width + wdelta,
983 NULL);
984 XtVaSetValues ((Widget) ew,
985 XtNheight, (XtArgVal) pixel_height,
986 XtNwidth, (XtArgVal) pixel_width,
987 NULL);
988 #ifdef SIGIO
989 sigunblock (sigmask (SIGIO));
990 #endif
991 turn_on_atimers (1);
992
993 lw_refigure_widget (f->output_data.x->column_widget, True);
994
995 update_hints_inhibit = 0;
996 update_wm_hints (ew);
997
998 /* These seem to get clobbered. I don't know why. - rms. */
999 f->output_data.x->widget->core.x = old_left;
1000 f->output_data.x->widget->core.y = old_top;
1001 }
1002
1003 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
1004 receive in the ConfigureNotify event; if we get what we asked
1005 for, then the event won't cause the screen to become garbaged, so
1006 we have to make sure to do it here. */
1007 SET_FRAME_GARBAGED (f);
1008 }
1009
1010 \f
1011 void
1012 widget_store_internal_border (widget)
1013 Widget widget;
1014 {
1015 EmacsFrame ew = (EmacsFrame) widget;
1016 FRAME_PTR f = ew->emacs_frame.frame;
1017
1018 ew->emacs_frame.internal_border_width
1019 = f->output_data.x->internal_border_width;
1020 }