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