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