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