Update FSF's address in the preamble.
[bpt/emacs.git] / src / widget.c
1 /* The emacs frame widget.
2 Copyright (C) 1992, 1993 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 #include <config.h>
24 #include <stdio.h>
25 #include "lisp.h"
26 #include "xterm.h"
27
28 #include "frame.h"
29
30 #include "dispextern.h"
31 #include "blockinput.h"
32
33 #include <X11/StringDefs.h>
34 #include <X11/IntrinsicP.h>
35 #include <X11/cursorfont.h>
36 #include "widgetprv.h"
37 #include <X11/ObjectP.h>
38 #include <X11/Shell.h>
39 #include <X11/ShellP.h>
40 #include "../lwlib/lwlib.h"
41
42 #define max(a, b) ((a) > (b) ? (a) : (b))
43
44 /* This sucks: this is the first default that x-faces.el tries. This won't
45 be used unless neither the "Emacs.EmacsFrame" resource nor the
46 "Emacs.EmacsFrame" resource is set; the frame
47 may have the wrong default size if this font doesn't exist, but some other
48 font that x-faces.el does. The workaround is to specify some font in the
49 resource database; I don't know a solution other than duplicating the font-
50 searching code from x-faces.el in this file.
51
52 This also means that if "Emacs.EmacsFrame" is specified as a non-
53 existent font, then Xt is going to substitute "XtDefaultFont" for it,
54 which is a different size than this one. The solution for this is to
55 make x-faces.el try to use XtDefaultFont. The problem with that is that
56 XtDefaultFont is almost certainly variable-width.
57
58 #### Perhaps we could have this code explicitly set XtDefaultFont to this?
59 */
60 #define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
61
62
63 static void EmacsFrameInitialize (/*Widget, Widget, ArgList, Cardinal * */);
64 static void EmacsFrameDestroy (/* Widget */);
65 static void EmacsFrameRealize (/* Widget, XtValueMask*, XSetWindowAttributes* */);
66 void EmacsFrameResize (/* Widget widget */);
67 static Boolean EmacsFrameSetValues (/* Widget, Widget, Widget,
68 ArgList, Cardinal * */);
69 static XtGeometryResult EmacsFrameQueryGeometry (/* Widget, XtWidgetGeometry*,
70 XtWidgetGeometry* */);
71
72
73 #undef XtOffset
74 #define XtOffset(p_type,field) \
75 ((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
76 #define offset(field) XtOffset(EmacsFrame, emacs_frame.field)
77
78 static XtResource resources[] = {
79 {XtNgeometry, XtCGeometry, XtRString, sizeof(String),
80 offset (geometry), XtRString, (XtPointer) 0},
81 {XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
82 offset (iconic), XtRImmediate, (XtPointer) False},
83
84 {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
85 offset (frame), XtRImmediate, 0},
86
87 {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
88 offset (minibuffer), XtRImmediate, (XtPointer)0},
89 {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
90 offset (unsplittable), XtRImmediate, (XtPointer)0},
91 {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
92 offset (internal_border_width), XtRImmediate, (XtPointer)4},
93 {XtNinterline, XtCInterline, XtRInt, sizeof (int),
94 offset (interline), XtRImmediate, (XtPointer)0},
95 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
96 offset(font),XtRString, DEFAULT_FACE_FONT},
97 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
98 offset(foreground_pixel), XtRString, "XtDefaultForeground"},
99 {XtNcursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
100 offset(cursor_color), XtRString, "XtDefaultForeground"},
101 {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
102 offset (bar_cursor), XtRImmediate, (XtPointer)0},
103 {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
104 offset (visual_bell), XtRImmediate, (XtPointer)0},
105 {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
106 offset (bell_volume), XtRImmediate, (XtPointer)0},
107 };
108
109 #undef offset
110
111 /*
112 static XtActionsRec
113 emacsFrameActionsTable [] = {
114 {"keypress", key_press},
115 {"focus_in", emacs_frame_focus_handler},
116 {"focus_out", emacs_frame_focus_handler},
117 };
118
119 static char
120 emacsFrameTranslations [] = "\
121 <KeyPress>: keypress()\n\
122 <FocusIn>: focus_in()\n\
123 <FocusOut>: focus_out()\n\
124 ";
125 */
126
127 EmacsFrameClassRec emacsFrameClassRec = {
128 { /* core fields */
129 /* superclass */ &widgetClassRec,
130 /* class_name */ "EmacsFrame",
131 /* widget_size */ sizeof(EmacsFrameRec),
132 /* class_initialize */ 0,
133 /* class_part_initialize */ 0,
134 /* class_inited */ FALSE,
135 /* initialize */ EmacsFrameInitialize,
136 /* initialize_hook */ 0,
137 /* realize */ EmacsFrameRealize,
138 /* actions */ 0, /*emacsFrameActionsTable*/
139 /* num_actions */ 0, /*XtNumber (emacsFrameActionsTable)*/
140 /* resources */ resources,
141 /* resource_count */ XtNumber(resources),
142 /* xrm_class */ NULLQUARK,
143 /* compress_motion */ TRUE,
144 /* compress_exposure */ TRUE,
145 /* compress_enterleave */ TRUE,
146 /* visible_interest */ FALSE,
147 /* destroy */ EmacsFrameDestroy,
148 /* resize */ EmacsFrameResize,
149 /* expose */ XtInheritExpose,
150 /* set_values */ EmacsFrameSetValues,
151 /* set_values_hook */ 0,
152 /* set_values_almost */ XtInheritSetValuesAlmost,
153 /* get_values_hook */ 0,
154 /* accept_focus */ XtInheritAcceptFocus,
155 /* version */ XtVersion,
156 /* callback_private */ 0,
157 /* tm_table */ 0, /*emacsFrameTranslations*/
158 /* query_geometry */ EmacsFrameQueryGeometry,
159 /* display_accelerator */ XtInheritDisplayAccelerator,
160 /* extension */ 0
161 }
162 };
163
164 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
165
166 static void
167 get_default_char_pixel_size (ew, pixel_width, pixel_height)
168 EmacsFrame ew;
169 int* pixel_width;
170 int* pixel_height;
171 {
172 struct frame* f = ew->emacs_frame.frame;
173 *pixel_width = FONT_WIDTH (f->output_data.x->font);
174 *pixel_height = f->output_data.x->line_height;
175 }
176
177 static void
178 pixel_to_char_size (ew, pixel_width, pixel_height, char_width, char_height)
179 EmacsFrame ew;
180 Dimension pixel_width;
181 Dimension pixel_height;
182 int* char_width;
183 int* char_height;
184 {
185 struct frame* f = ew->emacs_frame.frame;
186 *char_width = PIXEL_TO_CHAR_WIDTH (f, pixel_width);
187 *char_height = PIXEL_TO_CHAR_HEIGHT (f, pixel_height);
188 }
189
190 static void
191 char_to_pixel_size (ew, char_width, char_height, pixel_width, pixel_height)
192 EmacsFrame ew;
193 int char_width;
194 int char_height;
195 Dimension* pixel_width;
196 Dimension* pixel_height;
197 {
198 struct frame* f = ew->emacs_frame.frame;
199 *pixel_width = CHAR_TO_PIXEL_WIDTH (f, char_width);
200 *pixel_height = CHAR_TO_PIXEL_HEIGHT (f, char_height);
201 }
202
203 static void
204 round_size_to_char (ew, in_width, in_height, out_width, out_height)
205 EmacsFrame ew;
206 Dimension in_width;
207 Dimension in_height;
208 Dimension* out_width;
209 Dimension* out_height;
210 {
211 int char_width;
212 int char_height;
213 pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
214 char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
215 }
216
217 static Widget
218 get_wm_shell (w)
219 Widget w;
220 {
221 Widget wmshell;
222
223 for (wmshell = XtParent (w);
224 wmshell && !XtIsWMShell (wmshell);
225 wmshell = XtParent (wmshell));
226
227 return wmshell;
228 }
229
230 static void
231 mark_shell_size_user_specified (wmshell)
232 Widget wmshell;
233 {
234 if (! XtIsWMShell (wmshell)) abort ();
235 /* This is kind of sleazy, but I can't see how else to tell it to make it
236 mark the WM_SIZE_HINTS size as user specified when appropriate. */
237 ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
238 }
239
240
241 /* Can't have static frame locals because of some broken compilers.
242 Normally, initializing a variable like this doesn't work in emacs,
243 but it's ok in this file because it must come after lastfile (and
244 thus have its data not go into text space) because Xt needs to
245 write to initialized data objects too.
246 */
247 static Boolean first_frame_p = True;
248
249 static void
250 set_frame_size (ew)
251 EmacsFrame ew;
252 {
253 /* The widget hierarchy is
254
255 argv[0] emacsShell pane Frame-NAME
256 ApplicationShell EmacsShell Paned EmacsFrame
257
258 We accept geometry specs in this order:
259
260 *Frame-NAME.geometry
261 *EmacsFrame.geometry
262 Emacs.geometry
263
264 Other possibilities for widget hierarchies might be
265
266 argv[0] frame pane Frame-NAME
267 ApplicationShell EmacsShell Paned EmacsFrame
268 or
269 argv[0] Frame-NAME pane Frame-NAME
270 ApplicationShell EmacsShell Paned EmacsFrame
271 or
272 argv[0] Frame-NAME pane emacsTextPane
273 ApplicationShell EmacsFrame Paned EmacsTextPane
274
275 With the current setup, the text-display-area is the part which is
276 an emacs "frame", since that's the only part managed by emacs proper
277 (the menubar and the parent of the menubar and all that sort of thing
278 are managed by lwlib.)
279
280 The EmacsShell widget is simply a replacement for the Shell widget
281 which is able to deal with using an externally-supplied window instead
282 of always creating its own. It is not actually emacs specific, and
283 should possibly have class "Shell" instead of "EmacsShell" to simplify
284 the resources.
285
286 */
287
288 /* Geometry of the AppShell */
289 int app_flags = 0;
290 int app_x = 0;
291 int app_y = 0;
292 unsigned int app_w = 0;
293 unsigned int app_h = 0;
294
295 /* Geometry of the EmacsFrame */
296 int frame_flags = 0;
297 int frame_x = 0;
298 int frame_y = 0;
299 unsigned int frame_w = 0;
300 unsigned int frame_h = 0;
301
302 /* Hairily merged geometry */
303 int x = 0;
304 int y = 0;
305 unsigned int w = ew->emacs_frame.frame->width;
306 unsigned int h = ew->emacs_frame.frame->height;
307 int flags = 0;
308
309 Widget wmshell = get_wm_shell ((Widget) ew);
310 /* Each Emacs shell is now independent and top-level. */
311 Widget app_shell = wmshell;
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, 0);
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, 0);
328
329
330 {
331 char *geom = 0;
332 XtVaGetValues (app_shell, XtNgeometry, &geom, 0);
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, 0);
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* frame = ew->emacs_frame.frame;
423 Dimension pixel_width, pixel_height;
424 char shell_position [32];
425
426 /* Take into account the size of the scrollbar */
427 frame->output_data.x->vertical_scroll_bar_extra
428 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (frame)
429 ? 0
430 : FRAME_SCROLL_BAR_PIXEL_WIDTH (frame) > 0
431 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (frame)
432 : (FRAME_SCROLL_BAR_COLS (frame)
433 * FONT_WIDTH (frame->output_data.x->font)));
434
435 change_frame_size (frame, h, w, 1, 0);
436 char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
437 ew->core.width = pixel_width;
438 ew->core.height = pixel_height;
439
440 #if 0 /* xfns.c takes care of this now. */
441 /* If a position was specified, assign it to the shell widget.
442 (Else WM won't do anything with it.)
443 */
444 if (flags & (XValue | YValue))
445 {
446 /* the tricky things with the sign is to make sure that
447 -0 is printed -0. */
448 int len;
449 char *tem;
450 sprintf (shell_position, "=%c%d%c%d",
451 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
452 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
453 len = strlen (shell_position) + 1;
454 tem = (char *) xmalloc (len);
455 strncpy (tem, shell_position, len);
456 XtVaSetValues (wmshell, XtNgeometry, tem, 0);
457 }
458 else if (flags & (WidthValue | HeightValue))
459 {
460 int len;
461 char *tem;
462 sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
463 len = strlen (shell_position) + 1;
464 tem = (char *) xmalloc (len);
465 strncpy (tem, shell_position, len);
466 XtVaSetValues (wmshell, XtNgeometry, tem, 0);
467 }
468
469 /* If the geometry spec we're using has W/H components, mark the size
470 in the WM_SIZE_HINTS as user specified. */
471 if (flags & (WidthValue | HeightValue))
472 mark_shell_size_user_specified (wmshell);
473
474 /* Also assign the iconic status of the frame to the Shell, so that
475 the WM sees it. */
476 XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, 0);
477 #endif /* 0 */
478 }
479 }
480
481 /* Nonzero tells update_wm_hints not to do anything
482 (the caller should call update_wm_hints explicitly later.) */
483 int update_hints_inhibit;
484
485 static void
486 update_wm_hints (ew)
487 EmacsFrame ew;
488 {
489 Widget wmshell = get_wm_shell ((Widget)ew);
490 int cw;
491 int ch;
492 Dimension rounded_width;
493 Dimension rounded_height;
494 int char_width;
495 int char_height;
496 int base_width;
497 int base_height;
498 int min_rows = 0, min_cols = 0;
499
500 if (update_hints_inhibit)
501 return;
502
503 #if 0
504 check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
505 #endif
506
507 pixel_to_char_size (ew, ew->core.width, ew->core.height,
508 &char_width, &char_height);
509 char_to_pixel_size (ew, char_width, char_height,
510 &rounded_width, &rounded_height);
511 get_default_char_pixel_size (ew, &cw, &ch);
512
513 base_width = (wmshell->core.width - ew->core.width
514 + (rounded_width - (char_width * cw)));
515 base_height = (wmshell->core.height - ew->core.height
516 + (rounded_height - (char_height * ch)));
517
518 /* This is kind of sleazy, but I can't see how else to tell it to
519 make it mark the WM_SIZE_HINTS size as user specified.
520 */
521 /* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
522
523 XtVaSetValues (wmshell,
524 XtNbaseWidth, base_width,
525 XtNbaseHeight, base_height,
526 XtNwidthInc, cw,
527 XtNheightInc, ch,
528 XtNminWidth, base_width + min_cols * cw,
529 XtNminHeight, base_height + min_rows * ch,
530 0);
531 }
532
533 static void
534 create_frame_gcs (ew)
535 EmacsFrame ew;
536 {
537 struct frame *s = ew->emacs_frame.frame;
538
539 s->output_data.x->normal_gc
540 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
541 (unsigned long)0, (XGCValues *)0);
542 s->output_data.x->reverse_gc
543 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
544 (unsigned long)0, (XGCValues *)0);
545 s->output_data.x->cursor_gc
546 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
547 (unsigned long)0, (XGCValues *)0);
548 }
549
550 static char setup_frame_cursor_bits[] =
551 {
552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
556 };
557
558 static void
559 setup_frame_gcs (ew)
560 EmacsFrame ew;
561 {
562 XGCValues gc_values;
563 struct frame* s = ew->emacs_frame.frame;
564 Pixmap blank_stipple, blank_tile;
565
566 /* We have to initialize all of our GCs to have a stipple/tile, otherwise
567 XGetGCValues returns uninitialized data when we query the stipple
568 (instead of None or something sensible) and it makes things hard.
569
570 This should be fixed for real by not querying the GCs but instead having
571 some GC-based cache instead of the current face-based cache which doesn't
572 effectively cache all of the GC settings we need to use.
573 */
574
575 blank_stipple
576 = XCreateBitmapFromData (XtDisplay (ew),
577 RootWindowOfScreen (XtScreen (ew)),
578 setup_frame_cursor_bits, 2, 2);
579
580 /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
581 never actually get used as a background tile!
582 */
583 blank_tile
584 = XCreatePixmapFromBitmapData (XtDisplay(ew),
585 RootWindowOfScreen (XtScreen (ew)),
586 setup_frame_cursor_bits, 2, 2,
587 (unsigned long)0, (unsigned long)1,
588 ew->core.depth);
589
590 /* Normal video */
591 gc_values.font = ew->emacs_frame.font->fid;
592 gc_values.foreground = ew->emacs_frame.foreground_pixel;
593 gc_values.background = ew->core.background_pixel;
594 gc_values.graphics_exposures = False;
595 gc_values.stipple = blank_stipple;
596 gc_values.tile = blank_tile;
597 XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
598 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
599 | GCStipple | GCTile),
600 &gc_values);
601
602 /* Reverse video style. */
603 gc_values.font = ew->emacs_frame.font->fid;
604 gc_values.foreground = ew->core.background_pixel;
605 gc_values.background = ew->emacs_frame.foreground_pixel;
606 gc_values.graphics_exposures = False;
607 gc_values.stipple = blank_stipple;
608 gc_values.tile = blank_tile;
609 XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
610 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
611 | GCStipple | GCTile),
612 &gc_values);
613
614 /* Cursor has to have an empty stipple. */
615 gc_values.font = ew->emacs_frame.font->fid;
616 gc_values.foreground = ew->core.background_pixel;
617 gc_values.background = ew->emacs_frame.cursor_color;
618 gc_values.graphics_exposures = False;
619 gc_values.tile = blank_tile;
620 gc_values.stipple
621 = XCreateBitmapFromData (XtDisplay (ew),
622 RootWindowOfScreen (XtScreen (ew)),
623 setup_frame_cursor_bits, 16, 16);
624 XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
625 (GCFont | GCForeground | GCBackground | GCGraphicsExposures
626 | GCStipple | GCTile),
627 &gc_values);
628 }
629
630 static void
631 update_various_frame_slots (ew)
632 EmacsFrame ew;
633 {
634 struct x_output *x = ew->emacs_frame.frame->output_data.x;
635 x->pixel_height = ew->core.height;
636 x->pixel_width = ew->core.width;
637 x->internal_border_width = ew->emacs_frame.internal_border_width;
638
639 }
640
641 static void
642 update_from_various_frame_slots (ew)
643 EmacsFrame ew;
644 {
645 struct x_output *x = ew->emacs_frame.frame->output_data.x;
646 ew->core.height = x->pixel_height;
647 ew->core.width = x->pixel_width;
648 ew->core.background_pixel = x->background_pixel;
649 ew->emacs_frame.internal_border_width = x->internal_border_width;
650 ew->emacs_frame.font = x->font;
651 ew->emacs_frame.foreground_pixel = x->foreground_pixel;
652 ew->emacs_frame.cursor_color = x->cursor_pixel;
653 ew->core.border_pixel = x->border_pixel;
654 }
655
656 static void
657 EmacsFrameInitialize (request, new, dum1, dum2)
658 Widget request;
659 Widget new;
660 ArgList dum1;
661 Cardinal *dum2;
662 {
663 EmacsFrame ew = (EmacsFrame)new;
664
665 if (!ew->emacs_frame.frame)
666 {
667 fprintf (stderr,
668 "can't create an emacs frame widget without a frame\n");
669 exit (1);
670 }
671
672 #if 0 /* done in xfns.c */
673 /* If the "Emacs.EmacsFrame.{default,Face}.{attributeFont,AttributeFont}"
674 resource is set, then it always overrides "Emacs.EmacsFrame.{font,Font}".
675 It's unfortunate that we have to do this, but we need to know the font
676 size for frame-sizing purposes before the faces get initialized. If
677 the "default.attributeFont" isn't set, then we use the font of this
678 EmacsFrame itself, defaulting to XtDefaultFont. Up in the lisp code,
679 the "default" face will use the frame's font if its own is not set,
680 so everything stays in sync -- it's not possible for the frame's font
681 and the default face's font to be different.
682 */
683 {
684 XFontStruct *f = 0;
685 XtResource face_res;
686 face_res.resource_name = "attributeFont";
687 face_res.resource_class = "AttributeFont";
688 face_res.resource_type = XtRFontStruct;
689 face_res.resource_size = sizeof (XFontStruct *);
690 face_res.resource_offset = 0;
691 face_res.default_type = XtRImmediate;
692 face_res.default_addr = 0;
693 XtGetSubresources ((Widget) ew, (XtPointer) &f, "default", "Face",
694 &face_res, 1, NULL, 0);
695
696 if (f)
697 ew->emacs_frame.font = f;
698 else if (! ew->emacs_frame.font)
699 {
700 fprintf (stderr, "emacs frame widget could not load a font\n");
701 exit (1);
702 }
703 }
704
705 /* Update the font field in frame */
706 ew->emacs_frame.frame->output_data.x->font = ew->emacs_frame.font;
707 #endif
708
709 update_from_various_frame_slots (ew);
710 set_frame_size (ew);
711 /*create_frame_gcs (ew);
712 setup_frame_gcs (ew);
713 update_various_frame_slots (ew); */
714 }
715
716
717 static void
718 EmacsFrameRealize (widget, mask, attrs)
719 Widget widget;
720 XtValueMask *mask;
721 XSetWindowAttributes *attrs;
722 {
723 EmacsFrame ew = (EmacsFrame)widget;
724
725 attrs->event_mask = (KeyPressMask | ExposureMask | ButtonPressMask |
726 ButtonReleaseMask | StructureNotifyMask |
727 FocusChangeMask | PointerMotionHintMask |
728 PointerMotionMask | LeaveWindowMask | EnterWindowMask |
729 VisibilityChangeMask | PropertyChangeMask |
730 StructureNotifyMask | SubstructureNotifyMask |
731 SubstructureRedirectMask);
732 *mask |= CWEventMask;
733 XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
734 attrs);
735 update_wm_hints (ew);
736 }
737
738 extern void free_frame_faces (/* struct frame * */);
739
740 static void
741 EmacsFrameDestroy (widget)
742 Widget widget;
743 {
744 EmacsFrame ew = (EmacsFrame) widget;
745 struct frame* s = ew->emacs_frame.frame;
746
747 if (! s) abort ();
748 if (! s->output_data.x) abort ();
749 if (! s->output_data.x->normal_gc) abort ();
750
751 /* this would be called from Fdelete_frame() but it needs to free some
752 stuff after the widget has been finalized but before the widget has
753 been freed. */
754 free_frame_faces (s);
755
756 BLOCK_INPUT;
757 /* need to be careful that the face-freeing code doesn't free these too */
758 XFreeGC (XtDisplay (widget), s->output_data.x->normal_gc);
759 XFreeGC (XtDisplay (widget), s->output_data.x->reverse_gc);
760 XFreeGC (XtDisplay (widget), s->output_data.x->cursor_gc);
761 UNBLOCK_INPUT;
762 }
763
764 void
765 EmacsFrameResize (widget)
766 Widget widget;
767 {
768 EmacsFrame ew = (EmacsFrame)widget;
769 struct frame *f = ew->emacs_frame.frame;
770 int columns;
771 int rows;
772
773 pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
774 change_frame_size (f, rows, columns, 1, 0);
775 update_wm_hints (ew);
776 update_various_frame_slots (ew);
777 }
778
779 static Boolean
780 EmacsFrameSetValues (cur_widget, req_widget, new_widget, dum1, dum2)
781 Widget cur_widget;
782 Widget req_widget;
783 Widget new_widget;
784 ArgList dum1;
785 Cardinal *dum2;
786 {
787 EmacsFrame cur = (EmacsFrame)cur_widget;
788 EmacsFrame new = (EmacsFrame)new_widget;
789
790 Boolean needs_a_refresh = False;
791 Boolean has_to_recompute_size;
792 Boolean has_to_recompute_gcs;
793 Boolean has_to_update_hints;
794
795 int char_width, char_height;
796 Dimension pixel_width;
797 Dimension pixel_height;
798
799 has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
800 || (cur->emacs_frame.foreground_pixel
801 != new->emacs_frame.foreground_pixel)
802 || (cur->core.background_pixel
803 != new->core.background_pixel)
804 );
805
806 has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
807 && cur->core.width == new->core.width
808 && cur->core.height == new->core.height);
809
810 has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);
811
812 if (has_to_recompute_gcs)
813 {
814 setup_frame_gcs (new);
815 needs_a_refresh = True;
816 }
817
818 if (has_to_recompute_size)
819 {
820 pixel_width = new->core.width;
821 pixel_height = new->core.height;
822 pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
823 &char_height);
824 char_to_pixel_size (new, char_width, char_height, &pixel_width,
825 &pixel_height);
826 new->core.width = pixel_width;
827 new->core.height = pixel_height;
828
829 change_frame_size (new->emacs_frame.frame, char_height, char_width,
830 1, 0);
831 needs_a_refresh = True;
832 }
833
834 if (has_to_update_hints)
835 update_wm_hints (new);
836
837 update_various_frame_slots (new);
838
839 /* #### This doesn't work, I haven't been able to find ANY kludge that
840 will let (x-create-frame '((iconic . t))) work. It seems that changes
841 to wm_shell's iconic slot have no effect after it has been realized,
842 and calling XIconifyWindow doesn't work either (even thought the window
843 has been created.) Perhaps there is some property we could smash
844 directly, but I'm sick of this for now. Xt is a steaming pile of shit!
845 */
846 if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
847 {
848 Widget wmshell = get_wm_shell ((Widget) cur);
849 XtVaSetValues (wmshell, XtNiconic, new->emacs_frame.iconic, 0);
850 }
851
852 return needs_a_refresh;
853 }
854
855 static XtGeometryResult
856 EmacsFrameQueryGeometry (widget, request, result)
857 Widget widget;
858 XtWidgetGeometry* request;
859 XtWidgetGeometry* result;
860 {
861 EmacsFrame ew = (EmacsFrame)widget;
862
863 int mask = request->request_mode;
864 Dimension ok_width, ok_height;
865
866 if (mask & (CWWidth | CWHeight))
867 {
868 round_size_to_char (ew,
869 (mask & CWWidth) ? request->width : ew->core.width,
870 ((mask & CWHeight) ? request->height
871 : ew->core.height),
872 &ok_width, &ok_height);
873 if ((mask & CWWidth) && (ok_width != request->width))
874 {
875 result->request_mode |= CWWidth;
876 result->width = ok_width;
877 }
878 if ((mask & CWHeight) && (ok_height != request->height))
879 {
880 result->request_mode |= CWHeight;
881 result->height = ok_height;
882 }
883 }
884 return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
885 }
886
887 /* Special entrypoints */
888 void
889 EmacsFrameSetCharSize (widget, columns, rows)
890 Widget widget;
891 int columns;
892 int rows;
893 {
894 EmacsFrame ew = (EmacsFrame) widget;
895 Dimension pixel_width, pixel_height, granted_width, granted_height;
896 XtGeometryResult result;
897 struct frame *f = ew->emacs_frame.frame;
898 Arg al[2];
899 int ac = 0;
900
901 if (columns < 3) columns = 3; /* no way buddy */
902
903 check_frame_size (f, &rows, &columns);
904 f->output_data.x->vertical_scroll_bar_extra
905 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
906 ? 0
907 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
908 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
909 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
910
911 char_to_pixel_size (ew, columns, rows, &pixel_width, &pixel_height);
912
913 /* Manually change the height and width of all our widgets,
914 adjusting each widget by the same increments. */
915 if (ew->core.width != pixel_width || ew->core.height != pixel_height)
916 {
917 int hdelta = pixel_height - ew->core.height;
918 int wdelta = pixel_width - ew->core.width;
919 int column_widget_height = f->output_data.x->column_widget->core.height;
920 int column_widget_width = f->output_data.x->column_widget->core.width;
921 int outer_widget_height = f->output_data.x->widget->core.height;
922 int outer_widget_width = f->output_data.x->widget->core.width;
923 int old_left = f->output_data.x->widget->core.x;
924 int old_top = f->output_data.x->widget->core.y;
925
926 lw_refigure_widget (f->output_data.x->column_widget, False);
927 update_hints_inhibit = 1;
928
929 ac = 0;
930 XtSetArg (al[ac], XtNheight, pixel_height); ac++;
931 XtSetArg (al[ac], XtNwidth, pixel_width); ac++;
932 XtSetValues ((Widget) ew, al, ac);
933
934 ac = 0;
935 XtSetArg (al[ac], XtNheight, column_widget_height + hdelta); ac++;
936 XtSetArg (al[ac], XtNwidth, column_widget_width + wdelta); ac++;
937 XtSetValues (f->output_data.x->column_widget, al, ac);
938
939 ac = 0;
940 XtSetArg (al[ac], XtNheight, outer_widget_height + hdelta); ac++;
941 XtSetArg (al[ac], XtNwidth, outer_widget_width + wdelta); ac++;
942 XtSetValues (f->output_data.x->widget, al, ac);
943
944 lw_refigure_widget (f->output_data.x->column_widget, True);
945
946 update_hints_inhibit = 0;
947 update_wm_hints (ew);
948
949 /* These seem to get clobbered. I don't know why. - rms. */
950 f->output_data.x->widget->core.x = old_left;
951 f->output_data.x->widget->core.y = old_top;
952 }
953
954 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
955 receive in the ConfigureNotify event; if we get what we asked
956 for, then the event won't cause the screen to become garbaged, so
957 we have to make sure to do it here. */
958 SET_FRAME_GARBAGED (f);
959 }