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