1 /* The emacs frame widget.
2 Copyright (C) 1992-1993, 2000-2024 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 /* Emacs 19 face widget ported by Fred Pierresteguy */
21 /* This file has been censored by the Communications Decency Act.
22 That law was passed under the guise of a ban on pornography, but
23 it bans far more than that. This file did not contain pornography,
24 but it was censored nonetheless. */
36 #include <X11/StringDefs.h>
37 #include <X11/IntrinsicP.h>
38 #include <X11/cursorfont.h>
39 #include "widgetprv.h"
40 #include <X11/ObjectP.h>
41 #include <X11/Shell.h>
42 #include <X11/ShellP.h>
43 #include "../lwlib/lwlib.h"
45 static void EmacsFrameInitialize (Widget
, Widget
, ArgList
, Cardinal
*);
46 static void EmacsFrameDestroy (Widget
);
47 static void EmacsFrameRealize (Widget
, XtValueMask
*, XSetWindowAttributes
*);
48 static void EmacsFrameResize (Widget
);
49 static void EmacsFrameExpose (Widget
, XEvent
*, Region
);
50 static XtGeometryResult
EmacsFrameQueryGeometry (Widget
, XtWidgetGeometry
*,
54 #define offset(field) offsetof (EmacsFrameRec, emacs_frame.field)
56 static XtResource resources
[] = {
57 {(char *) XtNgeometry
, (char *) XtCGeometry
, XtRString
, sizeof (String
),
58 offset (geometry
), XtRString
, (XtPointer
) 0},
59 {XtNiconic
, XtCIconic
, XtRBoolean
, sizeof (Boolean
),
60 offset (iconic
), XtRImmediate
, (XtPointer
) False
},
62 {(char *) XtNemacsFrame
, (char *) XtCEmacsFrame
,
63 XtRPointer
, sizeof (XtPointer
),
64 offset (frame
), XtRImmediate
, 0},
66 {(char *) XtNminibuffer
, (char *) XtCMinibuffer
, XtRInt
, sizeof (int),
67 offset (minibuffer
), XtRImmediate
, (XtPointer
)0},
68 {(char *) XtNunsplittable
, (char *) XtCUnsplittable
,
69 XtRBoolean
, sizeof (Boolean
),
70 offset (unsplittable
), XtRImmediate
, (XtPointer
)0},
71 {(char *) XtNinternalBorderWidth
, (char *) XtCInternalBorderWidth
,
73 offset (internal_border_width
), XtRImmediate
, (XtPointer
)4},
74 {(char *) XtNinterline
, (char *) XtCInterline
, XtRInt
, sizeof (int),
75 offset (interline
), XtRImmediate
, (XtPointer
)0},
76 {(char *) XtNforeground
, (char *) XtCForeground
, XtRPixel
, sizeof (Pixel
),
77 offset (foreground_pixel
), XtRString
, (char *) "XtDefaultForeground"},
78 {(char *) XtNcursorColor
, (char *) XtCForeground
, XtRPixel
, sizeof (Pixel
),
79 offset (cursor_color
), XtRString
, (char *) "XtDefaultForeground"},
80 {(char *) XtNbarCursor
, (char *) XtCBarCursor
, XtRBoolean
, sizeof (Boolean
),
81 offset (bar_cursor
), XtRImmediate
, (XtPointer
)0},
82 {(char *) XtNvisualBell
, (char *) XtCVisualBell
, XtRBoolean
, sizeof (Boolean
),
83 offset (visual_bell
), XtRImmediate
, (XtPointer
)0},
84 {(char *) XtNbellVolume
, (char *) XtCBellVolume
, XtRInt
, sizeof (int),
85 offset (bell_volume
), XtRImmediate
, (XtPointer
)0},
92 emacsFrameActionsTable [] = {
93 {"keypress", key_press},
94 {"focus_in", emacs_frame_focus_handler},
95 {"focus_out", emacs_frame_focus_handler},
99 emacsFrameTranslations [] = "\
100 <KeyPress>: keypress()\n\
101 <FocusIn>: focus_in()\n\
102 <FocusOut>: focus_out()\n\
106 static EmacsFrameClassRec emacsFrameClassRec
= {
108 /* superclass */ 0, /* filled in by emacsFrameClass */
109 /* class_name */ (char *) "EmacsFrame",
110 /* widget_size */ sizeof (EmacsFrameRec
),
111 /* class_initialize */ 0,
112 /* class_part_initialize */ 0,
113 /* class_inited */ FALSE
,
114 /* initialize */ EmacsFrameInitialize
,
115 /* initialize_hook */ 0,
116 /* realize */ EmacsFrameRealize
,
117 /* actions */ 0, /*emacsFrameActionsTable*/
118 /* num_actions */ 0, /*XtNumber (emacsFrameActionsTable)*/
119 /* resources */ resources
,
120 /* resource_count */ XtNumber (resources
),
121 /* xrm_class */ NULLQUARK
,
122 /* compress_motion */ TRUE
,
123 /* compress_exposure */ XtExposeNoCompress
,
124 /* compress_enterleave */ TRUE
,
125 /* visible_interest */ FALSE
,
126 /* destroy */ EmacsFrameDestroy
,
127 /* resize */ EmacsFrameResize
,
128 /* expose */ EmacsFrameExpose
,
130 /* Emacs never does XtSetvalues on this widget, so we have no code
132 /* set_values */ 0, /* Not supported */
133 /* set_values_hook */ 0,
134 /* set_values_almost */ XtInheritSetValuesAlmost
,
135 /* get_values_hook */ 0,
136 /* accept_focus */ XtInheritAcceptFocus
,
137 /* version */ XtVersion
,
138 /* callback_private */ 0,
139 /* tm_table */ 0, /*emacsFrameTranslations*/
140 /* query_geometry */ EmacsFrameQueryGeometry
,
141 /* display_accelerator */ XtInheritDisplayAccelerator
,
147 emacsFrameClass (void)
149 /* Set the superclass here rather than relying on static
150 initialization, to work around an unexelf.c bug on x86 platforms
151 that use the GNU Gold linker (Bug#27248). */
152 emacsFrameClassRec
.core_class
.superclass
= &widgetClassRec
;
154 return (WidgetClass
) &emacsFrameClassRec
;
158 get_default_char_pixel_size (EmacsFrame ew
, int *pixel_width
, int *pixel_height
)
160 struct frame
*f
= ew
->emacs_frame
.frame
;
162 *pixel_width
= FRAME_COLUMN_WIDTH (f
);
163 *pixel_height
= FRAME_LINE_HEIGHT (f
);
167 pixel_to_char_size (EmacsFrame ew
, Dimension pixel_width
,
168 Dimension pixel_height
, int *char_width
, int *char_height
)
170 struct frame
*f
= ew
->emacs_frame
.frame
;
172 *char_width
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, (int) pixel_width
);
173 *char_height
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, (int) pixel_height
);
177 char_to_pixel_size (EmacsFrame ew
, int char_width
, int char_height
,
178 Dimension
*pixel_width
, Dimension
*pixel_height
)
180 struct frame
*f
= ew
->emacs_frame
.frame
;
182 *pixel_width
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, char_width
);
183 *pixel_height
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, char_height
);
187 round_size_to_char (EmacsFrame ew
, Dimension in_width
, Dimension in_height
,
188 Dimension
*out_width
, Dimension
*out_height
)
192 pixel_to_char_size (ew
, in_width
, in_height
,
193 &char_width
, &char_height
);
194 char_to_pixel_size (ew
, char_width
, char_height
,
195 out_width
, out_height
);
199 get_wm_shell (Widget w
)
203 for (wmshell
= XtParent (w
);
204 wmshell
&& !XtIsWMShell (wmshell
);
205 wmshell
= XtParent (wmshell
));
207 return (WMShellWidget
) wmshell
;
210 #if 0 /* Currently not used. */
213 mark_shell_size_user_specified (Widget wmshell
)
215 if (! XtIsWMShell (wmshell
)) emacs_abort ();
216 /* This is kind of sleazy, but I can't see how else to tell it to make it
217 mark the WM_SIZE_HINTS size as user specified when appropriate. */
218 ((WMShellWidget
) wmshell
)->wm
.size_hints
.flags
|= USSize
;
225 set_frame_size (EmacsFrame ew
)
227 /* The widget hierarchy is
229 argv[0] emacsShell pane Frame-NAME
230 ApplicationShell EmacsShell Paned EmacsFrame
232 We accept geometry specs in this order:
238 Other possibilities for widget hierarchies might be
240 argv[0] frame pane Frame-NAME
241 ApplicationShell EmacsShell Paned EmacsFrame
243 argv[0] Frame-NAME pane Frame-NAME
244 ApplicationShell EmacsShell Paned EmacsFrame
246 argv[0] Frame-NAME pane emacsTextPane
247 ApplicationShell EmacsFrame Paned EmacsTextPane
249 With the current setup, the text-display-area is the part which is
250 an emacs "frame", since that's the only part managed by emacs proper
251 (the menubar and the parent of the menubar and all that sort of thing
252 are managed by lwlib.)
254 The EmacsShell widget is simply a replacement for the Shell widget
255 which is able to deal with using an externally-supplied window instead
256 of always creating its own. It is not actually emacs specific, and
257 should possibly have class "Shell" instead of "EmacsShell" to simplify
262 struct frame
*f
= ew
->emacs_frame
.frame
;
264 ew
->core
.width
= FRAME_PIXEL_WIDTH (f
);
265 ew
->core
.height
= FRAME_PIXEL_HEIGHT (f
);
267 if (CONSP (frame_size_history
))
268 frame_size_history_plain
269 (f
, build_string ("set_frame_size"));
273 update_wm_hints (WMShellWidget wmshell
, EmacsFrame ew
)
277 Dimension rounded_width
;
278 Dimension rounded_height
;
283 char buffer
[sizeof wmshell
->wm
.size_hints
];
286 /* Copy the old size hints to the buffer. */
287 memcpy (buffer
, &wmshell
->wm
.size_hints
,
288 sizeof wmshell
->wm
.size_hints
);
290 pixel_to_char_size (ew
, ew
->core
.width
, ew
->core
.height
,
291 &char_width
, &char_height
);
292 char_to_pixel_size (ew
, char_width
, char_height
,
293 &rounded_width
, &rounded_height
);
294 get_default_char_pixel_size (ew
, &cw
, &ch
);
296 base_width
= (wmshell
->core
.width
- ew
->core
.width
297 + (rounded_width
- (char_width
* cw
)));
298 base_height
= (wmshell
->core
.height
- ew
->core
.height
299 + (rounded_height
- (char_height
* ch
)));
301 XtVaSetValues ((Widget
) wmshell
,
302 XtNbaseWidth
, (XtArgVal
) base_width
,
303 XtNbaseHeight
, (XtArgVal
) base_height
,
304 XtNwidthInc
, (XtArgVal
) (frame_resize_pixelwise
? 1 : cw
),
305 XtNheightInc
, (XtArgVal
) (frame_resize_pixelwise
? 1 : ch
),
306 XtNminWidth
, (XtArgVal
) base_width
,
307 XtNminHeight
, (XtArgVal
) base_height
,
310 /* Return if size hints really changed. If they did not, then Xt
311 probably didn't set them either (or take the flags into
313 hints_ptr
= (char *) &wmshell
->wm
.size_hints
;
315 /* Skip flags, which is unsigned long. */
316 return memcmp (hints_ptr
+ sizeof (long), buffer
+ sizeof (long),
317 sizeof wmshell
->wm
.wm_hints
- sizeof (long));
321 widget_update_wm_size_hints (Widget widget
, Widget frame
)
323 return update_wm_hints ((WMShellWidget
) widget
, (EmacsFrame
) frame
);
327 update_various_frame_slots (EmacsFrame ew
)
329 struct frame
*f
= ew
->emacs_frame
.frame
;
331 f
->internal_border_width
= ew
->emacs_frame
.internal_border_width
;
335 update_from_various_frame_slots (EmacsFrame ew
)
337 struct frame
*f
= ew
->emacs_frame
.frame
;
338 struct x_output
*x
= f
->output_data
.x
;
340 ew
->core
.height
= FRAME_PIXEL_HEIGHT (f
) - x
->menubar_height
;
341 ew
->core
.width
= FRAME_PIXEL_WIDTH (f
);
342 ew
->core
.background_pixel
= FRAME_BACKGROUND_PIXEL (f
);
343 ew
->emacs_frame
.internal_border_width
= f
->internal_border_width
;
344 ew
->emacs_frame
.foreground_pixel
= FRAME_FOREGROUND_PIXEL (f
);
345 ew
->emacs_frame
.cursor_color
= x
->cursor_pixel
;
346 ew
->core
.border_pixel
= x
->border_pixel
;
348 if (CONSP (frame_size_history
))
349 frame_size_history_extra
350 (f
, build_string ("update_from_various_frame_slots"),
351 FRAME_PIXEL_WIDTH (f
), FRAME_PIXEL_HEIGHT (f
),
352 ew
->core
.width
, ew
->core
.height
,
353 f
->new_width
, f
->new_height
);
357 EmacsFrameInitialize (Widget request
, Widget
new,
358 ArgList dum1
, Cardinal
*dum2
)
360 EmacsFrame ew
= (EmacsFrame
) new;
362 if (!ew
->emacs_frame
.frame
)
364 fputs ("can't create an emacs frame widget without a frame\n", stderr
);
368 update_from_various_frame_slots (ew
);
373 resize_cb (Widget widget
,
376 Boolean
*continue_to_dispatch
)
378 EmacsFrameResize (widget
);
383 EmacsFrameRealize (Widget widget
, XtValueMask
*mask
,
384 XSetWindowAttributes
*attrs
)
386 EmacsFrame ew
= (EmacsFrame
) widget
;
387 struct frame
*f
= ew
->emacs_frame
.frame
;
389 /* This used to contain SubstructureRedirectMask, but this turns out
390 to be a problem with XIM on Solaris, and events from that mask
391 don't seem to be used. Let's check that. */
392 attrs
->event_mask
= (STANDARD_EVENT_SET
394 | SubstructureNotifyMask
);
395 *mask
|= CWEventMask
;
396 XtCreateWindow (widget
, InputOutput
, (Visual
*) CopyFromParent
, *mask
,
398 /* Some ConfigureNotify events does not end up in EmacsFrameResize so
399 make sure we get them all. Seen with xfcwm4 for example. */
400 XtAddRawEventHandler (widget
, StructureNotifyMask
, False
, resize_cb
, NULL
);
402 if (CONSP (frame_size_history
))
403 frame_size_history_plain
404 (f
, build_string ("EmacsFrameRealize"));
406 if (get_wm_shell (widget
))
407 update_wm_hints (get_wm_shell (widget
), ew
);
411 EmacsFrameDestroy (Widget widget
)
413 /* All GCs are now freed in x_free_frame_resources. */
417 EmacsFrameResize (Widget widget
)
419 EmacsFrame ew
= (EmacsFrame
) widget
;
420 struct frame
*f
= ew
->emacs_frame
.frame
;
422 if (CONSP (frame_size_history
))
423 frame_size_history_extra
424 (f
, build_string ("EmacsFrameResize"),
425 FRAME_PIXEL_WIDTH (f
), FRAME_PIXEL_HEIGHT (f
),
426 ew
->core
.width
, ew
->core
.height
,
427 f
->new_width
, f
->new_height
);
429 change_frame_size (f
, ew
->core
.width
, ew
->core
.height
,
432 if (get_wm_shell (widget
))
433 update_wm_hints (get_wm_shell (widget
), ew
);
434 update_various_frame_slots (ew
);
436 cancel_mouse_face (f
);
439 static XtGeometryResult
440 EmacsFrameQueryGeometry (Widget widget
, XtWidgetGeometry
*request
,
441 XtWidgetGeometry
*result
)
443 int mask
= request
->request_mode
;
445 if (mask
& (CWWidth
| CWHeight
) && !frame_resize_pixelwise
)
447 EmacsFrame ew
= (EmacsFrame
) widget
;
448 Dimension ok_width
, ok_height
;
450 round_size_to_char (ew
,
451 mask
& CWWidth
? request
->width
: ew
->core
.width
,
452 mask
& CWHeight
? request
->height
: ew
->core
.height
,
453 &ok_width
, &ok_height
);
454 if ((mask
& CWWidth
) && (ok_width
!= request
->width
))
456 result
->request_mode
|= CWWidth
;
457 result
->width
= ok_width
;
459 if ((mask
& CWHeight
) && (ok_height
!= request
->height
))
461 result
->request_mode
|= CWHeight
;
462 result
->height
= ok_height
;
465 return result
->request_mode
? XtGeometryAlmost
: XtGeometryYes
;
468 /* Special entry points */
470 EmacsFrameSetCharSize (Widget widget
, int columns
, int rows
)
472 EmacsFrame ew
= (EmacsFrame
) widget
;
473 struct frame
*f
= ew
->emacs_frame
.frame
;
475 if (CONSP (frame_size_history
))
476 frame_size_history_extra
477 (f
, build_string ("EmacsFrameSetCharSize"),
478 FRAME_PIXEL_WIDTH (f
), FRAME_PIXEL_HEIGHT (f
),
480 f
->new_width
, f
->new_height
);
482 if (!frame_inhibit_resize (f
, 0, Qfont
)
483 && !frame_inhibit_resize (f
, 1, Qfont
))
484 x_set_window_size (f
, 0, columns
* FRAME_COLUMN_WIDTH (f
),
485 rows
* FRAME_LINE_HEIGHT (f
));
489 EmacsFrameExpose (Widget widget
, XEvent
*event
, Region region
)
491 EmacsFrame ew
= (EmacsFrame
) widget
;
492 struct frame
*f
= ew
->emacs_frame
.frame
;
494 expose_frame (f
, event
->xexpose
.x
, event
->xexpose
.y
,
495 event
->xexpose
.width
, event
->xexpose
.height
);
501 widget_store_internal_border (Widget widget
)
503 EmacsFrame ew
= (EmacsFrame
) widget
;
504 struct frame
*f
= ew
->emacs_frame
.frame
;
506 ew
->emacs_frame
.internal_border_width
= f
->internal_border_width
;