Merge from origin/emacs-25
[emacs.git] / src / widget.c
blob59ed431e23bf047351743b1982a65ea8730cabef
1 /* The emacs frame widget.
2 Copyright (C) 1992-1993, 2000-2016 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 <http://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/
31 #include <config.h>
32 #include "widget.h"
34 #include <stdio.h>
35 #include <stdlib.h>
37 #include "lisp.h"
38 #include "xterm.h"
39 #include "frame.h"
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 {XtNgeometry, XtCGeometry, XtRString, sizeof (String),
61 offset (geometry), XtRString, (XtPointer) 0},
62 {XtNiconic, XtCIconic, XtRBoolean, sizeof (Boolean),
63 offset (iconic), XtRImmediate, (XtPointer) False},
65 {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
66 offset (frame), XtRImmediate, 0},
68 {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
69 offset (minibuffer), XtRImmediate, (XtPointer)0},
70 {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
71 offset (unsplittable), XtRImmediate, (XtPointer)0},
72 {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
73 offset (internal_border_width), XtRImmediate, (XtPointer)4},
74 {XtNinterline, XtCInterline, XtRInt, sizeof (int),
75 offset (interline), XtRImmediate, (XtPointer)0},
76 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
77 offset (foreground_pixel), XtRString, "XtDefaultForeground"},
78 {XtNcursorColor, XtCForeground, XtRPixel, sizeof (Pixel),
79 offset (cursor_color), XtRString, "XtDefaultForeground"},
80 {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
81 offset (bar_cursor), XtRImmediate, (XtPointer)0},
82 {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
83 offset (visual_bell), XtRImmediate, (XtPointer)0},
84 {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
85 offset (bell_volume), XtRImmediate, (XtPointer)0},
88 #undef offset
91 static XtActionsRec
92 emacsFrameActionsTable [] = {
93 {"keypress", key_press},
94 {"focus_in", emacs_frame_focus_handler},
95 {"focus_out", emacs_frame_focus_handler},
98 static char
99 emacsFrameTranslations [] = "\
100 <KeyPress>: keypress()\n\
101 <FocusIn>: focus_in()\n\
102 <FocusOut>: focus_out()\n\
106 static EmacsFrameClassRec emacsFrameClassRec = {
107 { /* core fields */
108 /* superclass */ &widgetClassRec,
109 /* class_name */ "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 */ TRUE,
124 /* compress_enterleave */ TRUE,
125 /* visible_interest */ FALSE,
126 /* destroy */ EmacsFrameDestroy,
127 /* resize */ EmacsFrameResize,
128 /* expose */ XtInheritExpose,
130 /* Emacs never does XtSetvalues on this widget, so we have no code
131 for it. */
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,
142 /* extension */ 0
146 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
148 static void
149 get_default_char_pixel_size (EmacsFrame ew, int *pixel_width, int *pixel_height)
151 struct frame* f = ew->emacs_frame.frame;
152 *pixel_width = FRAME_COLUMN_WIDTH (f);
153 *pixel_height = FRAME_LINE_HEIGHT (f);
156 static void
157 pixel_to_char_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *char_width, int *char_height)
159 struct frame* f = ew->emacs_frame.frame;
160 *char_width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, (int) pixel_width);
161 *char_height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (int) pixel_height);
164 static void
165 pixel_to_text_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *text_width, int *text_height)
167 struct frame* f = ew->emacs_frame.frame;
168 *text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, (int) pixel_width);
169 *text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, (int) pixel_height);
172 static void
173 char_to_pixel_size (EmacsFrame ew, int char_width, int char_height, Dimension *pixel_width, Dimension *pixel_height)
175 struct frame* f = ew->emacs_frame.frame;
176 *pixel_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, char_width);
177 *pixel_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, char_height);
180 static void
181 round_size_to_char (EmacsFrame ew, Dimension in_width, Dimension in_height, Dimension *out_width, Dimension *out_height)
183 int char_width;
184 int char_height;
185 pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
186 char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
189 static Widget
190 get_wm_shell (Widget w)
192 Widget wmshell;
194 for (wmshell = XtParent (w);
195 wmshell && !XtIsWMShell (wmshell);
196 wmshell = XtParent (wmshell));
198 return wmshell;
201 #if 0 /* Currently not used. */
203 static void
204 mark_shell_size_user_specified (Widget wmshell)
206 if (! XtIsWMShell (wmshell)) emacs_abort ();
207 /* This is kind of sleazy, but I can't see how else to tell it to make it
208 mark the WM_SIZE_HINTS size as user specified when appropriate. */
209 ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
212 #endif
215 /* Can't have static frame locals because of some broken compilers.
216 Normally, initializing a variable like this doesn't work in emacs,
217 but it's ok in this file because it must come after lastfile (and
218 thus have its data not go into text space) because Xt needs to
219 write to initialized data objects too.
221 #if 0
222 static Boolean first_frame_p = True;
223 #endif
225 static void
226 set_frame_size (EmacsFrame ew)
228 /* The widget hierarchy is
230 argv[0] emacsShell pane Frame-NAME
231 ApplicationShell EmacsShell Paned EmacsFrame
233 We accept geometry specs in this order:
235 *Frame-NAME.geometry
236 *EmacsFrame.geometry
237 Emacs.geometry
239 Other possibilities for widget hierarchies might be
241 argv[0] frame pane Frame-NAME
242 ApplicationShell EmacsShell Paned EmacsFrame
244 argv[0] Frame-NAME pane Frame-NAME
245 ApplicationShell EmacsShell Paned EmacsFrame
247 argv[0] Frame-NAME pane emacsTextPane
248 ApplicationShell EmacsFrame Paned EmacsTextPane
250 With the current setup, the text-display-area is the part which is
251 an emacs "frame", since that's the only part managed by emacs proper
252 (the menubar and the parent of the menubar and all that sort of thing
253 are managed by lwlib.)
255 The EmacsShell widget is simply a replacement for the Shell widget
256 which is able to deal with using an externally-supplied window instead
257 of always creating its own. It is not actually emacs specific, and
258 should possibly have class "Shell" instead of "EmacsShell" to simplify
259 the resources.
263 /* Hairily merged geometry */
264 struct frame *f = ew->emacs_frame.frame;
265 int w = FRAME_COLS (f);
266 int h = FRAME_LINES (f);
267 Widget wmshell = get_wm_shell ((Widget) ew);
268 Dimension pixel_width, pixel_height;
269 /* Each Emacs shell is now independent and top-level. */
271 if (! XtIsSubclass (wmshell, shellWidgetClass)) emacs_abort ();
273 char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
274 ew->core.width = (frame_resize_pixelwise
275 ? FRAME_PIXEL_WIDTH (f)
276 : pixel_width);
277 ew->core.height = (frame_resize_pixelwise
278 ? FRAME_PIXEL_HEIGHT (f)
279 : pixel_height);
281 frame_size_history_add
282 (f, Qset_frame_size, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
283 list2 (make_number (ew->core.width), make_number (ew->core.height)));
286 static void
287 update_wm_hints (EmacsFrame ew)
289 Widget wmshell = get_wm_shell ((Widget) ew);
290 int cw;
291 int ch;
292 Dimension rounded_width;
293 Dimension rounded_height;
294 int char_width;
295 int char_height;
296 int base_width;
297 int base_height;
298 int min_rows = 0, min_cols = 0;
300 /* This happens when the frame is just created. */
301 if (! wmshell) return;
303 pixel_to_char_size (ew, ew->core.width, ew->core.height,
304 &char_width, &char_height);
305 char_to_pixel_size (ew, char_width, char_height,
306 &rounded_width, &rounded_height);
307 get_default_char_pixel_size (ew, &cw, &ch);
309 base_width = (wmshell->core.width - ew->core.width
310 + (rounded_width - (char_width * cw)));
311 base_height = (wmshell->core.height - ew->core.height
312 + (rounded_height - (char_height * ch)));
314 /* This is kind of sleazy, but I can't see how else to tell it to
315 make it mark the WM_SIZE_HINTS size as user specified.
317 /* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
319 XtVaSetValues (wmshell,
320 XtNbaseWidth, (XtArgVal) base_width,
321 XtNbaseHeight, (XtArgVal) base_height,
322 XtNwidthInc, (XtArgVal) (frame_resize_pixelwise ? 1 : cw),
323 XtNheightInc, (XtArgVal) (frame_resize_pixelwise ? 1 : ch),
324 XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
325 XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
326 NULL);
329 void
330 widget_update_wm_size_hints (Widget widget)
332 EmacsFrame ew = (EmacsFrame) widget;
333 update_wm_hints (ew);
336 static void
337 update_various_frame_slots (EmacsFrame ew)
339 struct frame *f = ew->emacs_frame.frame;
341 f->internal_border_width = ew->emacs_frame.internal_border_width;
344 static void
345 update_from_various_frame_slots (EmacsFrame ew)
347 struct frame *f = ew->emacs_frame.frame;
348 struct x_output *x = f->output_data.x;
350 ew->core.height = FRAME_PIXEL_HEIGHT (f) - x->menubar_height;
351 ew->core.width = FRAME_PIXEL_WIDTH (f);
352 ew->core.background_pixel = FRAME_BACKGROUND_PIXEL (f);
353 ew->emacs_frame.internal_border_width = f->internal_border_width;
354 ew->emacs_frame.foreground_pixel = FRAME_FOREGROUND_PIXEL (f);
355 ew->emacs_frame.cursor_color = x->cursor_pixel;
356 ew->core.border_pixel = x->border_pixel;
359 static void
360 EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2)
362 EmacsFrame ew = (EmacsFrame) new;
364 if (!ew->emacs_frame.frame)
366 fprintf (stderr,
367 "can't create an emacs frame widget without a frame\n");
368 exit (1);
371 update_from_various_frame_slots (ew);
372 set_frame_size (ew);
375 static void
376 resize_cb (Widget widget,
377 XtPointer closure,
378 XEvent* event,
379 Boolean* continue_to_dispatch)
381 EmacsFrameResize (widget);
385 static void
386 EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs)
388 EmacsFrame ew = (EmacsFrame) widget;
390 /* This used to contain SubstructureRedirectMask, but this turns out
391 to be a problem with XIM on Solaris, and events from that mask
392 don't seem to be used. Let's check that. */
393 attrs->event_mask = (STANDARD_EVENT_SET
394 | PropertyChangeMask
395 | SubstructureNotifyMask);
396 *mask |= CWEventMask;
397 XtCreateWindow (widget, InputOutput, (Visual *) CopyFromParent, *mask,
398 attrs);
399 /* Some ConfigureNotify events does not end up in EmacsFrameResize so
400 make sure we get them all. Seen with xfcwm4 for example. */
401 XtAddRawEventHandler (widget, StructureNotifyMask, False, resize_cb, NULL);
402 update_wm_hints (ew);
405 static void
406 EmacsFrameDestroy (Widget widget)
408 /* All GCs are now freed in x_free_frame_resources. */
411 static void
412 EmacsFrameResize (Widget widget)
414 EmacsFrame ew = (EmacsFrame) widget;
415 struct frame *f = ew->emacs_frame.frame;
416 int width, height;
418 pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height);
420 frame_size_history_add
421 (f, QEmacsFrameResize, width, height,
422 list5 (make_number (ew->core.width), make_number (ew->core.height),
423 make_number (FRAME_TOP_MARGIN_HEIGHT (f)),
424 make_number (FRAME_SCROLL_BAR_AREA_HEIGHT (f)),
425 make_number (2 * FRAME_INTERNAL_BORDER_WIDTH (f))));
427 change_frame_size (f, width, height, 0, 1, 0, 1);
429 update_wm_hints (ew);
430 update_various_frame_slots (ew);
432 cancel_mouse_face (f);
435 static XtGeometryResult
436 EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result)
438 EmacsFrame ew = (EmacsFrame) widget;
440 int mask = request->request_mode;
441 Dimension ok_width, ok_height;
443 if (mask & (CWWidth | CWHeight))
445 if (!frame_resize_pixelwise)
446 round_size_to_char (ew,
447 (mask & CWWidth) ? request->width : ew->core.width,
448 ((mask & CWHeight) ? request->height
449 : ew->core.height),
450 &ok_width, &ok_height);
451 if ((mask & CWWidth) && (ok_width != request->width))
453 result->request_mode |= CWWidth;
454 result->width = ok_width;
456 if ((mask & CWHeight) && (ok_height != request->height))
458 result->request_mode |= CWHeight;
459 result->height = ok_height;
462 return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
465 /* Special entry points */
466 void
467 EmacsFrameSetCharSize (Widget widget, int columns, int rows)
469 EmacsFrame ew = (EmacsFrame) widget;
470 struct frame *f = ew->emacs_frame.frame;
472 if (!frame_inhibit_resize (f, 0, Qfont)
473 && !frame_inhibit_resize (f, 1, Qfont))
474 x_set_window_size (f, 0, columns, rows, 0);
478 void
479 widget_store_internal_border (Widget widget)
481 EmacsFrame ew = (EmacsFrame) widget;
482 struct frame *f = ew->emacs_frame.frame;
484 ew->emacs_frame.internal_border_width = f->internal_border_width;