1 /* The emacs frame widget.
2 Copyright (C) 1992-1993, 2000-2018 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.
26 For information on US government censorship of the Internet, and
27 what you can do to bring back freedom of the press, see the web
28 site http://www.vtw.org/
41 #include <X11/StringDefs.h>
42 #include <X11/IntrinsicP.h>
43 #include <X11/cursorfont.h>
44 #include "widgetprv.h"
45 #include <X11/ObjectP.h>
46 #include <X11/Shell.h>
47 #include <X11/ShellP.h>
48 #include "../lwlib/lwlib.h"
50 static void EmacsFrameInitialize (Widget request
, Widget
new, ArgList dum1
, Cardinal
*dum2
);
51 static void EmacsFrameDestroy (Widget widget
);
52 static void EmacsFrameRealize (Widget widget
, XtValueMask
*mask
, XSetWindowAttributes
*attrs
);
53 static void EmacsFrameResize (Widget widget
);
54 static XtGeometryResult
EmacsFrameQueryGeometry (Widget widget
, XtWidgetGeometry
*request
, XtWidgetGeometry
*result
);
57 #define offset(field) offsetof (EmacsFrameRec, emacs_frame.field)
59 static XtResource resources
[] = {
60 {(char *) XtNgeometry
, (char *) XtCGeometry
, XtRString
, sizeof (String
),
61 offset (geometry
), XtRString
, (XtPointer
) 0},
62 {XtNiconic
, XtCIconic
, XtRBoolean
, sizeof (Boolean
),
63 offset (iconic
), XtRImmediate
, (XtPointer
) False
},
65 {(char *) XtNemacsFrame
, (char *) XtCEmacsFrame
,
66 XtRPointer
, sizeof (XtPointer
),
67 offset (frame
), XtRImmediate
, 0},
69 {(char *) XtNminibuffer
, (char *) XtCMinibuffer
, XtRInt
, sizeof (int),
70 offset (minibuffer
), XtRImmediate
, (XtPointer
)0},
71 {(char *) XtNunsplittable
, (char *) XtCUnsplittable
,
72 XtRBoolean
, sizeof (Boolean
),
73 offset (unsplittable
), XtRImmediate
, (XtPointer
)0},
74 {(char *) XtNinternalBorderWidth
, (char *) XtCInternalBorderWidth
,
76 offset (internal_border_width
), XtRImmediate
, (XtPointer
)4},
77 {(char *) XtNinterline
, (char *) XtCInterline
, XtRInt
, sizeof (int),
78 offset (interline
), XtRImmediate
, (XtPointer
)0},
79 {(char *) XtNforeground
, (char *) XtCForeground
, XtRPixel
, sizeof (Pixel
),
80 offset (foreground_pixel
), XtRString
, (char *) "XtDefaultForeground"},
81 {(char *) XtNcursorColor
, (char *) XtCForeground
, XtRPixel
, sizeof (Pixel
),
82 offset (cursor_color
), XtRString
, (char *) "XtDefaultForeground"},
83 {(char *) XtNbarCursor
, (char *) XtCBarCursor
, XtRBoolean
, sizeof (Boolean
),
84 offset (bar_cursor
), XtRImmediate
, (XtPointer
)0},
85 {(char *) XtNvisualBell
, (char *) XtCVisualBell
, XtRBoolean
, sizeof (Boolean
),
86 offset (visual_bell
), XtRImmediate
, (XtPointer
)0},
87 {(char *) XtNbellVolume
, (char *) XtCBellVolume
, XtRInt
, sizeof (int),
88 offset (bell_volume
), XtRImmediate
, (XtPointer
)0},
95 emacsFrameActionsTable [] = {
96 {"keypress", key_press},
97 {"focus_in", emacs_frame_focus_handler},
98 {"focus_out", emacs_frame_focus_handler},
102 emacsFrameTranslations [] = "\
103 <KeyPress>: keypress()\n\
104 <FocusIn>: focus_in()\n\
105 <FocusOut>: focus_out()\n\
109 static EmacsFrameClassRec emacsFrameClassRec
= {
111 /* superclass */ 0, /* filled in by emacsFrameClass */
112 /* class_name */ (char *) "EmacsFrame",
113 /* widget_size */ sizeof (EmacsFrameRec
),
114 /* class_initialize */ 0,
115 /* class_part_initialize */ 0,
116 /* class_inited */ FALSE
,
117 /* initialize */ EmacsFrameInitialize
,
118 /* initialize_hook */ 0,
119 /* realize */ EmacsFrameRealize
,
120 /* actions */ 0, /*emacsFrameActionsTable*/
121 /* num_actions */ 0, /*XtNumber (emacsFrameActionsTable)*/
122 /* resources */ resources
,
123 /* resource_count */ XtNumber (resources
),
124 /* xrm_class */ NULLQUARK
,
125 /* compress_motion */ TRUE
,
126 /* compress_exposure */ TRUE
,
127 /* compress_enterleave */ TRUE
,
128 /* visible_interest */ FALSE
,
129 /* destroy */ EmacsFrameDestroy
,
130 /* resize */ EmacsFrameResize
,
131 /* expose */ XtInheritExpose
,
133 /* Emacs never does XtSetvalues on this widget, so we have no code
135 /* set_values */ 0, /* Not supported */
136 /* set_values_hook */ 0,
137 /* set_values_almost */ XtInheritSetValuesAlmost
,
138 /* get_values_hook */ 0,
139 /* accept_focus */ XtInheritAcceptFocus
,
140 /* version */ XtVersion
,
141 /* callback_private */ 0,
142 /* tm_table */ 0, /*emacsFrameTranslations*/
143 /* query_geometry */ EmacsFrameQueryGeometry
,
144 /* display_accelerator */ XtInheritDisplayAccelerator
,
150 emacsFrameClass (void)
152 /* Set the superclass here rather than relying on static
153 initialization, to work around an unexelf.c bug on x86 platforms
154 that use the GNU Gold linker (Bug#27248). */
155 emacsFrameClassRec
.core_class
.superclass
= &widgetClassRec
;
157 return (WidgetClass
) &emacsFrameClassRec
;
161 get_default_char_pixel_size (EmacsFrame ew
, int *pixel_width
, int *pixel_height
)
163 struct frame
*f
= ew
->emacs_frame
.frame
;
164 *pixel_width
= FRAME_COLUMN_WIDTH (f
);
165 *pixel_height
= FRAME_LINE_HEIGHT (f
);
169 pixel_to_char_size (EmacsFrame ew
, Dimension pixel_width
, Dimension pixel_height
, int *char_width
, int *char_height
)
171 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 pixel_to_text_size (EmacsFrame ew
, Dimension pixel_width
, Dimension pixel_height
, int *text_width
, int *text_height
)
179 struct frame
*f
= ew
->emacs_frame
.frame
;
180 *text_width
= FRAME_PIXEL_TO_TEXT_WIDTH (f
, (int) pixel_width
);
181 *text_height
= FRAME_PIXEL_TO_TEXT_HEIGHT (f
, (int) pixel_height
);
185 char_to_pixel_size (EmacsFrame ew
, int char_width
, int char_height
, Dimension
*pixel_width
, Dimension
*pixel_height
)
187 struct frame
*f
= ew
->emacs_frame
.frame
;
188 *pixel_width
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, char_width
);
189 *pixel_height
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, char_height
);
193 round_size_to_char (EmacsFrame ew
, Dimension in_width
, Dimension in_height
, Dimension
*out_width
, Dimension
*out_height
)
197 pixel_to_char_size (ew
, in_width
, in_height
, &char_width
, &char_height
);
198 char_to_pixel_size (ew
, char_width
, char_height
, out_width
, out_height
);
202 get_wm_shell (Widget w
)
206 for (wmshell
= XtParent (w
);
207 wmshell
&& !XtIsWMShell (wmshell
);
208 wmshell
= XtParent (wmshell
));
213 #if 0 /* Currently not used. */
216 mark_shell_size_user_specified (Widget wmshell
)
218 if (! XtIsWMShell (wmshell
)) emacs_abort ();
219 /* This is kind of sleazy, but I can't see how else to tell it to make it
220 mark the WM_SIZE_HINTS size as user specified when appropriate. */
221 ((WMShellWidget
) wmshell
)->wm
.size_hints
.flags
|= USSize
;
228 set_frame_size (EmacsFrame ew
)
230 /* The widget hierarchy is
232 argv[0] emacsShell pane Frame-NAME
233 ApplicationShell EmacsShell Paned EmacsFrame
235 We accept geometry specs in this order:
241 Other possibilities for widget hierarchies might be
243 argv[0] frame pane Frame-NAME
244 ApplicationShell EmacsShell Paned EmacsFrame
246 argv[0] Frame-NAME pane Frame-NAME
247 ApplicationShell EmacsShell Paned EmacsFrame
249 argv[0] Frame-NAME pane emacsTextPane
250 ApplicationShell EmacsFrame Paned EmacsTextPane
252 With the current setup, the text-display-area is the part which is
253 an emacs "frame", since that's the only part managed by emacs proper
254 (the menubar and the parent of the menubar and all that sort of thing
255 are managed by lwlib.)
257 The EmacsShell widget is simply a replacement for the Shell widget
258 which is able to deal with using an externally-supplied window instead
259 of always creating its own. It is not actually emacs specific, and
260 should possibly have class "Shell" instead of "EmacsShell" to simplify
265 /* Hairily merged geometry */
266 struct frame
*f
= ew
->emacs_frame
.frame
;
267 int w
= FRAME_COLS (f
);
268 int h
= FRAME_LINES (f
);
269 Widget wmshell
= get_wm_shell ((Widget
) ew
);
270 Dimension pixel_width
, pixel_height
;
271 /* Each Emacs shell is now independent and top-level. */
273 if (! XtIsSubclass (wmshell
, shellWidgetClass
)) emacs_abort ();
275 char_to_pixel_size (ew
, w
, h
, &pixel_width
, &pixel_height
);
276 ew
->core
.width
= (frame_resize_pixelwise
277 ? FRAME_PIXEL_WIDTH (f
)
279 ew
->core
.height
= (frame_resize_pixelwise
280 ? FRAME_PIXEL_HEIGHT (f
)
283 frame_size_history_add
284 (f
, Qset_frame_size
, FRAME_TEXT_WIDTH (f
), FRAME_TEXT_HEIGHT (f
),
285 list2 (make_number (ew
->core
.width
), make_number (ew
->core
.height
)));
289 update_wm_hints (EmacsFrame ew
)
291 Widget wmshell
= get_wm_shell ((Widget
) ew
);
294 Dimension rounded_width
;
295 Dimension rounded_height
;
300 int min_rows
= 0, min_cols
= 0;
302 /* This happens when the frame is just created. */
303 if (! wmshell
) return;
305 pixel_to_char_size (ew
, ew
->core
.width
, ew
->core
.height
,
306 &char_width
, &char_height
);
307 char_to_pixel_size (ew
, char_width
, char_height
,
308 &rounded_width
, &rounded_height
);
309 get_default_char_pixel_size (ew
, &cw
, &ch
);
311 base_width
= (wmshell
->core
.width
- ew
->core
.width
312 + (rounded_width
- (char_width
* cw
)));
313 base_height
= (wmshell
->core
.height
- ew
->core
.height
314 + (rounded_height
- (char_height
* ch
)));
316 /* This is kind of sleazy, but I can't see how else to tell it to
317 make it mark the WM_SIZE_HINTS size as user specified.
319 /* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
321 XtVaSetValues (wmshell
,
322 XtNbaseWidth
, (XtArgVal
) base_width
,
323 XtNbaseHeight
, (XtArgVal
) base_height
,
324 XtNwidthInc
, (XtArgVal
) (frame_resize_pixelwise
? 1 : cw
),
325 XtNheightInc
, (XtArgVal
) (frame_resize_pixelwise
? 1 : ch
),
326 XtNminWidth
, (XtArgVal
) (base_width
+ min_cols
* cw
),
327 XtNminHeight
, (XtArgVal
) (base_height
+ min_rows
* ch
),
332 widget_update_wm_size_hints (Widget widget
)
334 EmacsFrame ew
= (EmacsFrame
) widget
;
335 update_wm_hints (ew
);
339 update_various_frame_slots (EmacsFrame ew
)
341 struct frame
*f
= ew
->emacs_frame
.frame
;
343 f
->internal_border_width
= ew
->emacs_frame
.internal_border_width
;
347 update_from_various_frame_slots (EmacsFrame ew
)
349 struct frame
*f
= ew
->emacs_frame
.frame
;
350 struct x_output
*x
= f
->output_data
.x
;
352 ew
->core
.height
= FRAME_PIXEL_HEIGHT (f
) - x
->menubar_height
;
353 ew
->core
.width
= FRAME_PIXEL_WIDTH (f
);
354 ew
->core
.background_pixel
= FRAME_BACKGROUND_PIXEL (f
);
355 ew
->emacs_frame
.internal_border_width
= f
->internal_border_width
;
356 ew
->emacs_frame
.foreground_pixel
= FRAME_FOREGROUND_PIXEL (f
);
357 ew
->emacs_frame
.cursor_color
= x
->cursor_pixel
;
358 ew
->core
.border_pixel
= x
->border_pixel
;
362 EmacsFrameInitialize (Widget request
, Widget
new, ArgList dum1
, Cardinal
*dum2
)
364 EmacsFrame ew
= (EmacsFrame
) new;
366 if (!ew
->emacs_frame
.frame
)
369 "can't create an emacs frame widget without a frame\n");
373 update_from_various_frame_slots (ew
);
378 resize_cb (Widget widget
,
381 Boolean
*continue_to_dispatch
)
383 EmacsFrameResize (widget
);
388 EmacsFrameRealize (Widget widget
, XtValueMask
*mask
, XSetWindowAttributes
*attrs
)
390 EmacsFrame ew
= (EmacsFrame
) widget
;
392 /* This used to contain SubstructureRedirectMask, but this turns out
393 to be a problem with XIM on Solaris, and events from that mask
394 don't seem to be used. Let's check that. */
395 attrs
->event_mask
= (STANDARD_EVENT_SET
397 | SubstructureNotifyMask
);
398 *mask
|= CWEventMask
;
399 XtCreateWindow (widget
, InputOutput
, (Visual
*) CopyFromParent
, *mask
,
401 /* Some ConfigureNotify events does not end up in EmacsFrameResize so
402 make sure we get them all. Seen with xfcwm4 for example. */
403 XtAddRawEventHandler (widget
, StructureNotifyMask
, False
, resize_cb
, NULL
);
404 update_wm_hints (ew
);
408 EmacsFrameDestroy (Widget widget
)
410 /* All GCs are now freed in x_free_frame_resources. */
414 EmacsFrameResize (Widget widget
)
416 EmacsFrame ew
= (EmacsFrame
) widget
;
417 struct frame
*f
= ew
->emacs_frame
.frame
;
420 pixel_to_text_size (ew
, ew
->core
.width
, ew
->core
.height
, &width
, &height
);
422 frame_size_history_add
423 (f
, QEmacsFrameResize
, width
, height
,
424 list5 (make_number (ew
->core
.width
), make_number (ew
->core
.height
),
425 make_number (FRAME_TOP_MARGIN_HEIGHT (f
)),
426 make_number (FRAME_SCROLL_BAR_AREA_HEIGHT (f
)),
427 make_number (2 * FRAME_INTERNAL_BORDER_WIDTH (f
))));
429 change_frame_size (f
, width
, height
, 0, 1, 0, 1);
431 update_wm_hints (ew
);
432 update_various_frame_slots (ew
);
434 cancel_mouse_face (f
);
437 static XtGeometryResult
438 EmacsFrameQueryGeometry (Widget widget
, XtWidgetGeometry
*request
, XtWidgetGeometry
*result
)
440 EmacsFrame ew
= (EmacsFrame
) widget
;
442 int mask
= request
->request_mode
;
443 Dimension ok_width
, ok_height
;
445 if (mask
& (CWWidth
| CWHeight
))
447 if (!frame_resize_pixelwise
)
448 round_size_to_char (ew
,
449 (mask
& CWWidth
) ? request
->width
: ew
->core
.width
,
450 ((mask
& CWHeight
) ? request
->height
452 &ok_width
, &ok_height
);
453 if ((mask
& CWWidth
) && (ok_width
!= request
->width
))
455 result
->request_mode
|= CWWidth
;
456 result
->width
= ok_width
;
458 if ((mask
& CWHeight
) && (ok_height
!= request
->height
))
460 result
->request_mode
|= CWHeight
;
461 result
->height
= ok_height
;
464 return result
->request_mode
? XtGeometryAlmost
: XtGeometryYes
;
467 /* Special entry points */
469 EmacsFrameSetCharSize (Widget widget
, int columns
, int rows
)
471 EmacsFrame ew
= (EmacsFrame
) widget
;
472 struct frame
*f
= ew
->emacs_frame
.frame
;
474 if (!frame_inhibit_resize (f
, 0, Qfont
)
475 && !frame_inhibit_resize (f
, 1, Qfont
))
476 x_set_window_size (f
, 0, columns
, rows
, 0);
481 widget_store_internal_border (Widget widget
)
483 EmacsFrame ew
= (EmacsFrame
) widget
;
484 struct frame
*f
= ew
->emacs_frame
.frame
;
486 ew
->emacs_frame
.internal_border_width
= f
->internal_border_width
;