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