Merge from trunk.
[bpt/emacs.git] / src / widget.c
1 /* The emacs frame widget.
2 Copyright (C) 1992-1993, 2000-2011 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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
9 (at your option) any later version.
10
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.
15
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/>. */
18
19 /* Emacs 19 face widget ported by Fred Pierresteguy */
20
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
31 #include <config.h>
32 #include <stdio.h>
33 #include <setjmp.h>
34 #include "lisp.h"
35 #include "xterm.h"
36
37 #include "keyboard.h"
38 #include "frame.h"
39 #include "window.h"
40
41 #include "dispextern.h"
42 #include "blockinput.h"
43
44 #include <X11/StringDefs.h>
45 #include <X11/IntrinsicP.h>
46 #include <X11/cursorfont.h>
47 #include "widgetprv.h"
48 #include <X11/ObjectP.h>
49 #include <X11/Shell.h>
50 #include <X11/ShellP.h>
51 #include "../lwlib/lwlib.h"
52
53 #include <signal.h>
54 #include "syssignal.h"
55
56 #include "character.h"
57 #include "font.h"
58
59 /* This sucks: this is the first default that x-faces.el tries. This won't
60 be used unless neither the "Emacs.EmacsFrame" resource nor the
61 "Emacs.EmacsFrame" resource is set; the frame
62 may have the wrong default size if this font doesn't exist, but some other
63 font that x-faces.el does. The workaround is to specify some font in the
64 resource database; I don't know a solution other than duplicating the font-
65 searching code from x-faces.el in this file.
66
67 This also means that if "Emacs.EmacsFrame" is specified as a non-
68 existent font, then Xt is going to substitute "XtDefaultFont" for it,
69 which is a different size than this one. The solution for this is to
70 make x-faces.el try to use XtDefaultFont. The problem with that is that
71 XtDefaultFont is almost certainly variable-width.
72
73 #### Perhaps we could have this code explicitly set XtDefaultFont to this?
74 */
75 #define DEFAULT_FACE_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-*"
76
77
78 static void EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2);
79 static void EmacsFrameDestroy (Widget widget);
80 static void EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs);
81 static void EmacsFrameResize (Widget widget);
82 static Boolean EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget, ArgList dum1, Cardinal *dum2);
83 static XtGeometryResult EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result);
84
85
86 #undef XtOffset
87 #define XtOffset(p_type,field) \
88 ((Cardinal) (((char *) (&(((p_type)0)->field))) - ((char *)0)))
89 #define offset(field) XtOffset(EmacsFrame, emacs_frame.field)
90
91 static XtResource resources[] = {
92 {XtNgeometry, XtCGeometry, XtRString, sizeof(String),
93 offset (geometry), XtRString, (XtPointer) 0},
94 {XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
95 offset (iconic), XtRImmediate, (XtPointer) False},
96
97 {XtNemacsFrame, XtCEmacsFrame, XtRPointer, sizeof (XtPointer),
98 offset (frame), XtRImmediate, 0},
99
100 {XtNminibuffer, XtCMinibuffer, XtRInt, sizeof (int),
101 offset (minibuffer), XtRImmediate, (XtPointer)0},
102 {XtNunsplittable, XtCUnsplittable, XtRBoolean, sizeof (Boolean),
103 offset (unsplittable), XtRImmediate, (XtPointer)0},
104 {XtNinternalBorderWidth, XtCInternalBorderWidth, XtRInt, sizeof (int),
105 offset (internal_border_width), XtRImmediate, (XtPointer)4},
106 {XtNinterline, XtCInterline, XtRInt, sizeof (int),
107 offset (interline), XtRImmediate, (XtPointer)0},
108 {XtNfont, XtCFont, XtRFontStruct, sizeof(struct font *),
109 offset(font),XtRString, DEFAULT_FACE_FONT},
110 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
111 offset(foreground_pixel), XtRString, "XtDefaultForeground"},
112 {XtNcursorColor, XtCForeground, XtRPixel, sizeof(Pixel),
113 offset(cursor_color), XtRString, "XtDefaultForeground"},
114 {XtNbarCursor, XtCBarCursor, XtRBoolean, sizeof (Boolean),
115 offset (bar_cursor), XtRImmediate, (XtPointer)0},
116 {XtNvisualBell, XtCVisualBell, XtRBoolean, sizeof (Boolean),
117 offset (visual_bell), XtRImmediate, (XtPointer)0},
118 {XtNbellVolume, XtCBellVolume, XtRInt, sizeof (int),
119 offset (bell_volume), XtRImmediate, (XtPointer)0},
120 };
121
122 #undef offset
123
124 /*
125 static XtActionsRec
126 emacsFrameActionsTable [] = {
127 {"keypress", key_press},
128 {"focus_in", emacs_frame_focus_handler},
129 {"focus_out", emacs_frame_focus_handler},
130 };
131
132 static char
133 emacsFrameTranslations [] = "\
134 <KeyPress>: keypress()\n\
135 <FocusIn>: focus_in()\n\
136 <FocusOut>: focus_out()\n\
137 ";
138 */
139
140 static EmacsFrameClassRec emacsFrameClassRec = {
141 { /* core fields */
142 /* superclass */ &widgetClassRec,
143 /* class_name */ "EmacsFrame",
144 /* widget_size */ sizeof(EmacsFrameRec),
145 /* class_initialize */ 0,
146 /* class_part_initialize */ 0,
147 /* class_inited */ FALSE,
148 /* initialize */ EmacsFrameInitialize,
149 /* initialize_hook */ 0,
150 /* realize */ EmacsFrameRealize,
151 /* actions */ 0, /*emacsFrameActionsTable*/
152 /* num_actions */ 0, /*XtNumber (emacsFrameActionsTable)*/
153 /* resources */ resources,
154 /* resource_count */ XtNumber(resources),
155 /* xrm_class */ NULLQUARK,
156 /* compress_motion */ TRUE,
157 /* compress_exposure */ TRUE,
158 /* compress_enterleave */ TRUE,
159 /* visible_interest */ FALSE,
160 /* destroy */ EmacsFrameDestroy,
161 /* resize */ EmacsFrameResize,
162 /* expose */ XtInheritExpose,
163 /* set_values */ EmacsFrameSetValues,
164 /* set_values_hook */ 0,
165 /* set_values_almost */ XtInheritSetValuesAlmost,
166 /* get_values_hook */ 0,
167 /* accept_focus */ XtInheritAcceptFocus,
168 /* version */ XtVersion,
169 /* callback_private */ 0,
170 /* tm_table */ 0, /*emacsFrameTranslations*/
171 /* query_geometry */ EmacsFrameQueryGeometry,
172 /* display_accelerator */ XtInheritDisplayAccelerator,
173 /* extension */ 0
174 }
175 };
176
177 WidgetClass emacsFrameClass = (WidgetClass) &emacsFrameClassRec;
178
179 static void
180 get_default_char_pixel_size (EmacsFrame ew, int *pixel_width, int *pixel_height)
181 {
182 struct frame* f = ew->emacs_frame.frame;
183 *pixel_width = FRAME_COLUMN_WIDTH (f);
184 *pixel_height = FRAME_LINE_HEIGHT (f);
185 }
186
187 static void
188 pixel_to_char_size (EmacsFrame ew, Dimension pixel_width, Dimension pixel_height, int *char_width, int *char_height)
189 {
190 struct frame* f = ew->emacs_frame.frame;
191 *char_width = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, (int) pixel_width);
192 *char_height = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (int) pixel_height);
193 }
194
195 static void
196 char_to_pixel_size (EmacsFrame ew, int char_width, int char_height, Dimension *pixel_width, Dimension *pixel_height)
197 {
198 struct frame* f = ew->emacs_frame.frame;
199 *pixel_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, char_width);
200 *pixel_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, char_height);
201 }
202
203 static void
204 round_size_to_char (EmacsFrame ew, Dimension in_width, Dimension in_height, Dimension *out_width, Dimension *out_height)
205 {
206 int char_width;
207 int char_height;
208 pixel_to_char_size (ew, in_width, in_height, &char_width, &char_height);
209 char_to_pixel_size (ew, char_width, char_height, out_width, out_height);
210 }
211
212 static Widget
213 get_wm_shell (Widget w)
214 {
215 Widget wmshell;
216
217 for (wmshell = XtParent (w);
218 wmshell && !XtIsWMShell (wmshell);
219 wmshell = XtParent (wmshell));
220
221 return wmshell;
222 }
223
224 #if 0 /* Currently not used. */
225
226 static void
227 mark_shell_size_user_specified (wmshell)
228 Widget wmshell;
229 {
230 if (! XtIsWMShell (wmshell)) abort ();
231 /* This is kind of sleazy, but I can't see how else to tell it to make it
232 mark the WM_SIZE_HINTS size as user specified when appropriate. */
233 ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;
234 }
235
236 #endif
237
238
239 /* Can't have static frame locals because of some broken compilers.
240 Normally, initializing a variable like this doesn't work in emacs,
241 but it's ok in this file because it must come after lastfile (and
242 thus have its data not go into text space) because Xt needs to
243 write to initialized data objects too.
244 */
245 #if 0
246 static Boolean first_frame_p = True;
247 #endif
248
249 static void
250 set_frame_size (EmacsFrame ew)
251 {
252 /* The widget hierarchy is
253
254 argv[0] emacsShell pane Frame-NAME
255 ApplicationShell EmacsShell Paned EmacsFrame
256
257 We accept geometry specs in this order:
258
259 *Frame-NAME.geometry
260 *EmacsFrame.geometry
261 Emacs.geometry
262
263 Other possibilities for widget hierarchies might be
264
265 argv[0] frame pane Frame-NAME
266 ApplicationShell EmacsShell Paned EmacsFrame
267 or
268 argv[0] Frame-NAME pane Frame-NAME
269 ApplicationShell EmacsShell Paned EmacsFrame
270 or
271 argv[0] Frame-NAME pane emacsTextPane
272 ApplicationShell EmacsFrame Paned EmacsTextPane
273
274 With the current setup, the text-display-area is the part which is
275 an emacs "frame", since that's the only part managed by emacs proper
276 (the menubar and the parent of the menubar and all that sort of thing
277 are managed by lwlib.)
278
279 The EmacsShell widget is simply a replacement for the Shell widget
280 which is able to deal with using an externally-supplied window instead
281 of always creating its own. It is not actually emacs specific, and
282 should possibly have class "Shell" instead of "EmacsShell" to simplify
283 the resources.
284
285 */
286
287 /* Hairily merged geometry */
288 unsigned int w = FRAME_COLS (ew->emacs_frame.frame);
289 unsigned int h = FRAME_LINES (ew->emacs_frame.frame);
290
291 Widget wmshell = get_wm_shell ((Widget) ew);
292 /* Each Emacs shell is now independent and top-level. */
293
294 if (! XtIsSubclass (wmshell, shellWidgetClass)) abort ();
295
296 /* We don't need this for the moment. The geometry is computed in
297 xfns.c. */
298 #if 0
299 /* If the EmacsFrame doesn't have a geometry but the shell does,
300 treat that as the geometry of the frame. (Is this bogus?
301 I'm not sure.) */
302 if (ew->emacs_frame.geometry == 0)
303 XtVaGetValues (wmshell, XtNgeometry, &ew->emacs_frame.geometry, NULL);
304
305 /* If the Shell is iconic, then the EmacsFrame is iconic. (Is
306 this bogus? I'm not sure.) */
307 if (!ew->emacs_frame.iconic)
308 XtVaGetValues (wmshell, XtNiconic, &ew->emacs_frame.iconic, NULL);
309
310
311 {
312 char *geom = 0;
313 XtVaGetValues (app_shell, XtNgeometry, &geom, NULL);
314 if (geom)
315 app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
316 }
317
318 if (ew->emacs_frame.geometry)
319 frame_flags = XParseGeometry (ew->emacs_frame.geometry,
320 &frame_x, &frame_y,
321 &frame_w, &frame_h);
322
323 if (first_frame_p)
324 {
325 /* If this is the first frame created:
326 ====================================
327
328 - Use the ApplicationShell's size/position, if specified.
329 (This is "Emacs.geometry", or the "-geometry" command line arg.)
330 - Else use the EmacsFrame's size/position.
331 (This is "*Frame-NAME.geometry")
332
333 - If the AppShell is iconic, the frame should be iconic.
334
335 AppShell comes first so that -geometry always applies to the first
336 frame created, even if there is an "every frame" entry in the
337 resource database.
338 */
339 if (app_flags & (XValue | YValue))
340 {
341 x = app_x; y = app_y;
342 flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
343 }
344 else if (frame_flags & (XValue | YValue))
345 {
346 x = frame_x; y = frame_y;
347 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
348 }
349
350 if (app_flags & (WidthValue | HeightValue))
351 {
352 w = app_w; h = app_h;
353 flags |= (app_flags & (WidthValue | HeightValue));
354 }
355 else if (frame_flags & (WidthValue | HeightValue))
356 {
357 w = frame_w; h = frame_h;
358 flags |= (frame_flags & (WidthValue | HeightValue));
359 }
360
361 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
362 if (!ew->emacs_frame.iconic)
363 XtVaGetValues (app_shell, XtNiconic, &ew->emacs_frame.iconic, NULL);
364
365 first_frame_p = False;
366 }
367 else
368 {
369 /* If this is not the first frame created:
370 ========================================
371
372 - use the EmacsFrame's size/position if specified
373 - Otherwise, use the ApplicationShell's size, but not position.
374
375 So that means that one can specify the position of the first frame
376 with "Emacs.geometry" or `-geometry'; but can only specify the
377 position of subsequent frames with "*Frame-NAME.geometry".
378
379 AppShell comes second so that -geometry does not apply to subsequent
380 frames when there is an "every frame" entry in the resource db,
381 but does apply to the first frame.
382 */
383 if (frame_flags & (XValue | YValue))
384 {
385 x = frame_x; y = frame_y;
386 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
387 }
388
389 if (frame_flags & (WidthValue | HeightValue))
390 {
391 w = frame_w; h = frame_h;
392 flags |= (frame_flags & (WidthValue | HeightValue));
393 }
394 else if (app_flags & (WidthValue | HeightValue))
395 {
396 w = app_w;
397 h = app_h;
398 flags |= (app_flags & (WidthValue | HeightValue));
399 }
400 }
401 #endif /* 0 */
402 {
403 struct frame *f = ew->emacs_frame.frame;
404 Dimension pixel_width, pixel_height;
405
406 /* Take into account the size of the scrollbar. Always use the
407 number of columns occupied by the scroll bar here otherwise we
408 might end up with a frame width that is not a multiple of the
409 frame's character width which is bad for vertically split
410 windows. */
411 f->scroll_bar_actual_width
412 = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
413
414 compute_fringe_widths (f, 0);
415
416 #if 0 /* This can run Lisp code, and it is dangerous to give
417 out the frame to Lisp code before it officially exists.
418 This is handled in Fx_create_frame so not needed here. */
419 change_frame_size (f, h, w, 1, 0, 0);
420 #endif
421 char_to_pixel_size (ew, w, h, &pixel_width, &pixel_height);
422 ew->core.width = pixel_width;
423 ew->core.height = pixel_height;
424
425 #if 0 /* xfns.c takes care of this now. */
426 /* If a position was specified, assign it to the shell widget.
427 (Else WM won't do anything with it.)
428 */
429 if (flags & (XValue | YValue))
430 {
431 /* the tricky things with the sign is to make sure that
432 -0 is printed -0. */
433 int len;
434 char *tem;
435 sprintf (shell_position, "=%c%d%c%d",
436 flags & XNegative ? '-' : '+', x < 0 ? -x : x,
437 flags & YNegative ? '-' : '+', y < 0 ? -y : y);
438 len = strlen (shell_position) + 1;
439 tem = (char *) xmalloc (len);
440 strncpy (tem, shell_position, len);
441 XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
442 }
443 else if (flags & (WidthValue | HeightValue))
444 {
445 int len;
446 char *tem;
447 sprintf (shell_position, "=%dx%d", pixel_width, pixel_height);
448 len = strlen (shell_position) + 1;
449 tem = (char *) xmalloc (len);
450 strncpy (tem, shell_position, len);
451 XtVaSetValues (wmshell, XtNgeometry, tem, NULL);
452 }
453
454 /* If the geometry spec we're using has W/H components, mark the size
455 in the WM_SIZE_HINTS as user specified. */
456 if (flags & (WidthValue | HeightValue))
457 mark_shell_size_user_specified (wmshell);
458
459 /* Also assign the iconic status of the frame to the Shell, so that
460 the WM sees it. */
461 XtVaSetValues (wmshell, XtNiconic, ew->emacs_frame.iconic, NULL);
462 #endif /* 0 */
463 }
464 }
465
466 static void
467 update_wm_hints (EmacsFrame ew)
468 {
469 Widget wmshell = get_wm_shell ((Widget)ew);
470 int cw;
471 int ch;
472 Dimension rounded_width;
473 Dimension rounded_height;
474 int char_width;
475 int char_height;
476 int base_width;
477 int base_height;
478 int min_rows = 0, min_cols = 0;
479
480 #if 0
481 check_frame_size (ew->emacs_frame.frame, &min_rows, &min_cols);
482 #endif
483
484 pixel_to_char_size (ew, ew->core.width, ew->core.height,
485 &char_width, &char_height);
486 char_to_pixel_size (ew, char_width, char_height,
487 &rounded_width, &rounded_height);
488 get_default_char_pixel_size (ew, &cw, &ch);
489
490 base_width = (wmshell->core.width - ew->core.width
491 + (rounded_width - (char_width * cw)));
492 base_height = (wmshell->core.height - ew->core.height
493 + (rounded_height - (char_height * ch)));
494
495 /* This is kind of sleazy, but I can't see how else to tell it to
496 make it mark the WM_SIZE_HINTS size as user specified.
497 */
498 /* ((WMShellWidget) wmshell)->wm.size_hints.flags |= USSize;*/
499
500 XtVaSetValues (wmshell,
501 XtNbaseWidth, (XtArgVal) base_width,
502 XtNbaseHeight, (XtArgVal) base_height,
503 XtNwidthInc, (XtArgVal) cw,
504 XtNheightInc, (XtArgVal) ch,
505 XtNminWidth, (XtArgVal) (base_width + min_cols * cw),
506 XtNminHeight, (XtArgVal) (base_height + min_rows * ch),
507 NULL);
508 }
509
510 #if 0
511
512 static void
513 create_frame_gcs (ew)
514 EmacsFrame ew;
515 {
516 struct frame *s = ew->emacs_frame.frame;
517
518 s->output_data.x->normal_gc
519 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
520 (unsigned long)0, (XGCValues *)0);
521 s->output_data.x->reverse_gc
522 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
523 (unsigned long)0, (XGCValues *)0);
524 s->output_data.x->cursor_gc
525 = XCreateGC (XtDisplay (ew), RootWindowOfScreen (XtScreen (ew)),
526 (unsigned long)0, (XGCValues *)0);
527 s->output_data.x->black_relief.gc = 0;
528 s->output_data.x->white_relief.gc = 0;
529 }
530
531 #endif /* 0 */
532
533 static char setup_frame_cursor_bits[] =
534 {
535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
539 };
540
541 static void
542 setup_frame_gcs (EmacsFrame ew)
543 {
544 XGCValues gc_values;
545 struct frame* s = ew->emacs_frame.frame;
546 Pixmap blank_stipple, blank_tile;
547 unsigned long valuemask = (GCForeground | GCBackground | GCGraphicsExposures
548 | GCStipple | GCTile);
549 Lisp_Object font;
550
551 XSETFONT (font, ew->emacs_frame.font);
552 font = Ffont_xlfd_name (font, Qnil);
553 if (STRINGP (font))
554 {
555 XFontStruct *xfont = XLoadQueryFont (FRAME_X_DISPLAY_INFO (s)->display,
556 SSDATA (font));
557 if (xfont)
558 {
559 gc_values.font = xfont->fid;
560 valuemask |= GCFont;
561 }
562 }
563
564 /* We have to initialize all of our GCs to have a stipple/tile, otherwise
565 XGetGCValues returns uninitialized data when we query the stipple
566 (instead of None or something sensible) and it makes things hard.
567
568 This should be fixed for real by not querying the GCs but instead having
569 some GC-based cache instead of the current face-based cache which doesn't
570 effectively cache all of the GC settings we need to use.
571 */
572
573 blank_stipple
574 = XCreateBitmapFromData (XtDisplay (ew),
575 RootWindowOfScreen (XtScreen (ew)),
576 setup_frame_cursor_bits, 2, 2);
577
578 /* use fg = 0, bg = 1 below, but it's irrelevant since this pixmap should
579 never actually get used as a background tile!
580 */
581 blank_tile
582 = XCreatePixmapFromBitmapData (XtDisplay(ew),
583 RootWindowOfScreen (XtScreen (ew)),
584 setup_frame_cursor_bits, 2, 2,
585 (unsigned long)0, (unsigned long)1,
586 ew->core.depth);
587
588 /* Normal video */
589 gc_values.foreground = ew->emacs_frame.foreground_pixel;
590 gc_values.background = ew->core.background_pixel;
591 gc_values.graphics_exposures = False;
592 gc_values.stipple = blank_stipple;
593 gc_values.tile = blank_tile;
594 XChangeGC (XtDisplay (ew), s->output_data.x->normal_gc,
595 valuemask, &gc_values);
596
597 /* Reverse video style. */
598 gc_values.foreground = ew->core.background_pixel;
599 gc_values.background = ew->emacs_frame.foreground_pixel;
600 gc_values.graphics_exposures = False;
601 gc_values.stipple = blank_stipple;
602 gc_values.tile = blank_tile;
603 XChangeGC (XtDisplay (ew), s->output_data.x->reverse_gc,
604 valuemask, &gc_values);
605
606 /* Cursor has to have an empty stipple. */
607 gc_values.foreground = ew->core.background_pixel;
608 gc_values.background = ew->emacs_frame.cursor_color;
609 gc_values.graphics_exposures = False;
610 gc_values.tile = blank_tile;
611 gc_values.stipple
612 = XCreateBitmapFromData (XtDisplay (ew),
613 RootWindowOfScreen (XtScreen (ew)),
614 setup_frame_cursor_bits, 16, 16);
615 XChangeGC (XtDisplay (ew), s->output_data.x->cursor_gc,
616 valuemask, &gc_values);
617 }
618
619 static void
620 update_various_frame_slots (EmacsFrame ew)
621 {
622 struct frame *f = ew->emacs_frame.frame;
623 struct x_output *x = f->output_data.x;
624 FRAME_PIXEL_HEIGHT (f) = ew->core.height + x->menubar_height;
625 FRAME_PIXEL_WIDTH (f) = ew->core.width;
626 f->internal_border_width = ew->emacs_frame.internal_border_width;
627
628 }
629
630 static void
631 update_from_various_frame_slots (EmacsFrame ew)
632 {
633 struct frame *f = ew->emacs_frame.frame;
634 struct x_output *x = f->output_data.x;
635 ew->core.height = FRAME_PIXEL_HEIGHT (f) - x->menubar_height;
636 ew->core.width = FRAME_PIXEL_WIDTH (f);
637 ew->core.background_pixel = FRAME_BACKGROUND_PIXEL (f);
638 ew->emacs_frame.internal_border_width = f->internal_border_width;
639 ew->emacs_frame.font = x->font;
640 ew->emacs_frame.foreground_pixel = FRAME_FOREGROUND_PIXEL (f);
641 ew->emacs_frame.cursor_color = x->cursor_pixel;
642 ew->core.border_pixel = x->border_pixel;
643 }
644
645 static void
646 EmacsFrameInitialize (Widget request, Widget new, ArgList dum1, Cardinal *dum2)
647 {
648 EmacsFrame ew = (EmacsFrame)new;
649
650 if (!ew->emacs_frame.frame)
651 {
652 fprintf (stderr,
653 "can't create an emacs frame widget without a frame\n");
654 exit (1);
655 }
656
657 update_from_various_frame_slots (ew);
658 set_frame_size (ew);
659 }
660
661
662 static void
663 EmacsFrameRealize (Widget widget, XtValueMask *mask, XSetWindowAttributes *attrs)
664 {
665 EmacsFrame ew = (EmacsFrame)widget;
666
667 /* This used to contain SubstructureRedirectMask, but this turns out
668 to be a problem with XIM on Solaris, and events from that mask
669 don't seem to be used. Let's check that. */
670 attrs->event_mask = (STANDARD_EVENT_SET
671 | PropertyChangeMask
672 | SubstructureNotifyMask);
673 *mask |= CWEventMask;
674 XtCreateWindow (widget, InputOutput, (Visual *)CopyFromParent, *mask,
675 attrs);
676 update_wm_hints (ew);
677 }
678
679 extern void free_frame_faces (struct frame *);
680
681 static void
682 EmacsFrameDestroy (Widget widget)
683 {
684 EmacsFrame ew = (EmacsFrame) widget;
685 struct frame* s = ew->emacs_frame.frame;
686
687 if (! s) abort ();
688 if (! s->output_data.x) abort ();
689
690 BLOCK_INPUT;
691 x_free_gcs (s);
692 if (s->output_data.x->white_relief.gc)
693 XFreeGC (XtDisplay (widget), s->output_data.x->white_relief.gc);
694 if (s->output_data.x->black_relief.gc)
695 XFreeGC (XtDisplay (widget), s->output_data.x->black_relief.gc);
696 UNBLOCK_INPUT;
697 }
698
699 static void
700 EmacsFrameResize (Widget widget)
701 {
702 EmacsFrame ew = (EmacsFrame)widget;
703 struct frame *f = ew->emacs_frame.frame;
704 int columns;
705 int rows;
706
707 pixel_to_char_size (ew, ew->core.width, ew->core.height, &columns, &rows);
708 change_frame_size (f, rows, columns, 0, 1, 0);
709 update_wm_hints (ew);
710 update_various_frame_slots (ew);
711
712 cancel_mouse_face (f);
713 }
714
715 static Boolean
716 EmacsFrameSetValues (Widget cur_widget, Widget req_widget, Widget new_widget, ArgList dum1, Cardinal *dum2)
717 {
718 EmacsFrame cur = (EmacsFrame)cur_widget;
719 EmacsFrame new = (EmacsFrame)new_widget;
720
721 Boolean needs_a_refresh = False;
722 Boolean has_to_recompute_size;
723 Boolean has_to_recompute_gcs;
724 Boolean has_to_update_hints;
725
726 int char_width, char_height;
727 Dimension pixel_width;
728 Dimension pixel_height;
729
730 /* AFAIK, this function is never called. -- Jan D, Oct 2009. */
731 has_to_recompute_gcs = (cur->emacs_frame.font != new->emacs_frame.font
732 || (cur->emacs_frame.foreground_pixel
733 != new->emacs_frame.foreground_pixel)
734 || (cur->core.background_pixel
735 != new->core.background_pixel)
736 );
737
738 has_to_recompute_size = (cur->emacs_frame.font != new->emacs_frame.font
739 && cur->core.width == new->core.width
740 && cur->core.height == new->core.height);
741
742 has_to_update_hints = (cur->emacs_frame.font != new->emacs_frame.font);
743
744 if (has_to_recompute_gcs)
745 {
746 setup_frame_gcs (new);
747 needs_a_refresh = True;
748 }
749
750 if (has_to_recompute_size)
751 {
752 pixel_width = new->core.width;
753 pixel_height = new->core.height;
754 pixel_to_char_size (new, pixel_width, pixel_height, &char_width,
755 &char_height);
756 char_to_pixel_size (new, char_width, char_height, &pixel_width,
757 &pixel_height);
758 new->core.width = pixel_width;
759 new->core.height = pixel_height;
760
761 change_frame_size (new->emacs_frame.frame, char_height, char_width,
762 1, 0, 0);
763 needs_a_refresh = True;
764 }
765
766 if (has_to_update_hints)
767 update_wm_hints (new);
768
769 update_various_frame_slots (new);
770
771 /* #### This doesn't work, I haven't been able to find ANY kludge that
772 will let (x-create-frame '((iconic . t))) work. It seems that changes
773 to wm_shell's iconic slot have no effect after it has been realized,
774 and calling XIconifyWindow doesn't work either (even though the window
775 has been created.) Perhaps there is some property we could smash
776 directly, but I'm sick of this for now.
777 */
778 if (cur->emacs_frame.iconic != new->emacs_frame.iconic)
779 {
780 Widget wmshell = get_wm_shell ((Widget) cur);
781 XtVaSetValues (wmshell, XtNiconic,
782 (XtArgVal) new->emacs_frame.iconic, NULL);
783 }
784
785 return needs_a_refresh;
786 }
787
788 static XtGeometryResult
789 EmacsFrameQueryGeometry (Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *result)
790 {
791 EmacsFrame ew = (EmacsFrame)widget;
792
793 int mask = request->request_mode;
794 Dimension ok_width, ok_height;
795
796 if (mask & (CWWidth | CWHeight))
797 {
798 round_size_to_char (ew,
799 (mask & CWWidth) ? request->width : ew->core.width,
800 ((mask & CWHeight) ? request->height
801 : ew->core.height),
802 &ok_width, &ok_height);
803 if ((mask & CWWidth) && (ok_width != request->width))
804 {
805 result->request_mode |= CWWidth;
806 result->width = ok_width;
807 }
808 if ((mask & CWHeight) && (ok_height != request->height))
809 {
810 result->request_mode |= CWHeight;
811 result->height = ok_height;
812 }
813 }
814 return result->request_mode ? XtGeometryAlmost : XtGeometryYes;
815 }
816
817 /* Special entrypoints */
818 void
819 EmacsFrameSetCharSize (Widget widget, int columns, int rows)
820 {
821 EmacsFrame ew = (EmacsFrame) widget;
822 struct frame *f = ew->emacs_frame.frame;
823
824 x_set_window_size (f, 0, columns, rows);
825 }
826
827 \f
828 void
829 widget_store_internal_border (Widget widget)
830 {
831 EmacsFrame ew = (EmacsFrame) widget;
832 FRAME_PTR f = ew->emacs_frame.frame;
833
834 ew->emacs_frame.internal_border_width = f->internal_border_width;
835 }