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