Fixes: debbugs:17865
[bpt/emacs.git] / src / widget.c
CommitLineData
07bf635f 1/* The emacs frame widget.
ba318903 2 Copyright (C) 1992-1993, 2000-2014 Free Software Foundation, Inc.
07bf635f
RS
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
07bf635f 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
07bf635f
RS
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
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
07bf635f
RS
18
19/* Emacs 19 face widget ported by Fred Pierresteguy */
20
ac26ca64
KH
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.
25
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/
29 */
30
9e65ad77 31#include <config.h>
565620a5 32#include <stdio.h>
0328b6de 33
07bf635f
RS
34#include "lisp.h"
35#include "xterm.h"
36
87a43646 37#include "keyboard.h"
07bf635f 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 52
39d14c25
CY
53#include "character.h"
54#include "font.h"
55
07bf635f
RS
56/* This sucks: this is the first default that x-faces.el tries. This won't
57 be used unless neither the "Emacs.EmacsFrame" resource nor the
58 "Emacs.EmacsFrame" resource is set; the frame
59 may have the wrong default size if this font doesn't exist, but some other
60 font that x-faces.el does. The workaround is to specify some font in the
61 resource database; I don't know a solution other than duplicating the font-
62 searching code from x-faces.el in this file.
63
64 This also means that if "Emacs.EmacsFrame" is specified as a non-
65 existent font, then Xt is going to substitute "XtDefaultFont" for it,
66 which is a different size than this one. The solution for this is to
67 make x-faces.el try to use XtDefaultFont. The problem with that is that
68 XtDefaultFont is almost certainly variable-width.
69
70 #### Perhaps we could have this code explicitly set XtDefaultFont to this?
71 */
72#define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
73
74
ebd15611
DN
75static void EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2);
76static void EmacsFrameDestroy (Widget widget);
77static void EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs);
4475bec4 78static void EmacsFrameResize (Widget widget);
ebd15611
DN
79static Boolean EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget, ArgList dum1, Cardinal *dum2);
80static XtGeometryResult EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result);
07bf635f
RS
81
82
83#undef XtOffset
84#define XtOffset(p_type,field) \
85 ((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
5e617bc2 86#define offset(field) XtOffset (EmacsFrame, emacs_frame.field)
07bf635f
RS
87
88static XtResource resources[] = {
5e617bc2 89 {XtNgeometry, XtCGeometry, XtRString, sizeof (String),
07bf635f 90 offset (geometry), XtRString, (XtPointer) 0},
5e617bc2 91 {XtNiconic, XtCIconic, XtRBoolean, sizeof (Boolean),
07bf635f
RS
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},
5e617bc2
JB
105 {XtNfont, XtCFont, XtRFontStruct, sizeof (struct font *),
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"},
07bf635f
RS
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
4475bec4 137static EmacsFrameClassRec emacsFrameClassRec = {
07bf635f
RS
138 { /* core fields */
139 /* superclass */ &widgetClassRec,
140 /* class_name */ "EmacsFrame",
5e617bc2 141 /* widget_size */ sizeof (EmacsFrameRec),
07bf635f
RS
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,
5e617bc2 151 /* resource_count */ XtNumber (resources),
07bf635f
RS
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
ebd15611 177get_default_char_pixel_size (EmacsFrame ew, int *pixel_width, int *pixel_height)
07bf635f 178{
07bf635f 179 struct frame* f = ew->emacs_frame.frame;
90022f5a
KS
180 *pixel_width = FRAME_COLUMN_WIDTH (f);
181 *pixel_height = FRAME_LINE_HEIGHT (f);
07bf635f
RS
182}
183
184static void
ebd15611 185pixel_to_char_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *char_width, int *char_height)
07bf635f
RS
186{
187 struct frame* f = ew->emacs_frame.frame;
90022f5a
KS
188 *char_width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, (int) pixel_width);
189 *char_height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (int) pixel_height);
07bf635f
RS
190}
191
9b3c0a16
MR
192static void
193pixel_to_text_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *text_width, int *text_height)
194{
195 struct frame* f = ew->emacs_frame.frame;
196 *text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, (int) pixel_width);
197 *text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, (int) pixel_height);
198}
199
07bf635f 200static void
ebd15611 201char_to_pixel_size (EmacsFrame ew, int char_width, int char_height, Dimension *pixel_width, Dimension *pixel_height)
07bf635f
RS
202{
203 struct frame* f = ew->emacs_frame.frame;
90022f5a
KS
204 *pixel_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, char_width);
205 *pixel_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, char_height);
07bf635f
RS
206}
207
208static void
ebd15611 209round_size_to_char (EmacsFrame ew, Dimension in_width, Dimension in_height, Dimension *out_width, Dimension *out_height)
07bf635f
RS
210{
211 int char_width;
212 int char_height;
213 pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
214 char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
215}
216
217static Widget
ebd15611 218get_wm_shell (Widget w)
07bf635f
RS
219{
220 Widget wmshell;
221
222 for (wmshell = XtParent (w);
223 wmshell && !XtIsWMShell (wmshell);
224 wmshell = XtParent (wmshell));
225
226 return wmshell;
227}
228
ccce6056
GM
229#if 0 /* Currently not used. */
230
07bf635f 231static void
1dae0f0a 232mark_shell_size_user_specified (Widget wmshell)
07bf635f 233{
1088b922 234 if (! XtIsWMShell (wmshell)) emacs_abort ();
07bf635f
RS
235 /* This is kind of sleazy, but I can't see how else to tell it to make it
236 mark the WM_SIZE_HINTS size as user specified when appropriate. */
237 ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
238}
239
ccce6056
GM
240#endif
241
07bf635f
RS
242
243/* Can't have static frame locals because of some broken compilers.
244 Normally, initializing a variable like this doesn't work in emacs,
245 but it's ok in this file because it must come after lastfile (and
246 thus have its data not go into text space) because Xt needs to
247 write to initialized data objects too.
248 */
ccce6056 249#if 0
07bf635f 250static Boolean first_frame_p = True;
ccce6056 251#endif
07bf635f
RS
252
253static void
ebd15611 254set_frame_size (EmacsFrame ew)
07bf635f
RS
255{
256 /* The widget hierarchy is
257
258 argv[0] emacsShell pane Frame-NAME
259 ApplicationShell EmacsShell Paned EmacsFrame
260
261 We accept geometry specs in this order:
262
263 *Frame-NAME.geometry
264 *EmacsFrame.geometry
265 Emacs.geometry
266
267 Other possibilities for widget hierarchies might be
268
269 argv[0] frame pane Frame-NAME
270 ApplicationShell EmacsShell Paned EmacsFrame
271 or
272 argv[0] Frame-NAME pane Frame-NAME
273 ApplicationShell EmacsShell Paned EmacsFrame
274 or
275 argv[0] Frame-NAME pane emacsTextPane
276 ApplicationShell EmacsFrame Paned EmacsTextPane
277
278 With the current setup, the text-display-area is the part which is
279 an emacs "frame", since that's the only part managed by emacs proper
280 (the menubar and the parent of the menubar and all that sort of thing
281 are managed by lwlib.)
282
177c0ea7 283 The EmacsShell widget is simply a replacement for the Shell widget
07bf635f
RS
284 which is able to deal with using an externally-supplied window instead
285 of always creating its own. It is not actually emacs specific, and
286 should possibly have class "Shell" instead of "EmacsShell" to simplify
287 the resources.
288
289 */
290
07bf635f 291 /* Hairily merged geometry */
90022f5a
KS
292 unsigned int w = FRAME_COLS (ew->emacs_frame.frame);
293 unsigned int h = FRAME_LINES (ew->emacs_frame.frame);
177c0ea7 294
07bf635f 295 Widget wmshell = get_wm_shell ((Widget) ew);
38971c41 296 /* Each Emacs shell is now independent and top-level. */
177c0ea7 297
1088b922 298 if (! XtIsSubclass (wmshell, shellWidgetClass)) emacs_abort ();
07bf635f 299
177c0ea7 300 /* We don't need this for the moment. The geometry is computed in
edaf359b
FP
301 xfns.c. */
302#if 0
07bf635f
RS
303 /* If the EmacsFrame doesn't have a geometry but the shell does,
304 treat that as the geometry of the frame. (Is this bogus?
305 I'm not sure.) */
306 if (ew->emacs_frame.geometry == 0)
c52e7aa6 307 XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, NULL);
07bf635f
RS
308
309 /* If the Shell is iconic, then the EmacsFrame is iconic. (Is
310 this bogus? I'm not sure.) */
311 if (!ew->emacs_frame.iconic)
c52e7aa6 312 XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, NULL);
177c0ea7
JB
313
314
07bf635f
RS
315 {
316 char *geom = 0;
c52e7aa6 317 XtVaGetValues (app_shell, XtNgeometry, &geom, NULL);
07bf635f
RS
318 if (geom)
319 app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
320 }
177c0ea7 321
07bf635f
RS
322 if (ew->emacs_frame.geometry)
323 frame_flags = XParseGeometry (ew->emacs_frame.geometry,
324 &frame_x, &frame_y,
325 &frame_w, &frame_h);
177c0ea7 326
07bf635f
RS
327 if (first_frame_p)
328 {
329 /* If this is the first frame created:
330 ====================================
331
332 - Use the ApplicationShell's size/position, if specified.
333 (This is "Emacs.geometry", or the "-geometry" command line arg.)
334 - Else use the EmacsFrame's size/position.
335 (This is "*Frame-NAME.geometry")
336
337 - If the AppShell is iconic, the frame should be iconic.
338
339 AppShell comes first so that -geometry always applies to the first
340 frame created, even if there is an "every frame" entry in the
341 resource database.
342 */
343 if (app_flags & (XValue | YValue))
344 {
345 x = app_x; y = app_y;
346 flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
347 }
348 else if (frame_flags & (XValue | YValue))
349 {
350 x = frame_x; y = frame_y;
351 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
352 }
353
354 if (app_flags & (WidthValue | HeightValue))
355 {
356 w = app_w; h = app_h;
357 flags |= (app_flags & (WidthValue | HeightValue));
358 }
359 else if (frame_flags & (WidthValue | HeightValue))
360 {
361 w = frame_w; h = frame_h;
362 flags |= (frame_flags & (WidthValue | HeightValue));
363 }
364
365 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
366 if (!ew->emacs_frame.iconic)
c52e7aa6 367 XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, NULL);
07bf635f
RS
368
369 first_frame_p = False;
370 }
371 else
372 {
373 /* If this is not the first frame created:
374 ========================================
375
376 - use the EmacsFrame's size/position if specified
377 - Otherwise, use the ApplicationShell's size, but not position.
378
379 So that means that one can specify the position of the first frame
380 with "Emacs.geometry" or `-geometry'; but can only specify the
381 position of subsequent frames with "*Frame-NAME.geometry".
382
383 AppShell comes second so that -geometry does not apply to subsequent
384 frames when there is an "every frame" entry in the resource db,
385 but does apply to the first frame.
386 */
387 if (frame_flags & (XValue | YValue))
388 {
389 x = frame_x; y = frame_y;
390 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
391 }
392
393 if (frame_flags & (WidthValue | HeightValue))
394 {
395 w = frame_w; h = frame_h;
396 flags |= (frame_flags & (WidthValue | HeightValue));
397 }
398 else if (app_flags & (WidthValue | HeightValue))
399 {
400 w = app_w;
401 h = app_h;
402 flags |= (app_flags & (WidthValue | HeightValue));
403 }
404 }
edaf359b 405#endif /* 0 */
07bf635f 406 {
90022f5a 407 struct frame *f = ew->emacs_frame.frame;
07bf635f 408 Dimension pixel_width, pixel_height;
07bf635f 409
f403d3c3
GM
410 /* Take into account the size of the scrollbar. Always use the
411 number of columns occupied by the scroll bar here otherwise we
412 might end up with a frame width that is not a multiple of the
413 frame's character width which is bad for vertically split
414 windows. */
07bf635f 415
90022f5a 416 compute_fringe_widths (f, 0);
f403d3c3 417
de70f8b6
RS
418#if 0 /* This can run Lisp code, and it is dangerous to give
419 out the frame to Lisp code before it officially exists.
420 This is handled in Fx_create_frame so not needed here. */
880e6158 421 change_frame_size (f, w, h, 1, 0, 0, 0);
de70f8b6 422#endif
07bf635f
RS
423 char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
424 ew->core.width = pixel_width;
425 ew->core.height = pixel_height;
426
6ae9a3f2 427#if 0 /* xfns.c takes care of this now. */
07bf635f
RS
428 /* If a position was specified, assign it to the shell widget.
429 (Else WM won't do anything with it.)
430 */
431 if (flags & (XValue | YValue))
432 {
433 /* the tricky things with the sign is to make sure that
434 -0 is printed -0. */
07bf635f
RS
435 sprintf (shell_position, "=%c%d%c%d",
436 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
437 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
e99a530f 438 XtVaSetValues (wmshell, XtNgeometry, xstrdup (shell_position), NULL);
07bf635f
RS
439 }
440 else if (flags & (WidthValue | HeightValue))
441 {
07bf635f 442 sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
e99a530f 443 XtVaSetValues (wmshell, XtNgeometry, xstrdup (shell_position), NULL);
07bf635f
RS
444 }
445
446 /* If the geometry spec we're using has W/H components, mark the size
447 in the WM_SIZE_HINTS as user specified. */
448 if (flags & (WidthValue | HeightValue))
449 mark_shell_size_user_specified (wmshell);
450
451 /* Also assign the iconic status of the frame to the Shell, so that
452 the WM sees it. */
c52e7aa6 453 XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, NULL);
edaf359b 454#endif /* 0 */
07bf635f
RS
455 }
456}
457
07bf635f 458static void
ebd15611 459update_wm_hints (EmacsFrame ew)
07bf635f
RS
460{
461 Widget wmshell = get_wm_shell ((Widget)ew);
462 int cw;
463 int ch;
464 Dimension rounded_width;
465 Dimension rounded_height;
466 int char_width;
467 int char_height;
468 int base_width;
469 int base_height;
470 int min_rows = 0, min_cols = 0;
471
c052ead4
JD
472 /* This happens when the frame is just created. */
473 if (! wmshell) return;
474
cfcd12d6 475#if 0
880e6158 476 check_frame_size (ew->emacs_frame.frame, &min_cols, &min_rows, 0);
cfcd12d6 477#endif
07bf635f
RS
478
479 pixel_to_char_size (ew, ew->core.width, ew->core.height,
480 &char_width, &char_height);
481 char_to_pixel_size (ew, char_width, char_height,
482 &rounded_width, &rounded_height);
177c0ea7 483 get_default_char_pixel_size (ew, &cw, &ch);
07bf635f
RS
484
485 base_width = (wmshell->core.width - ew->core.width
486 + (rounded_width - (char_width * cw)));
487 base_height = (wmshell->core.height - ew->core.height
488 + (rounded_height - (char_height * ch)));
489
490 /* This is kind of sleazy, but I can't see how else to tell it to
491 make it mark the WM_SIZE_HINTS size as user specified.
492 */
493/* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
494
495 XtVaSetValues (wmshell,
cbec8c51
GM
496 XtNbaseWidth, (XtArgVal) base_width,
497 XtNbaseHeight, (XtArgVal) base_height,
9b3c0a16
MR
498 XtNwidthInc, (XtArgVal) (frame_resize_pixelwise ? 1 : cw),
499 XtNheightInc, (XtArgVal) (frame_resize_pixelwise ? 1 : ch),
cbec8c51
GM
500 XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
501 XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
c52e7aa6 502 NULL);
07bf635f
RS
503}
504
c052ead4
JD
505void
506widget_update_wm_size_hints (Widget widget)
507{
508 EmacsFrame ew = (EmacsFrame)widget;
509 update_wm_hints (ew);
510}
511
1ad2277b
RS
512static char setup_frame_cursor_bits[] =
513{
514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
518};
519
07bf635f 520static void
ebd15611 521setup_frame_gcs (EmacsFrame ew)
07bf635f
RS
522{
523 XGCValues gc_values;
524 struct frame* s = ew->emacs_frame.frame;
525 Pixmap blank_stipple, blank_tile;
39d14c25
CY
526 unsigned long valuemask = (GCForeground | GCBackground | GCGraphicsExposures
527 | GCStipple | GCTile);
528 Lisp_Object font;
529
530 XSETFONT (font, ew->emacs_frame.font);
531 font = Ffont_xlfd_name (font, Qnil);
532 if (STRINGP (font))
533 {
aad3612f 534 XFontStruct *xfont = XLoadQueryFont (FRAME_DISPLAY_INFO (s)->display,
42a5b22f 535 SSDATA (font));
39d14c25
CY
536 if (xfont)
537 {
538 gc_values.font = xfont->fid;
539 valuemask |= GCFont;
540 }
541 }
07bf635f 542
07bf635f
RS
543 /* We have to initialize all of our GCs to have a stipple/tile, otherwise
544 XGetGCValues returns uninitialized data when we query the stipple
545 (instead of None or something sensible) and it makes things hard.
546
547 This should be fixed for real by not querying the GCs but instead having
548 some GC-based cache instead of the current face-based cache which doesn't
549 effectively cache all of the GC settings we need to use.
550 */
551
85e53327
KH
552 blank_stipple
553 = XCreateBitmapFromData (XtDisplay (ew),
554 RootWindowOfScreen (XtScreen (ew)),
555 setup_frame_cursor_bits, 2, 2);
07bf635f
RS
556
557 /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
558 never actually get used as a background tile!
559 */
85e53327 560 blank_tile
5e617bc2 561 = XCreatePixmapFromBitmapData (XtDisplay (ew),
85e53327
KH
562 RootWindowOfScreen (XtScreen (ew)),
563 setup_frame_cursor_bits, 2, 2,
578c21e6 564 0, 1, ew->core.depth);
07bf635f
RS
565
566 /* Normal video */
07bf635f
RS
567 gc_values.foreground = ew->emacs_frame.foreground_pixel;
568 gc_values.background = ew->core.background_pixel;
569 gc_values.graphics_exposures = False;
570 gc_values.stipple = blank_stipple;
571 gc_values.tile = blank_tile;
54e9e953 572 XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
39d14c25 573 valuemask, &gc_values);
07bf635f
RS
574
575 /* Reverse video style. */
07bf635f
RS
576 gc_values.foreground = ew->core.background_pixel;
577 gc_values.background = ew->emacs_frame.foreground_pixel;
578 gc_values.graphics_exposures = False;
579 gc_values.stipple = blank_stipple;
580 gc_values.tile = blank_tile;
54e9e953 581 XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
39d14c25 582 valuemask, &gc_values);
07bf635f
RS
583
584 /* Cursor has to have an empty stipple. */
07bf635f
RS
585 gc_values.foreground = ew->core.background_pixel;
586 gc_values.background = ew->emacs_frame.cursor_color;
587 gc_values.graphics_exposures = False;
588 gc_values.tile = blank_tile;
85e53327
KH
589 gc_values.stipple
590 = XCreateBitmapFromData (XtDisplay (ew),
591 RootWindowOfScreen (XtScreen (ew)),
592 setup_frame_cursor_bits, 16, 16);
54e9e953 593 XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
39d14c25 594 valuemask, &gc_values);
07bf635f
RS
595}
596
597static void
ebd15611 598update_various_frame_slots (EmacsFrame ew)
07bf635f 599{
90022f5a 600 struct frame *f = ew->emacs_frame.frame;
d2f720ac 601
5185f8ed
MR
602 /* Don't do that: It confuses the check in change_frame_size_1 whether
603 the pixel size of the frame changed due to a change of the internal
604 border width. Bug#16736. */
d2f720ac
PE
605 if (false)
606 {
607 struct x_output *x = f->output_data.x;
608 FRAME_PIXEL_HEIGHT (f) = ew->core.height + x->menubar_height;
609 FRAME_PIXEL_WIDTH (f) = ew->core.width;
610 }
07bf635f 611
d2f720ac 612 f->internal_border_width = ew->emacs_frame.internal_border_width;
07bf635f
RS
613}
614
615static void
ebd15611 616update_from_various_frame_slots (EmacsFrame ew)
07bf635f 617{
90022f5a
KS
618 struct frame *f = ew->emacs_frame.frame;
619 struct x_output *x = f->output_data.x;
620 ew->core.height = FRAME_PIXEL_HEIGHT (f) - x->menubar_height;
621 ew->core.width = FRAME_PIXEL_WIDTH (f);
ce593f6e 622 ew->core.background_pixel = FRAME_BACKGROUND_PIXEL (f);
90022f5a 623 ew->emacs_frame.internal_border_width = f->internal_border_width;
07bf635f 624 ew->emacs_frame.font = x->font;
ce593f6e 625 ew->emacs_frame.foreground_pixel = FRAME_FOREGROUND_PIXEL (f);
07bf635f
RS
626 ew->emacs_frame.cursor_color = x->cursor_pixel;
627 ew->core.border_pixel = x->border_pixel;
628}
629
177c0ea7 630static void
ebd15611 631EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2)
07bf635f
RS
632{
633 EmacsFrame ew = (EmacsFrame)new;
634
635 if (!ew->emacs_frame.frame)
636 {
637 fprintf (stderr,
638 "can't create an emacs frame widget without a frame\n");
639 exit (1);
640 }
641
07bf635f 642 update_from_various_frame_slots (ew);
177c0ea7 643 set_frame_size (ew);
07bf635f
RS
644}
645
ad10696b
JD
646static void
647resize_cb (Widget widget,
648 XtPointer closure,
649 XEvent* event,
650 Boolean* continue_to_dispatch)
651{
ad10696b
JD
652 EmacsFrameResize (widget);
653}
654
07bf635f
RS
655
656static void
ebd15611 657EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs)
07bf635f
RS
658{
659 EmacsFrame ew = (EmacsFrame)widget;
660
486a103d
GM
661 /* This used to contain SubstructureRedirectMask, but this turns out
662 to be a problem with XIM on Solaris, and events from that mask
2fce2bb4 663 don't seem to be used. Let's check that. */
486a103d
GM
664 attrs->event_mask = (STANDARD_EVENT_SET
665 | PropertyChangeMask
666 | SubstructureNotifyMask);
07bf635f
RS
667 *mask |= CWEventMask;
668 XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
669 attrs);
ad10696b
JD
670 /* Some ConfigureNotify events does not end up in EmacsFrameResize so
671 make sure we get them all. Seen with xfcwm4 for example. */
672 XtAddRawEventHandler (widget, StructureNotifyMask, False, resize_cb, NULL);
177c0ea7 673 update_wm_hints (ew);
07bf635f
RS
674}
675
07bf635f 676static void
ebd15611 677EmacsFrameDestroy (Widget widget)
07bf635f 678{
4b5c9326 679 /* All GCs are now freed in x_free_frame_resources. */
07bf635f
RS
680}
681
4475bec4 682static void
ebd15611 683EmacsFrameResize (Widget widget)
07bf635f
RS
684{
685 EmacsFrame ew = (EmacsFrame)widget;
686 struct frame *f = ew->emacs_frame.frame;
9b3c0a16 687
d2f720ac
PE
688 /* Always process resize requests pixelwise. Frame maximizing
689 should work even when frame_resize_pixelwise is nil. */
690 if (true || frame_resize_pixelwise)
ad10696b 691 {
9b3c0a16
MR
692 int width, height;
693
694 pixel_to_text_size (ew, ew->core.width, ew->core.height, &width, &height);
695 change_frame_size (f, width, height, 0, 1, 0, 1);
696
ad10696b
JD
697 update_wm_hints (ew);
698 update_various_frame_slots (ew);
49feb47d 699
ad10696b
JD
700 cancel_mouse_face (f);
701 }
9b3c0a16
MR
702 else
703 {
d2f720ac 704 struct x_output *x = f->output_data.x;
9b3c0a16
MR
705 int columns, rows;
706
707 pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
708 if (columns != FRAME_COLS (f)
709 || rows != FRAME_LINES (f)
710 || ew->core.width != FRAME_PIXEL_WIDTH (f)
711 || ew->core.height + x->menubar_height != FRAME_PIXEL_HEIGHT (f))
712 {
713 change_frame_size (f, columns, rows, 0, 1, 0, 0);
714 update_wm_hints (ew);
715 update_various_frame_slots (ew);
716
717 cancel_mouse_face (f);
718 }
719 }
07bf635f
RS
720}
721
722static Boolean
ebd15611 723EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget, ArgList dum1, Cardinal *dum2)
07bf635f
RS
724{
725 EmacsFrame cur = (EmacsFrame)cur_widget;
726 EmacsFrame new = (EmacsFrame)new_widget;
727
728 Boolean needs_a_refresh = False;
729 Boolean has_to_recompute_size;
730 Boolean has_to_recompute_gcs;
731 Boolean has_to_update_hints;
732
733 int char_width, char_height;
734 Dimension pixel_width;
735 Dimension pixel_height;
177c0ea7 736
5c646d5a 737 /* AFAIK, this function is never called. -- Jan D, Oct 2009. */
07bf635f
RS
738 has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
739 || (cur->emacs_frame.foreground_pixel
740 != new->emacs_frame.foreground_pixel)
741 || (cur->core.background_pixel
742 != new->core.background_pixel)
743 );
177c0ea7 744
07bf635f
RS
745 has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
746 && cur->core.width == new->core.width
747 && cur->core.height == new->core.height);
748
749 has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);
750
751 if (has_to_recompute_gcs)
752 {
753 setup_frame_gcs (new);
754 needs_a_refresh = True;
755 }
177c0ea7 756
07bf635f
RS
757 if (has_to_recompute_size)
758 {
9b3c0a16 759 /* Don't do this pixelwise, hopefully. */
07bf635f
RS
760 pixel_width = new->core.width;
761 pixel_height = new->core.height;
762 pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
763 &char_height);
764 char_to_pixel_size (new, char_width, char_height, &pixel_width,
765 &pixel_height);
766 new->core.width = pixel_width;
767 new->core.height = pixel_height;
768
880e6158
MR
769 change_frame_size (new->emacs_frame.frame, char_width, char_height,
770 1, 0, 0, 0);
07bf635f
RS
771 needs_a_refresh = True;
772 }
773
774 if (has_to_update_hints)
775 update_wm_hints (new);
776
777 update_various_frame_slots (new);
778
779 /* #### This doesn't work, I haven't been able to find ANY kludge that
780 will let (x-create-frame '((iconic . t))) work. It seems that changes
781 to wm_shell's iconic slot have no effect after it has been realized,
2dd5c7f7 782 and calling XIconifyWindow doesn't work either (even though the window
07bf635f 783 has been created.) Perhaps there is some property we could smash
ac26ca64 784 directly, but I'm sick of this for now.
07bf635f
RS
785 */
786 if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
787 {
788 Widget wmshell = get_wm_shell ((Widget) cur);
cbec8c51
GM
789 XtVaSetValues (wmshell, XtNiconic,
790 (XtArgVal) new->emacs_frame.iconic, NULL);
07bf635f
RS
791 }
792
793 return needs_a_refresh;
794}
795
796static XtGeometryResult
ebd15611 797EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result)
07bf635f
RS
798{
799 EmacsFrame ew = (EmacsFrame)widget;
800
801 int mask = request->request_mode;
802 Dimension ok_width, ok_height;
803
804 if (mask & (CWWidth | CWHeight))
805 {
806 round_size_to_char (ew,
807 (mask & CWWidth) ? request->width : ew->core.width,
808 ((mask & CWHeight) ? request->height
809 : ew->core.height),
810 &ok_width, &ok_height);
811 if ((mask & CWWidth) && (ok_width != request->width))
812 {
813 result->request_mode |= CWWidth;
814 result->width = ok_width;
815 }
816 if ((mask & CWHeight) && (ok_height != request->height))
817 {
818 result->request_mode |= CWHeight;
819 result->height = ok_height;
820 }
821 }
822 return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
823}
824
e4769531 825/* Special entry points */
07bf635f 826void
ebd15611 827EmacsFrameSetCharSize (Widget widget, int columns, int rows)
07bf635f
RS
828{
829 EmacsFrame ew = (EmacsFrame) widget;
982a94d9 830 struct frame *f = ew->emacs_frame.frame;
177c0ea7 831
880e6158 832 x_set_window_size (f, 0, columns, rows, 0);
07bf635f 833}
f403d3c3 834
d793b105 835\f
dfcf069d 836void
ebd15611 837widget_store_internal_border (Widget widget)
d793b105
RS
838{
839 EmacsFrame ew = (EmacsFrame) widget;
a10c8269 840 struct frame *f = ew->emacs_frame.frame;
d793b105 841
90022f5a 842 ew->emacs_frame.internal_border_width = f->internal_border_width;
d793b105 843}