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