comparison src/frame-x.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Functions for the X window system.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995, 1996 Ben Wing.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: Not synched with FSF. */
23
24 /* Substantially rewritten for XEmacs. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-x.h"
30 #include "xintrinsicp.h" /* CoreP.h needs this */
31 #include <X11/CoreP.h> /* Numerous places access the fields of
32 a core widget directly. We could
33 use XtVaGetValues(), but ... */
34 #include <X11/Shell.h>
35 #include <X11/ShellP.h>
36 #include "xmu.h"
37 #include "EmacsManager.h"
38 #include "EmacsFrameP.h"
39 #include "EmacsShell.h"
40 #ifdef EXTERNAL_WIDGET
41 #include "ExternalShell.h"
42 #endif
43 #include "glyphs-x.h"
44 #include "objects-x.h"
45 #include "scrollbar-x.h"
46
47 #include "buffer.h"
48 #include "events.h"
49 #include "extents.h"
50 #include "faces.h"
51 #include "frame.h"
52 #include "window.h"
53
54 /* Default properties to use when creating frames. */
55 Lisp_Object Vdefault_x_frame_plist;
56
57 Lisp_Object Qwindow_id;
58 Lisp_Object Qpopup;
59 Lisp_Object Qx_resource_name;
60
61
62 /************************************************************************/
63 /* helper functions */
64 /************************************************************************/
65
66 /* Return the Emacs frame-object corresponding to an X window */
67 struct frame *
68 x_window_to_frame (struct device *d, Window wdesc)
69 {
70 Lisp_Object tail, frame;
71 struct frame *f;
72
73 /* This function was previously written to accept only a window argument
74 (and to loop over all devices looking for a matching window), but
75 that is incorrect because window ID's are not unique across displays. */
76
77 for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
78 {
79 frame = XCAR (tail);
80 if (!FRAMEP (frame))
81 continue;
82 f = XFRAME (frame);
83 if (FRAME_X_P (f) && XtWindow (FRAME_X_TEXT_WIDGET (f)) == wdesc)
84 return f;
85 }
86 return 0;
87 }
88
89 /* Like x_window_to_frame but also compares the window with the widget's
90 windows */
91 struct frame *
92 x_any_window_to_frame (struct device *d, Window wdesc)
93 {
94 Lisp_Object tail, frame;
95 struct frame *f;
96
97 assert (DEVICE_X_P (d));
98
99 /* This function was previously written to accept only a window argument
100 (and to loop over all devices looking for a matching window), but
101 that is incorrect because window ID's are not unique across displays. */
102
103 for (tail = DEVICE_FRAME_LIST (d); CONSP (tail); tail = XCDR (tail))
104 {
105 int i;
106
107 frame = XCAR (tail);
108 f = XFRAME (frame);
109 /* This frame matches if the window is any of its widgets. */
110 if (wdesc == XtWindow (FRAME_X_SHELL_WIDGET (f)) ||
111 wdesc == XtWindow (FRAME_X_CONTAINER_WIDGET (f)) ||
112 wdesc == XtWindow (FRAME_X_TEXT_WIDGET (f)))
113 return f;
114
115 /* Match if the window is one of the widgets at the top of the frame
116 (menubar, Energize psheets). */
117
118 /* Note: Jamie once said
119
120 "Do *not* match if the window is this frame's psheet."
121
122 But this is wrong and will screw up some functions that expect
123 x_any_window_to_frame() to work as advertised. I think the reason
124 for this statement is that, in the old (broken) event loop, where
125 not all events went through XtDispatchEvent(), psheet events
126 would incorrectly get sucked away by Emacs if this function matched
127 on psheet widgets. */
128
129 for (i = 0; i < FRAME_X_NUM_TOP_WIDGETS (f); i++)
130 {
131 Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
132 if (wid && XtIsManaged (wid) && wdesc == XtWindow (wid))
133 return f;
134 }
135
136 #ifdef HAVE_SCROLLBARS
137 /* Match if the window is one of this frame's scrollbars. */
138 if (x_window_is_scrollbar (f, wdesc))
139 return f;
140 #endif
141 }
142
143 return 0;
144 }
145
146 struct frame *
147 x_any_widget_or_parent_to_frame (struct device *d, Widget widget)
148 {
149 while (widget)
150 {
151 struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
152 if (f)
153 return f;
154 widget = XtParent (widget);
155 }
156
157 return 0;
158 }
159
160 struct frame *
161 decode_x_frame (Lisp_Object frame)
162 {
163 if (NILP (frame))
164 XSETFRAME (frame, selected_frame ());
165 CHECK_LIVE_FRAME (frame);
166 /* this will also catch dead frames, but putting in the above check
167 results in a more useful error */
168 CHECK_X_FRAME (frame);
169 return XFRAME (frame);
170 }
171
172
173 /************************************************************************/
174 /* window-manager interactions */
175 /************************************************************************/
176
177 #if 0
178 /* Not currently used. */
179
180 void
181 x_wm_mark_shell_size_user_specified (Widget wmshell)
182 {
183 if (! XtIsWMShell (wmshell)) abort ();
184 EmacsShellSetSizeUserSpecified (wmshell);
185 }
186
187 void
188 x_wm_mark_shell_position_user_specified (Widget wmshell)
189 {
190 if (! XtIsWMShell (wmshell)) abort ();
191 EmacsShellSetPositionUserSpecified (wmshell);
192 }
193
194 #endif
195
196 void
197 x_wm_set_shell_iconic_p (Widget shell, int iconic_p)
198 {
199 if (! XtIsWMShell (shell)) abort ();
200
201 /* Because of questionable logic in Shell.c, this sequence can't work:
202
203 w = XtCreatePopupShell (...);
204 XtVaSetValues (w, XtNiconic, True, 0);
205 XtRealizeWidget (w);
206
207 The iconic resource is only consulted at initialization time (when
208 XtCreatePopupShell is called) instead of at realization time (just
209 before the window gets created, which would be more sensible) or
210 at management-time (just before the window gets mapped, which would
211 be most sensible of all).
212
213 The bug is that Shell's SetValues method doesn't do anything to
214 w->wm.wm_hints.initial_state until after the widget has been realized.
215 Calls to XtSetValues are ignored in the window between creation and
216 realization. This is true of MIT X11R5 patch level 25, at least.
217 (Apparently some other versions of Xt don't have this bug?)
218 */
219 XtVaSetValues (shell, XtNiconic, iconic_p, 0);
220 EmacsShellSmashIconicHint (shell, iconic_p);
221 }
222
223 void
224 x_wm_set_cell_size (Widget wmshell, int cw, int ch)
225 {
226 if (!XtIsWMShell (wmshell))
227 abort ();
228 if (cw <= 0 || ch <= 0)
229 abort ();
230
231 XtVaSetValues (wmshell,
232 XtNwidthInc, cw,
233 XtNheightInc, ch,
234 0);
235 }
236
237 void
238 x_wm_set_variable_size (Widget wmshell, int width, int height)
239 {
240 if (!XtIsWMShell (wmshell))
241 abort ();
242 #ifdef DEBUG_GEOMETRY_MANAGEMENT
243 /* See comment in EmacsShell.c */
244 printf ("x_wm_set_variable_size: %d %d\n", width, height);
245 fflush (stdout);
246 #endif
247 XtVaSetValues (wmshell,
248 XtNwidthCells, width,
249 XtNheightCells, height,
250 0);
251 }
252
253 /* If the WM_PROTOCOLS property does not already contain WM_TAKE_FOCUS
254 and WM_DELETE_WINDOW, then add them. (They may already be present
255 because of the toolkit (Motif adds them, for example, but Xt doesn't).
256 */
257 static void
258 x_wm_hack_wm_protocols (Widget widget)
259 {
260 Display *dpy = XtDisplay (widget);
261 struct device *d = get_device_from_display (dpy);
262 Window w = XtWindow (widget);
263 int need_delete = 1;
264 int need_focus = 1;
265
266 if (!XtIsWMShell (widget))
267 abort ();
268
269 {
270 Atom type, *atoms = 0;
271 int format = 0;
272 unsigned long nitems = 0;
273 unsigned long bytes_after;
274
275 if (Success == XGetWindowProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d),
276 0, 100, False, XA_ATOM,
277 &type, &format, &nitems, &bytes_after,
278 (unsigned char **) &atoms)
279 && format == 32 && type == XA_ATOM)
280 while (nitems > 0)
281 {
282 nitems--;
283 if (atoms [nitems] == DEVICE_XATOM_WM_DELETE_WINDOW (d))
284 need_delete = 0;
285 else if (atoms [nitems] == DEVICE_XATOM_WM_TAKE_FOCUS (d))
286 need_focus = 0;
287 }
288 if (atoms) XFree ((char *) atoms);
289 }
290 {
291 Atom props [10];
292 int count = 0;
293 if (need_delete) props[count++] = DEVICE_XATOM_WM_DELETE_WINDOW (d);
294 if (need_focus) props[count++] = DEVICE_XATOM_WM_TAKE_FOCUS (d);
295 if (count)
296 XChangeProperty (dpy, w, DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32,
297 PropModeAppend, (unsigned char *) props, count);
298 }
299 }
300
301 static void
302 x_wm_store_class_hints (Widget shell, char *frame_name)
303 {
304 Display *dpy = XtDisplay (shell);
305 char *app_name, *app_class;
306 XClassHint classhint;
307
308 if (!XtIsWMShell (shell))
309 abort ();
310
311 XtGetApplicationNameAndClass (dpy, &app_name, &app_class);
312 classhint.res_name = frame_name;
313 classhint.res_class = app_class;
314 XSetClassHint (dpy, XtWindow (shell), &classhint);
315 }
316
317 static void
318 x_wm_maybe_store_wm_command (struct frame *f)
319 {
320 Widget w = FRAME_X_SHELL_WIDGET (f);
321 struct device *d = XDEVICE (FRAME_DEVICE (f));
322
323 if (!XtIsWMShell (w))
324 abort ();
325
326 if (NILP (DEVICE_X_WM_COMMAND_FRAME (d)))
327 {
328 int argc;
329 char **argv;
330 make_argc_argv (Vcommand_line_args, &argc, &argv);
331 XSetCommand (XtDisplay (w), XtWindow (w), argv, argc);
332 free_argc_argv (argv);
333 XSETFRAME (DEVICE_X_WM_COMMAND_FRAME (d), f);
334 }
335 }
336
337 /* If we're deleting the frame on which the WM_COMMAND property has been
338 set, then move that property to another frame so that there is exactly
339 one frame that has that property set.
340 */
341 static void
342 x_wm_maybe_move_wm_command (struct frame *f)
343 {
344 struct device *d = XDEVICE (FRAME_DEVICE (f));
345
346 /* There may not be a frame in DEVICE_X_WM_COMMAND_FRAME()
347 if we C-c'ed at startup at the right time. */
348 if (FRAMEP (DEVICE_X_WM_COMMAND_FRAME (d))
349 && f == XFRAME (DEVICE_X_WM_COMMAND_FRAME (d)))
350 {
351 Lisp_Object rest = DEVICE_FRAME_LIST (d);
352 DEVICE_X_WM_COMMAND_FRAME (d) = Qnil;
353 /* find some random other X frame that is not this one, or give up */
354 /* skip non-top-level (ExternalClient) frames */
355 while (!NILP (rest) &&
356 (f == XFRAME (XCAR (rest)) ||
357 !FRAME_X_TOP_LEVEL_FRAME_P (XFRAME (XCAR (rest)))))
358 rest = XCDR (rest);
359 if (NILP (rest))
360 return;
361 f = XFRAME (XCAR (rest));
362 x_wm_maybe_store_wm_command (f);
363 }
364 }
365
366 static int
367 x_frame_iconified_p (struct frame *f)
368 {
369 Atom actual_type;
370 int actual_format;
371 unsigned long nitems, bytesafter;
372 unsigned long *datap = 0;
373 Widget widget;
374 int result = 0;
375 struct device *d = XDEVICE (FRAME_DEVICE (f));
376
377 widget = FRAME_X_SHELL_WIDGET (f);
378 if (Success == XGetWindowProperty (XtDisplay (widget), XtWindow (widget),
379 DEVICE_XATOM_WM_STATE (d), 0, 2, False,
380 DEVICE_XATOM_WM_STATE (d), &actual_type,
381 &actual_format, &nitems, &bytesafter,
382 (unsigned char **) &datap)
383 && datap)
384 {
385 if (nitems <= 2 /* "suggested" by ICCCM version 1 */
386 && datap[0] == IconicState)
387 result = 1;
388 XFree ((char *) datap);
389 }
390 return result;
391 }
392
393
394 /************************************************************************/
395 /* frame properties */
396 /************************************************************************/
397
398 /* Connect the frame-property names (symbols) to the corresponding
399 X Resource Manager names. The name of a property, as a Lisp symbol,
400 has an `x-resource-name' property which is a Lisp_String. */
401
402 static void
403 init_x_prop_symbols (void)
404 {
405 #define def(sym, rsrc) \
406 pure_put (sym, Qx_resource_name, build_string (rsrc))
407 #define defi(sym,rsrc) \
408 def (sym, rsrc); pure_put (sym, Qintegerp, Qt)
409
410 #if 0 /* this interferes with things. #### fix this right */
411 def (Qminibuffer, XtNminibuffer);
412 def (Qunsplittable, XtNunsplittable);
413 #endif
414 defi(Qinternal_border_width, XtNinternalBorderWidth);
415 #ifdef HAVE_TOOLBARS
416 def (Qtop_toolbar_shadow_color, XtNtopToolBarShadowColor);
417 def (Qbottom_toolbar_shadow_color, XtNbottomToolBarShadowColor);
418 def (Qbackground_toolbar_color, XtNbackgroundToolBarColor);
419 def (Qtop_toolbar_shadow_pixmap, XtNtopToolBarShadowPixmap);
420 def (Qbottom_toolbar_shadow_pixmap, XtNbottomToolBarShadowPixmap);
421 defi(Qtoolbar_shadow_thickness, XtNtoolBarShadowThickness);
422 #endif
423 def (Qscrollbar_placement, XtNscrollBarPlacement);
424 defi(Qinter_line_space, XtNinterline);
425 /* font, foreground */
426 def (Qiconic, XtNiconic);
427 def (Qbar_cursor, XtNbarCursor);
428 def (Qvisual_bell, XtNvisualBell);
429 defi(Qbell_volume, XtNbellVolume);
430 def (Qpointer_background, XtNpointerBackground);
431 def (Qpointer_color, XtNpointerColor);
432 def (Qtext_pointer, XtNtextPointer);
433 def (Qspace_pointer, XtNspacePointer);
434 def (Qmodeline_pointer, XtNmodeLinePointer);
435 def (Qgc_pointer, XtNgcPointer);
436 /* geometry, initial_geometry */
437 def (Qinitially_unmapped, XtNinitiallyUnmapped);
438 /* preferred_width, preferred_height */
439 def (Quse_backing_store, XtNuseBackingStore);
440
441 /* inherited: */
442
443 def (Qborder_color, XtNborderColor);
444 defi(Qborder_width, XtNborderWidth);
445 defi(Qwidth, XtNwidth);
446 defi(Qheight, XtNheight);
447 defi(Qleft, XtNx);
448 defi(Qtop, XtNy);
449
450 #undef def
451 }
452
453 static Lisp_Object
454 color_to_string (Widget w, unsigned long pixel)
455 {
456 char buf[255];
457
458 XColor color;
459 color.pixel = pixel;
460 XQueryColor (XtDisplay (w), w->core.colormap, &color);
461 sprintf (buf, "#%04x%04x%04x", color.red, color.green, color.blue);
462 return build_string (buf);
463 }
464
465 static void
466 x_get_top_level_position (Display *d, Window w, Position *x, Position *y)
467 {
468 Window root, parent = w, *children;
469 unsigned int nchildren;
470 XWindowAttributes xwa;
471
472 do
473 {
474 w = parent;
475 if (!XQueryTree (d, w, &root, &parent, &children, &nchildren))
476 {
477 *x = 0;
478 *y = 0;
479 return;
480 }
481 XFree (children);
482 }
483 while (root != parent);
484 XGetWindowAttributes (d, w, &xwa);
485 *x = xwa.x;
486 *y = xwa.y;
487 }
488
489 static void
490 x_smash_bastardly_shell_position (Widget shell)
491 {
492 /* Naturally those bastards who wrote Xt couldn't be bothered
493 to learn about race conditions and such. We can't trust
494 the X and Y values to have any resemblance of correctness,
495 so we smash the right values in place. */
496
497 /* We might be called before we've actually realized the window (if
498 we're checking for the minibuffer resource). This will bomb in
499 that case so we don't bother calling it. */
500 if (XtWindow (shell))
501 x_get_top_level_position (XtDisplay (shell), XtWindow (shell),
502 &shell->core.x, &shell->core.y);
503 }
504
505 static Lisp_Object
506 x_frame_property (struct frame *f, Lisp_Object property)
507 {
508 Widget shell = FRAME_X_SHELL_WIDGET (f);
509 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
510 Widget gw = (Widget) w;
511
512 #define FROB(propprop, value) \
513 do { \
514 if (EQ (property, propprop)) \
515 { \
516 return (value); \
517 } \
518 } while (0)
519
520 if (EQ (property, Qleft) || EQ (property, Qtop))
521 x_smash_bastardly_shell_position (shell);
522 FROB (Qleft, make_int (shell->core.x));
523 FROB (Qtop, make_int (shell->core.y));
524 FROB (Qborder_width, make_int (w->core.border_width));
525 FROB (Qinternal_border_width,
526 make_int (w->emacs_frame.internal_border_width));
527 FROB (Qborder_color, color_to_string (gw, w->core.border_pixel));
528 #ifdef HAVE_TOOLBARS
529 FROB (Qtop_toolbar_shadow_color,
530 color_to_string (gw, w->emacs_frame.top_toolbar_shadow_pixel));
531 FROB (Qbottom_toolbar_shadow_color,
532 color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel));
533 FROB (Qbackground_toolbar_color,
534 color_to_string (gw, w->emacs_frame.background_toolbar_pixel));
535 FROB (Qtoolbar_shadow_thickness,
536 make_int (w->emacs_frame.toolbar_shadow_thickness));
537 #endif
538 FROB (Qinter_line_space, make_int (w->emacs_frame.interline));
539 FROB (Qwindow_id, Fx_window_id (make_frame (f)));
540
541 #undef FROB
542
543 return Qunbound;
544 }
545
546 static int
547 x_internal_frame_property_p (struct frame *f, Lisp_Object property)
548 {
549 if (EQ (property, Qleft)
550 || EQ (property, Qtop)
551 || EQ (property, Qborder_width)
552 || EQ (property, Qinternal_border_width)
553 || EQ (property, Qborder_color)
554 #ifdef HAVE_TOOLBARS
555 || EQ (property, Qtop_toolbar_shadow_color)
556 || EQ (property, Qbottom_toolbar_shadow_color)
557 || EQ (property, Qbackground_toolbar_color)
558 || EQ (property, Qtoolbar_shadow_thickness)
559 #endif
560 || EQ (property, Qinter_line_space)
561 || EQ (property, Qwindow_id)
562 || STRINGP (property))
563 return 1;
564
565 return 0;
566 }
567
568 static Lisp_Object
569 x_frame_properties (struct frame *f)
570 {
571 Lisp_Object result = Qnil;
572 Widget shell = FRAME_X_SHELL_WIDGET (f);
573 EmacsFrame w = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
574 Widget gw = (Widget) w;
575
576 #define FROB(propprop, value) \
577 do { \
578 Lisp_Object temtem = (value); \
579 if (!NILP (temtem)) \
580 /* backwards order; we reverse it below */ \
581 result = Fcons (temtem, Fcons (propprop, result)); \
582 } while (0)
583
584 x_smash_bastardly_shell_position (shell);
585 FROB (Qleft, make_int (shell->core.x));
586 FROB (Qtop, make_int (shell->core.y));
587 FROB (Qborder_width, make_int (w->core.border_width));
588 FROB (Qinternal_border_width,
589 make_int (w->emacs_frame.internal_border_width));
590 FROB (Qborder_color, color_to_string (gw, w->core.border_pixel));
591 #ifdef HAVE_TOOLBARS
592 FROB (Qtop_toolbar_shadow_color,
593 color_to_string (gw, w->emacs_frame.top_toolbar_shadow_pixel));
594 FROB (Qbottom_toolbar_shadow_color,
595 color_to_string (gw, w->emacs_frame.bottom_toolbar_shadow_pixel));
596 FROB (Qbackground_toolbar_color,
597 color_to_string (gw, w->emacs_frame.background_toolbar_pixel));
598 FROB (Qtoolbar_shadow_thickness,
599 make_int (w->emacs_frame.toolbar_shadow_thickness));
600 #endif
601 FROB (Qinter_line_space, make_int (w->emacs_frame.interline));
602 FROB (Qwindow_id, Fx_window_id (make_frame (f)));
603
604 #undef FROB
605
606 return result;
607 }
608
609
610 /* Functions called only from `x_set_frame_properties' to set
611 ** individual properties. */
612
613 static void
614 x_set_title_from_char (struct frame *f, char *name)
615 {
616 CONST char *old_name = 0;
617 CONST char *new_name;
618 Arg av[1];
619
620 GET_C_CHARPTR_EXT_CTEXT_DATA_ALLOCA (name, new_name);
621 XtSetArg (av[0], XtNtitle, &old_name);
622 XtGetValues (FRAME_X_SHELL_WIDGET (f), av, 1);
623 if (!old_name || strcmp (new_name, old_name))
624 {
625 XtSetArg (av[0], XtNtitle, new_name);
626 XtSetValues (FRAME_X_SHELL_WIDGET (f), av, 1);
627 }
628 }
629
630 static void
631 x_set_icon_name_from_char (struct frame *f, char *name)
632 {
633 CONST char *old_name = 0;
634 CONST char *new_name;
635 Arg av[1];
636
637 GET_C_CHARPTR_EXT_CTEXT_DATA_ALLOCA (name, new_name);
638 XtSetArg (av[0], XtNiconName, &old_name);
639 XtGetValues (FRAME_X_SHELL_WIDGET (f), av, 1);
640 if (!old_name || strcmp (new_name, old_name))
641 {
642 XtSetArg (av[0], XtNiconName, new_name);
643 XtSetValues (FRAME_X_SHELL_WIDGET (f), av, 1);
644 }
645 }
646
647 /* Set the initial frame size as specified. This function is used
648 when the frame's widgets have not yet been realized. In this
649 case, it is not sufficient just to set the width and height of
650 the EmacsFrame widget, because they will be ignored when the
651 widget is realized (instead, the shell's geometry resource is
652 used). */
653
654 static void
655 x_set_initial_frame_size (struct frame *f, int flags, int x, int y,
656 unsigned int w, unsigned int h)
657 {
658 char shell_geom [255];
659 int xval, yval;
660 char xsign, ysign;
661 char uspos = !!(flags & (XValue | YValue));
662 char ussize = !!(flags & (WidthValue | HeightValue));
663 char *temp;
664
665 /* assign the correct size to the EmacsFrame widget ... */
666 EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), w, h);
667
668 /* and also set the WMShell's geometry */
669 (flags & XNegative) ? (xval = -x, xsign = '-') : (xval = x, xsign = '+');
670 (flags & YNegative) ? (yval = -y, ysign = '-') : (yval = y, ysign = '+');
671
672 if (uspos && ussize)
673 sprintf (shell_geom, "=%dx%d%c%d%c%d", w, h, xsign, xval, ysign, yval);
674 else if (uspos)
675 sprintf (shell_geom, "=%c%d%c%d", xsign, xval, ysign, yval);
676 else if (ussize)
677 sprintf (shell_geom, "=%dx%d", w, h);
678
679 if (uspos || ussize)
680 {
681 temp = xmalloc (1 + strlen (shell_geom));
682 strcpy (temp, shell_geom);
683 FRAME_X_GEOM_FREE_ME_PLEASE (f) = temp;
684 }
685 else
686 temp = NULL;
687 XtVaSetValues (FRAME_X_SHELL_WIDGET (f), XtNgeometry, temp, 0);
688 }
689
690 /* Report to X that a frame property of frame S is being set or changed.
691 If the property is not specially recognized, do nothing.
692 */
693
694 static void
695 x_set_frame_properties (struct frame *f, Lisp_Object plist)
696 {
697 int x = 0, y = 0;
698 Dimension width = 0, height = 0;
699 Bool width_specified_p = False;
700 Bool height_specified_p = False;
701 Bool x_position_specified_p = False;
702 Bool y_position_specified_p = False;
703 Bool internal_border_width_specified = False;
704 Lisp_Object tail;
705 Widget w = FRAME_X_TEXT_WIDGET (f);
706
707 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
708 {
709 Lisp_Object prop = Fcar (tail);
710 Lisp_Object val = Fcar (Fcdr (tail));
711
712 if (STRINGP (prop))
713 {
714 CONST char *extprop;
715
716 if (string_length (XSTRING (prop)) == 0)
717 continue;
718
719 GET_C_STRING_CTEXT_DATA_ALLOCA (prop, extprop);
720 if (STRINGP (val))
721 {
722 Extbyte *extval;
723 Extcount extvallen;
724
725 GET_STRING_CTEXT_DATA_ALLOCA (val, extval, extvallen);
726 XtVaSetValues (w, XtVaTypedArg, extprop,
727 XtRString, extval, extvallen + 1, 0);
728 }
729 else
730 XtVaSetValues (w, XtVaTypedArg,
731 extprop, XtRInt, XINT (val),
732 sizeof (int),
733 0);
734 }
735 else if (SYMBOLP (prop))
736 {
737 Lisp_Object str = Fget (prop, Qx_resource_name, Qnil);
738 int int_p = !NILP (Fget (prop, Qintegerp, Qnil));
739
740 if (NILP (prop) || NILP (str))
741 {
742 /* Kludge to handle the font property. */
743 if (EQ (prop, Qfont))
744 {
745 /* If the value is not a string we silently ignore it. */
746 if (STRINGP (val))
747 {
748 Lisp_Object frm, font_spec;
749
750 XSETFRAME (frm, f);
751 font_spec = Fget (Fget_face (Qdefault), Qfont, Qnil);
752
753 Fadd_spec_to_specifier (font_spec, val, frm, Qnil, Qnil);
754 update_frame_face_values (f);
755 }
756
757 continue;
758 }
759 else
760 continue;
761 }
762 CHECK_STRING (str);
763
764 /* Kludge the width/height so that we interpret them in characters
765 instead of pixels. Yuck yuck yuck. */
766 if (!strcmp ((char *) string_data (XSTRING (str)), "width"))
767 {
768 CHECK_INT (val);
769 width = XINT (val);
770 width_specified_p = True;
771 continue;
772 }
773 if (!strcmp ((char *) string_data (XSTRING (str)), "height"))
774 {
775 CHECK_INT (val);
776 height = XINT (val);
777 height_specified_p = True;
778 continue;
779 }
780 /* Further kludge the x/y. */
781 if (!strcmp ((char *) string_data (XSTRING (str)), "x"))
782 {
783 CHECK_INT (val);
784 x = XINT (val);
785 x_position_specified_p = True;
786 continue;
787 }
788 if (!strcmp ((char *) string_data (XSTRING (str)), "y"))
789 {
790 CHECK_INT (val);
791 y = XINT (val);
792 y_position_specified_p = True;
793 continue;
794 }
795 /* Have you figured out by now that this entire function is
796 one gigantic kludge? */
797 if (!strcmp ((char *) string_data (XSTRING (str)),
798 "internalBorderWidth"))
799 {
800 internal_border_width_specified = True;
801 }
802
803 if (int_p)
804 {
805 CHECK_INT (val);
806 XtVaSetValues (w, (char *) string_data (XSTRING (str)),
807 XINT (val), 0);
808 }
809 else if (EQ (val, Qt))
810 XtVaSetValues (w,
811 /* XtN... */
812 (char *) string_data (XSTRING (str)),
813 True,
814 0);
815 else if (EQ (val, Qnil))
816 XtVaSetValues (w,
817 /* XtN... */
818 (char *) string_data (XSTRING (str)),
819 False,
820 0);
821 else
822 {
823 CHECK_STRING (val);
824 XtVaSetValues (w, XtVaTypedArg,
825 /* XtN... */
826 (char *) string_data (XSTRING (str)),
827 XtRString,
828 string_data (XSTRING (val)),
829 string_length (XSTRING (val)) + 1,
830 0);
831 }
832
833 #ifdef HAVE_SCROLLBARS
834 if (!strcmp ((char *) string_data (XSTRING (str)), "scrollBarWidth")
835 || !strcmp ((char *) string_data (XSTRING (str)),
836 "scrollBarHeight"))
837 {
838 x_update_frame_scrollbars (f);
839 }
840 #endif
841 }
842 }
843
844 /* Kludge kludge kludge. We need to deal with the size and position
845 specially. */
846 {
847 int size_specified_p = width_specified_p || height_specified_p;
848 int position_specified_p = x_position_specified_p ||
849 y_position_specified_p;
850
851 if (!width_specified_p)
852 width = FRAME_WIDTH (f);
853 if (!height_specified_p)
854 height = FRAME_HEIGHT (f);
855
856 /* Kludge kludge kludge kludge. */
857 if (!x_position_specified_p)
858 x = (int) (FRAME_X_SHELL_WIDGET (f)->core.x);
859 if (!y_position_specified_p)
860 y = (int) (FRAME_X_SHELL_WIDGET (f)->core.y);
861
862 if (!f->init_finished)
863 {
864 int flags = (size_specified_p ? WidthValue | HeightValue : 0) |
865 (position_specified_p ? XValue | YValue : 0) |
866 (x < 0 ? XNegative : 0) | (y < 0 ? YNegative : 0);
867 if (size_specified_p
868 || position_specified_p
869 || internal_border_width_specified)
870 x_set_initial_frame_size (f, flags, x, y, width, height);
871 }
872 else
873 {
874 if (size_specified_p || internal_border_width_specified)
875 {
876 Lisp_Object frame;
877 XSETFRAME (frame, f);
878 Fset_frame_size (frame, make_int (width),
879 make_int (height), Qnil);
880 }
881 if (position_specified_p)
882 {
883 Lisp_Object frame;
884 XSETFRAME (frame, f);
885 Fset_frame_position (frame, make_int (x), make_int (y));
886 }
887 }
888 }
889 }
890
891 static int frame_title_format_already_set;
892
893 static void
894 maybe_set_frame_title_format (Widget shell)
895 {
896
897 /* Only do this if this is the first X frame we're creating.
898
899 If the *title resource (or -title option) was specified, then
900 set frame-title-format to its value.
901 */
902
903 if (!frame_title_format_already_set)
904 {
905 /* No doubt there's a less stupid way to do this. */
906 char *results [2];
907 XtResource resources [2];
908 results [0] = results [1] = 0;
909 resources [0].resource_name = XtNtitle;
910 resources [0].resource_class = XtCTitle;
911 resources [0].resource_type = XtRString;
912 resources [0].resource_size = sizeof (String);
913 resources [0].resource_offset = 0;
914 resources [0].default_type = XtRString;
915 resources [0].default_addr = 0;
916 resources [1].resource_name = XtNiconName;
917 resources [1].resource_class = XtCIconName;
918 resources [1].resource_type = XtRString;
919 resources [1].resource_size = sizeof (String);
920 resources [1].resource_offset = sizeof (char *);
921 resources [1].default_type = XtRString;
922 resources [1].default_addr = 0;
923 XtGetSubresources (XtParent (shell), (XtPointer) results,
924 shell->core.name,
925 shell->core.widget_class->core_class.class_name,
926 resources, XtNumber (resources), 0, 0);
927 if (results[0])
928 Vframe_title_format = build_string (results[0]);
929 if (results[1])
930 Vframe_icon_title_format = build_string (results[1]);
931 }
932
933 frame_title_format_already_set = 1;
934 }
935
936 #ifdef HAVE_CDE
937 #include <Dt/Dt.h>
938 #include <Dt/Dnd.h>
939
940 void
941 x_cde_transfer_callback (Widget widget, XtPointer clientData,
942 XtPointer callData)
943 {
944 char *filePath;
945 int ii;
946 Lisp_Object path = Qnil;
947 Lisp_Object frame = Qnil;
948 struct gcpro gcpro1, gcpro2;
949
950 DtDndTransferCallbackStruct *transferInfo =
951 (DtDndTransferCallbackStruct *) callData;
952
953 if (transferInfo == NULL)
954 return;
955
956 GCPRO2 (path, frame);
957
958 frame = make_frame ((struct frame *) clientData);
959 if (transferInfo->dropData->protocol == DtDND_FILENAME_TRANSFER)
960 {
961 for (ii = 0; ii < transferInfo->dropData->numItems; ii++)
962 {
963 filePath = transferInfo->dropData->data.files[ii];
964 path = make_string (filePath, strlen (filePath));
965 va_run_hook_with_args (Qdrag_and_drop_functions, 2, frame, path);
966 }
967 }
968
969 UNGCPRO;
970 return;
971 }
972 #endif
973
974
975 /************************************************************************/
976 /* widget creation */
977 /************************************************************************/
978
979 /* The widget hierarchy is
980
981 argv[0] shell container FRAME-NAME
982 ApplicationShell EmacsShell EmacsManager EmacsFrame
983
984 We accept geometry specs in this order:
985
986 *FRAME-NAME.geometry
987 *EmacsFrame.geometry
988 Emacs.geometry
989
990 Other possibilities for widget hierarchies might be
991
992 argv[0] frame container FRAME-NAME
993 ApplicationShell EmacsShell EmacsManager EmacsFrame
994 or
995 argv[0] FRAME-NAME container FRAME-NAME
996 ApplicationShell EmacsShell EmacsManager EmacsFrame
997 or
998 argv[0] FRAME-NAME container emacsTextPane
999 ApplicationShell EmacsShell EmacsManager EmacsFrame
1000
1001 #ifdef EXTERNAL_WIDGET
1002 The ExternalShell widget is simply a replacement for the Shell widget
1003 which is able to deal with using an externally-supplied window instead
1004 of always creating its own.
1005 #endif
1006
1007 */
1008
1009 #ifdef EXTERNAL_WIDGET
1010
1011 static int
1012 is_valid_window (Window w, struct device *d)
1013 {
1014 XWindowAttributes xwa;
1015 Display *dpy = DEVICE_X_DISPLAY (d);
1016
1017 expect_x_error (dpy);
1018 XGetWindowAttributes (dpy, w, &xwa);
1019 return !x_error_occurred_p (dpy);
1020 }
1021
1022 #endif /* EXTERNAL_WIDGET */
1023
1024 /* This sends a synthetic mouse-motion event to the frame, if the mouse
1025 is over the frame. This ensures that the cursor gets set properly
1026 before the user moves the mouse for the first time. */
1027
1028 static void
1029 x_send_synthetic_mouse_event (struct frame *f)
1030 {
1031 /* #### write this function. */
1032 }
1033
1034 static int
1035 first_x_frame_p (struct frame *f)
1036 {
1037 Lisp_Object rest = DEVICE_FRAME_LIST (XDEVICE (f->device));
1038 while (!NILP (rest) &&
1039 (f == XFRAME (XCAR (rest)) ||
1040 !FRAME_X_P (XFRAME (XCAR (rest)))))
1041 rest = XCDR (rest);
1042 return (NILP (rest));
1043 }
1044
1045 /* Figure out what size the EmacsFrame widget should initially be,
1046 and set it. Should be called after the default font has been
1047 determined but before the widget has been realized. */
1048
1049 static void
1050 x_initialize_frame_size (struct frame *f)
1051 {
1052 /* Geometry of the AppShell */
1053 int app_flags = 0;
1054 int app_x = 0;
1055 int app_y = 0;
1056 unsigned int app_w = 0;
1057 unsigned int app_h = 0;
1058
1059 /* Geometry of the EmacsFrame */
1060 int frame_flags = 0;
1061 int frame_x = 0;
1062 int frame_y = 0;
1063 unsigned int frame_w = 0;
1064 unsigned int frame_h = 0;
1065
1066 /* Hairily merged geometry */
1067 int x = 0;
1068 int y = 0;
1069 unsigned int w = 80;
1070 unsigned int h = 40;
1071 int flags = 0;
1072
1073 char *geom = 0, *ew_geom = 0;
1074 Boolean iconic_p = False, ew_iconic_p = False;
1075
1076 Widget wmshell = FRAME_X_SHELL_WIDGET (f);
1077 /* #### This may not be an ApplicationShell any more, with the 'popup
1078 frame property. */
1079 Widget app_shell = XtParent (wmshell);
1080 Widget ew = FRAME_X_TEXT_WIDGET (f);
1081
1082 /* set the position of the frame's root window now. When the
1083 frame was created, the position was initialized to (0,0). */
1084 {
1085 struct window *win = XWINDOW (f->root_window);
1086
1087 WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f);
1088 WINDOW_TOP (win) = FRAME_TOP_BORDER_END (f);
1089
1090 if (!NILP (f->minibuffer_window))
1091 {
1092 win = XWINDOW (f->minibuffer_window);
1093 WINDOW_LEFT (win) = FRAME_LEFT_BORDER_END (f);
1094 }
1095 }
1096
1097 #ifdef EXTERNAL_WIDGET
1098 /* If we're an external widget, then the size of the frame is predetermined
1099 (by the client) and is not our decision to make. */
1100 if (FRAME_X_EXTERNAL_WINDOW_P (f))
1101 return;
1102 #endif
1103
1104 #if 0
1105 /* #### this junk has not been tested; therefore it's
1106 probably wrong. Doesn't really matter at this point because
1107 currently all frames are either top-level or external widgets. */
1108
1109 /* If we're not our own top-level window, then we shouldn't go messing around
1110 with top-level shells or "Emacs.geometry" or any such stuff. Therefore,
1111 we do as follows to determine the size of the frame:
1112
1113 1) If a value for the frame's "geometry" resource was specified, then
1114 use it. (This specifies a size in characters.)
1115 2) Else, if the "width" and "height" resources were specified, then
1116 leave them alone. (This is a value in pixels. Sorry, we can't break
1117 Xt conventions here.)
1118 3) Else, assume a size of 64x12. (This is somewhat arbitrary, but
1119 it's unlikely that a size of 80x40 is desirable because we're probably
1120 inside of a dialog box.)
1121
1122 Set the widget's x, y, height, and width as determined. Don't set the
1123 top-level container widget, because we don't necessarily know what it
1124 is. (Assume it is smart and pays attention to our values.)
1125 */
1126
1127 if (!FRAME_X_TOP_LEVEL_FRAME_P (f))
1128 {
1129 XtVaGetValues (ew, XtNgeometry, &ew_geom, 0);
1130 if (ew_geom)
1131 frame_flags = XParseGeometry (ew_geom, &frame_x, &frame_y,
1132 &frame_w, &frame_h);
1133 if (! (frame_flags & (WidthValue | HeightValue)))
1134 {
1135 XtVaGetValues (ew, XtNwidth, &frame_w,
1136 XtNheight, &frame_h, 0);
1137 if (!frame_w && !frame_h)
1138 {
1139 frame_w = 64;
1140 frame_h = 12;
1141 frame_flags |= WidthValue | HeightValue;
1142 }
1143 }
1144 if (frame_flags & (WidthValue | HeightValue))
1145 EmacsFrameSetCharSize (ew, frame_w, frame_h);
1146 if (frame_flags & (XValue | YValue))
1147 {
1148 XtVaGetValues (ew, XtNwidth, &frame_w,
1149 XtNheight, &frame_h, 0);
1150 if (frame_flags & XNegative)
1151 frame_x += frame_w;
1152 if (frame_flags & YNegative)
1153 frame_y += frame_h;
1154 XtVaSetValues (ew, XtNx, frame_x, XtNy, frame_y, 0);
1155 }
1156 return;
1157 }
1158 #endif
1159
1160 /* OK, we're a top-level shell. */
1161
1162 if (!XtIsWMShell (wmshell))
1163 abort ();
1164
1165 /* If the EmacsFrame doesn't have a geometry but the shell does,
1166 treat that as the geometry of the frame. (Is this bogus?
1167 I'm not sure.) */
1168
1169 XtVaGetValues (ew, XtNgeometry, &ew_geom, 0);
1170 if (!ew_geom)
1171 {
1172 XtVaGetValues (wmshell, XtNgeometry, &geom, 0);
1173 if (geom)
1174 {
1175 ew_geom = geom;
1176 XtVaSetValues (ew, XtNgeometry, ew_geom, 0);
1177 }
1178 }
1179
1180 /* If the Shell is iconic, then the EmacsFrame is iconic. (Is
1181 this bogus? I'm not sure.) */
1182 XtVaGetValues (ew, XtNiconic, &ew_iconic_p, 0);
1183 if (!ew_iconic_p)
1184 {
1185 XtVaGetValues (wmshell, XtNiconic, &iconic_p, 0);
1186 if (iconic_p)
1187 {
1188 ew_iconic_p = iconic_p;
1189 XtVaSetValues (ew, XtNiconic, iconic_p, 0);
1190 }
1191 }
1192
1193 XtVaGetValues (app_shell, XtNgeometry, &geom, 0);
1194 if (geom)
1195 app_flags = XParseGeometry (geom, &app_x, &app_y, &app_w, &app_h);
1196
1197 if (ew_geom)
1198 frame_flags = XParseGeometry (ew_geom, &frame_x, &frame_y,
1199 &frame_w, &frame_h);
1200
1201 if (first_x_frame_p (f))
1202 {
1203 /* If this is the first frame created:
1204 ====================================
1205
1206 - Use the ApplicationShell's size/position, if specified.
1207 (This is "Emacs.geometry", or the "-geometry" command line arg.)
1208 - Else use the EmacsFrame's size/position.
1209 (This is "*FRAME-NAME.geometry")
1210
1211 - If the AppShell is iconic, the frame should be iconic.
1212
1213 AppShell comes first so that -geometry always applies to the first
1214 frame created, even if there is an "every frame" entry in the
1215 resource database.
1216 */
1217 if (app_flags & (XValue | YValue))
1218 {
1219 x = app_x; y = app_y;
1220 flags |= (app_flags & (XValue | YValue | XNegative | YNegative));
1221 }
1222 else if (frame_flags & (XValue | YValue))
1223 {
1224 x = frame_x; y = frame_y;
1225 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1226 }
1227
1228 if (app_flags & (WidthValue | HeightValue))
1229 {
1230 w = app_w; h = app_h;
1231 flags |= (app_flags & (WidthValue | HeightValue));
1232 }
1233 else if (frame_flags & (WidthValue | HeightValue))
1234 {
1235 w = frame_w; h = frame_h;
1236 flags |= (frame_flags & (WidthValue | HeightValue));
1237 }
1238
1239 /* If the AppShell is iconic, then the EmacsFrame is iconic. */
1240 if (!ew_iconic_p)
1241 {
1242 XtVaGetValues (app_shell, XtNiconic, &iconic_p, 0);
1243 if (iconic_p)
1244 {
1245 ew_iconic_p = iconic_p;
1246 XtVaSetValues (ew, XtNiconic, iconic_p, 0);
1247 }
1248 }
1249 }
1250 else
1251 {
1252 /* If this is not the first frame created:
1253 ========================================
1254
1255 - use the EmacsFrame's size/position if specified
1256 - Otherwise, use the ApplicationShell's size, but not position.
1257
1258 So that means that one can specify the position of the first frame
1259 with "Emacs.geometry" or `-geometry'; but can only specify the
1260 position of subsequent frames with "*FRAME-NAME.geometry".
1261
1262 AppShell comes second so that -geometry does not apply to subsequent
1263 frames when there is an "every frame" entry in the resource db,
1264 but does apply to the first frame.
1265 */
1266 if (frame_flags & (XValue | YValue))
1267 {
1268 x = frame_x; y = frame_y;
1269 flags |= (frame_flags & (XValue | YValue | XNegative | YNegative));
1270 }
1271
1272 if (frame_flags & (WidthValue | HeightValue))
1273 {
1274 w = frame_w; h = frame_h;
1275 flags |= (frame_flags & (WidthValue | HeightValue));
1276 }
1277 else if (app_flags & (WidthValue | HeightValue))
1278 {
1279 w = app_w;
1280 h = app_h;
1281 flags |= (app_flags & (WidthValue | HeightValue));
1282 }
1283 }
1284
1285 x_set_initial_frame_size (f, flags, x, y, w, h);
1286 }
1287
1288 static void
1289 x_get_layout_sizes (struct frame *f, Dimension *topbreadth)
1290 {
1291 int i;
1292
1293 /* compute height of all top-area widgets */
1294 for (i=0, *topbreadth = 0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1295 {
1296 Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1297 if (wid && XtIsManaged (wid))
1298 *topbreadth += wid->core.height + 2*wid->core.border_width;
1299 }
1300 }
1301
1302 static void
1303 x_layout_widgets (Widget w, XtPointer client_data, XtPointer call_data)
1304 {
1305 struct frame *f = (struct frame *) client_data;
1306 EmacsManagerResizeStruct *emst = (EmacsManagerResizeStruct *) call_data;
1307 Dimension width = emst->width;
1308 Dimension height = emst->height;
1309 Widget text = FRAME_X_TEXT_WIDGET (f);
1310 Dimension textbord = text->core.border_width;
1311 Dimension topbreadth;
1312 Position text_x = 0, text_y = 0;
1313 int i;
1314
1315 x_get_layout_sizes (f, &topbreadth);
1316
1317 /* first the menubar and psheets ... */
1318 for (i=0; i<FRAME_X_NUM_TOP_WIDGETS (f); i++)
1319 {
1320 Widget wid = FRAME_X_TOP_WIDGETS (f)[i];
1321 if (wid && XtIsManaged (wid))
1322 {
1323 Dimension bord = wid->core.border_width;
1324 XtConfigureWidget (wid, 0, text_y,
1325 width - 2*bord, wid->core.height,
1326 bord);
1327 text_y += wid->core.height + 2*bord;
1328 }
1329 }
1330
1331 #ifdef HAVE_SCROLLBARS
1332 {
1333 /* The scrollbar positioning is completely handled by redisplay. We
1334 just need to know which sides they are supposed to go on. */
1335 unsigned char scrollbar_placement;
1336 XtVaGetValues (text, XtNscrollBarPlacement, &scrollbar_placement, 0);
1337 f->scrollbar_on_left = (scrollbar_placement == XtTOP_LEFT ||
1338 scrollbar_placement == XtBOTTOM_LEFT);
1339 f->scrollbar_on_top = (scrollbar_placement == XtTOP_LEFT ||
1340 scrollbar_placement == XtTOP_RIGHT);
1341 f->scrollbar_y_offset = topbreadth + textbord;
1342 }
1343 #endif
1344
1345 /* finally the text area */
1346 XtConfigureWidget (text, text_x, text_y,
1347 width - 2*textbord,
1348 height - text_y - 2*textbord,
1349 textbord);
1350 }
1351
1352 static void
1353 x_do_query_geometry (Widget w, XtPointer client_data, XtPointer call_data)
1354 {
1355 struct frame *f = (struct frame *) client_data;
1356 EmacsManagerQueryGeometryStruct *emst =
1357 (EmacsManagerQueryGeometryStruct *) call_data;
1358 Widget text = FRAME_X_TEXT_WIDGET (f);
1359 Dimension textbord = text->core.border_width;
1360 Dimension topbreadth;
1361 XtWidgetGeometry req, repl;
1362 int mask = emst->request_mode & (CWWidth | CWHeight);
1363
1364 x_get_layout_sizes (f, &topbreadth);
1365
1366 /* strip away menubar from suggested size, and ask the text widget
1367 what size it wants to be */
1368 req.request_mode = mask;
1369 if (mask & CWWidth)
1370 req.width = emst->proposed_width - 2*textbord;
1371 if (mask & CWHeight)
1372 req.height = emst->proposed_height - topbreadth - 2*textbord;
1373 XtQueryGeometry (text, &req, &repl);
1374
1375 /* Now add the menubar back again */
1376 emst->proposed_width = repl.width + 2*textbord;
1377 emst->proposed_height = repl.height + topbreadth + 2*textbord;
1378 }
1379
1380 /* Creates the widgets for a frame.
1381 lisp_window_id is a Lisp description of an X window or Xt
1382 widget to parse.
1383
1384 This function does not create or map the windows. (That is
1385 done by x_popup_frame().)
1386 */
1387 static void
1388 x_create_widgets (struct frame *f, Lisp_Object lisp_window_id,
1389 Lisp_Object parent)
1390 {
1391 struct device *d = XDEVICE (f->device);
1392 #ifdef EXTERNAL_WIDGET
1393 Window window_id = 0;
1394 #endif
1395 CONST char *name;
1396 Arg av [25];
1397 int ac = 0;
1398 Widget text, container, shell;
1399 Widget parentwid = 0;
1400 #ifdef HAVE_MENUBARS
1401 int menubar_visible;
1402 Widget menubar;
1403 #endif
1404
1405 if (STRINGP (f->name))
1406 GET_C_STRING_CTEXT_DATA_ALLOCA (f->name, name);
1407 else
1408 name = "emacs";
1409
1410 /* The widget hierarchy is
1411
1412 argv[0] shell pane FRAME-NAME
1413 ApplicationShell EmacsShell EmacsManager EmacsFrame
1414
1415 (the type of the shell is ExternalShell if this frame is running
1416 in another client's window)
1417
1418 However the EmacsShell widget has WM_CLASS of FRAME-NAME/Emacs.
1419 Normally such shells have name/class shellname/appclass, which in this
1420 case would be "shell/Emacs" instead of "frame-name/Emacs". We could
1421 also get around this by naming the shell "frame-name", but that would
1422 be confusing because the text area (the EmacsFrame widget inferior of
1423 the shell) is also called that. So we just set the WM_CLASS property.
1424 */
1425
1426 #ifndef EXTERNAL_WIDGET
1427 if (!NILP (lisp_window_id))
1428 error ("support for external widgets was not enabled at compile-time");
1429 #else
1430 if (!NILP (lisp_window_id))
1431 {
1432 char *string;
1433
1434 CHECK_STRING (lisp_window_id);
1435 string = (char *) (string_data (XSTRING (lisp_window_id)));
1436 if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
1437 sscanf (string+2, "%lxu", &window_id);
1438 #if 0
1439 else if (string[0] == 'w')
1440 {
1441 sscanf (string+1, "%x", &parent_widget);
1442 if (parent_widget)
1443 window_id = XtWindow (parent_widget);
1444 }
1445 #endif
1446 else
1447 sscanf (string, "%lu", &window_id);
1448 if (!is_valid_window (window_id, d))
1449 error ("Invalid window %lu", (unsigned long) window_id);
1450 FRAME_X_EXTERNAL_WINDOW_P (f) = 1;
1451 } else
1452 #endif /* EXTERNAL_WIDGET */
1453 FRAME_X_TOP_LEVEL_FRAME_P (f) = 1;
1454
1455 ac = 0;
1456 XtSetArg (av[ac], XtNallowShellResize, True); ac++;
1457 #ifdef LWLIB_USES_MOTIF
1458 /* Motif sucks beans. Without this in here, it will delete the window
1459 out from under us when it receives a WM_DESTROY_WINDOW message
1460 from the WM. */
1461 XtSetArg (av[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
1462 #endif
1463
1464 #ifdef EXTERNAL_WIDGET
1465 if (window_id)
1466 {
1467 XtSetArg (av[ac], XtNwindow, window_id); ac++;
1468 }
1469 else
1470 #endif
1471 {
1472 XtSetArg (av[ac], XtNinput, True); ac++;
1473 XtSetArg (av[ac], XtNminWidthCells, 10); ac++;
1474 XtSetArg (av[ac], XtNminHeightCells, 1); ac++;
1475 }
1476
1477 if (!NILP (parent))
1478 {
1479 parentwid = FRAME_X_SHELL_WIDGET (XFRAME (parent));
1480 XtSetArg (av[ac], XtNtransientFor, parentwid); ac++;
1481 }
1482
1483 shell = XtCreatePopupShell ("shell",
1484 (
1485 #ifdef EXTERNAL_WIDGET
1486 window_id ? externalShellWidgetClass :
1487 #endif
1488 parentwid ? transientEmacsShellWidgetClass :
1489 topLevelEmacsShellWidgetClass
1490 ),
1491 parentwid ? parentwid :
1492 DEVICE_XT_APP_SHELL (d),
1493 av, ac);
1494 FRAME_X_SHELL_WIDGET (f) = shell;
1495 maybe_set_frame_title_format (shell);
1496
1497 /* Create the manager widget */
1498 container = XtVaCreateWidget ("container",
1499 emacsManagerWidgetClass,
1500 shell, 0);
1501 FRAME_X_CONTAINER_WIDGET (f) = container;
1502 XtAddCallback (container, XtNresizeCallback, x_layout_widgets,
1503 (XtPointer) f);
1504 XtAddCallback (container, XtNqueryGeometryCallback, x_do_query_geometry,
1505 (XtPointer) f);
1506
1507 /* Create the text area */
1508 ac = 0;
1509 XtSetArg (av[ac], XtNborderWidth, 0); ac++; /* should this be settable? */
1510 XtSetArg (av[ac], XtNemacsFrame, f); ac++;
1511 text = XtCreateWidget (name,
1512 emacsFrameClass,
1513 container, av, ac);
1514 FRAME_X_TEXT_WIDGET (f) = text;
1515
1516 #ifdef HAVE_MENUBARS
1517 /* Create the initial menubar widget. */
1518 menubar_visible = x_initialize_frame_menubar (f);
1519 FRAME_X_TOP_WIDGETS (f)[0] = menubar = FRAME_X_MENUBAR_WIDGET (f);
1520 FRAME_X_NUM_TOP_WIDGETS (f) = 1;
1521
1522 if (menubar_visible)
1523 XtManageChild (menubar);
1524 #endif
1525 XtManageChild (text);
1526 XtManageChild (container);
1527 }
1528
1529 /* We used to call XtPopup() in x_popup_frame, but that doesn't give
1530 you control over whether the widget is initially mapped or not
1531 because XtPopup() makes an unconditional call to XMapRaised().
1532 Boy, those Xt designers were clever.
1533
1534 When we first removed it we only kept the XtRealizeWidget call in
1535 XtPopup. For everything except HP's that was enough. For HP's,
1536 though, the failure to call the popup callbacks resulted in XEmacs
1537 not accepting any input. Bizarre but true. Stupid but true.
1538
1539 So, in case there are any other gotches floating out there along
1540 the same lines I've duplicated the majority of XtPopup here. It
1541 assumes no grabs and that the widget is not already popped up, both
1542 valid assumptions for the one place this is called from. */
1543 static void
1544 xemacs_XtPopup (Widget widget)
1545 {
1546 ShellWidget shell_widget = (ShellWidget) widget;
1547 XtGrabKind call_data = XtGrabNone;
1548
1549 XtCallCallbacks (widget, XtNpopupCallback, (XtPointer)&call_data);
1550
1551 shell_widget->shell.popped_up = TRUE;
1552 shell_widget->shell.grab_kind = XtGrabNone;
1553 shell_widget->shell.spring_loaded = False;
1554
1555 if (shell_widget->shell.create_popup_child_proc != NULL)
1556 (*(shell_widget->shell.create_popup_child_proc))(widget);
1557
1558 /* The XtVaSetValues below are not in XtPopup menu. We just want to
1559 make absolutely sure... */
1560 XtVaSetValues (widget, XtNmappedWhenManaged, False, NULL);
1561 XtRealizeWidget (widget);
1562 XtVaSetValues (widget, XtNmappedWhenManaged, True, NULL);
1563 }
1564
1565 #ifdef HAVE_CDE
1566 /* Does this have to be non-automatic? */
1567 /* hack frame to respond to dnd messages */
1568 static XtCallbackRec dnd_transfer_cb_rec[2];
1569 #endif
1570
1571 /* create the windows for the specified frame and display them.
1572 Note that the widgets have already been created, and any
1573 necessary geometry calculations have already been done. */
1574 static void
1575 x_popup_frame (struct frame *f)
1576 {
1577 Widget shell_widget = FRAME_X_SHELL_WIDGET (f);
1578 Widget frame_widget = FRAME_X_TEXT_WIDGET (f);
1579 struct device *d = XDEVICE (FRAME_DEVICE (f));
1580
1581 /* Before mapping the window, make sure that the WMShell's notion of
1582 whether it should be iconified is synchronized with the EmacsFrame's
1583 notion.
1584 */
1585 if (FRAME_X_TOP_LEVEL_FRAME_P (f))
1586 x_wm_set_shell_iconic_p (shell_widget,
1587 ((EmacsFrame) frame_widget)
1588 ->emacs_frame.iconic);
1589
1590 xemacs_XtPopup (shell_widget);
1591
1592 if (!((EmacsFrame) frame_widget)->emacs_frame.initially_unmapped)
1593 XtMapWidget (shell_widget);
1594 else
1595 {
1596 /* We may have set f->visible to 1 in x_init_frame(), so undo
1597 that now. */
1598 FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
1599 f->visible = 0;
1600 }
1601
1602 #ifdef EXTERNAL_WIDGET
1603 if (FRAME_X_EXTERNAL_WINDOW_P (f))
1604 ExternalShellReady (shell_widget, XtWindow (frame_widget), KeyPressMask);
1605 else
1606 #endif
1607 if (FRAME_X_TOP_LEVEL_FRAME_P (f))
1608 {
1609 /* tell the window manager about us. */
1610 x_wm_store_class_hints (shell_widget, XtName (frame_widget));
1611 x_wm_maybe_store_wm_command (f);
1612 x_wm_hack_wm_protocols (shell_widget);
1613 }
1614
1615 #ifdef HACK_EDITRES
1616 /* Allow XEmacs to respond to EditRes requests. See the O'Reilly Xt */
1617 /* Instrinsics Programming Manual, Motif Edition, Aug 1993, Sect 14.14, */
1618 /* pp. 483-493. */
1619 XtAddEventHandler (shell_widget, /* the shell widget in question */
1620 (EventMask) NoEventMask,/* OR with existing mask */
1621 True, /* called on non-maskable events? */
1622 _XEditResCheckMessages, /* the handler */
1623 NULL);
1624 #endif
1625
1626 #ifdef HAVE_CDE
1627 {
1628 dnd_transfer_cb_rec[0].callback = x_cde_transfer_callback;
1629 dnd_transfer_cb_rec[0].closure = (XtPointer) f;
1630 dnd_transfer_cb_rec[1].callback = NULL;
1631 dnd_transfer_cb_rec[1].closure = NULL;
1632
1633 DtDndVaDropRegister (FRAME_X_TEXT_WIDGET (f),
1634 DtDND_FILENAME_TRANSFER,
1635 XmDROP_COPY,
1636 dnd_transfer_cb_rec,
1637 DtNpreserveRegistration, False,
1638 NULL);
1639 }
1640 #endif
1641
1642 /* Do a stupid property change to force the server to generate a
1643 propertyNotify event so that the event_stream server timestamp will
1644 be initialized to something relevant to the time we created the window.
1645 */
1646 XChangeProperty (XtDisplay (frame_widget), XtWindow (frame_widget),
1647 DEVICE_XATOM_WM_PROTOCOLS (d), XA_ATOM, 32, PropModeAppend,
1648 (unsigned char*) NULL, 0);
1649
1650 x_send_synthetic_mouse_event (f);
1651 }
1652
1653 static void
1654 allocate_x_frame_struct (struct frame *f)
1655 {
1656 /* zero out all slots. */
1657 f->frame_data = malloc_type_and_zero (struct x_frame);
1658
1659 /* yeah, except the lisp ones */
1660 FRAME_X_ICON_PIXMAP (f) = Qnil;
1661 FRAME_X_ICON_PIXMAP_MASK (f) = Qnil;
1662 #ifdef ENERGIZE
1663 FRAME_X_CURRENT_PSHEET_BUFFER (f) = Qnil;
1664 FRAME_X_DESIRED_PSHEET_BUFFER (f) = Qnil;
1665 #endif
1666 }
1667
1668
1669 /************************************************************************/
1670 /* Lisp functions */
1671 /************************************************************************/
1672
1673 static void
1674 x_init_frame_1 (struct frame *f, Lisp_Object props)
1675 {
1676 /* This function can GC */
1677 Lisp_Object device = FRAME_DEVICE (f);
1678 struct device *d = XDEVICE (device);
1679 Lisp_Object lisp_window_id;
1680 Lisp_Object popup;
1681
1682 lisp_window_id = Fplist_get (props, Qwindow_id, Qnil);
1683 popup = Fplist_get (props, Qpopup, Qnil);
1684 if (!NILP (popup))
1685 {
1686 if (EQ (popup, Qt))
1687 popup = Fselected_frame (device);
1688 CHECK_LIVE_FRAME (popup);
1689 if (!EQ (device, FRAME_DEVICE (XFRAME (popup))))
1690 signal_simple_error_2 ("Parent must be on same device as frame",
1691 device, popup);
1692 }
1693
1694 if (NILP (DEVICE_SELECTED_FRAME (d)))
1695 {
1696 /* This means that this is the first frame on the device.
1697 So short-ciruit the delay in processing the initial MapNotify
1698 event so that output on the first frame shows up right
1699 away... */
1700 f->visible = 1;
1701 }
1702
1703 allocate_x_frame_struct (f);
1704 x_create_widgets (f, lisp_window_id, popup);
1705 }
1706
1707 static void
1708 x_init_frame_2 (struct frame *f, Lisp_Object props)
1709 {
1710 /* Set up the values of the widget/frame. A case could be made for putting
1711 this inside of the widget's initialize method. */
1712
1713 update_frame_face_values (f);
1714 x_initialize_frame_size (f);
1715 update_frame_title (f);
1716 }
1717
1718 static void
1719 x_init_frame_3 (struct frame *f)
1720 {
1721 /* Pop up the frame. */
1722
1723 x_popup_frame (f);
1724 }
1725
1726 static void
1727 x_mark_frame (struct frame *f, void (*markobj) (Lisp_Object))
1728 {
1729 ((markobj) (FRAME_X_ICON_PIXMAP (f)));
1730 ((markobj) (FRAME_X_ICON_PIXMAP_MASK (f)));
1731 #ifdef ENERGIZE
1732 ((markobj) (FRAME_X_CURRENT_PSHEET_BUFFER (f)));
1733 ((markobj) (FRAME_X_DESIRED_PSHEET_BUFFER (f)));
1734 #endif
1735 }
1736
1737 static void
1738 x_set_frame_icon (struct frame *f)
1739 {
1740 Pixmap x_pixmap, x_mask;
1741
1742 if (IMAGE_INSTANCEP (f->icon)
1743 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (f->icon)))
1744 {
1745 x_pixmap = XIMAGE_INSTANCE_X_PIXMAP (f->icon);
1746 x_mask = XIMAGE_INSTANCE_X_MASK (f->icon);
1747 }
1748 else
1749 {
1750 x_pixmap = 0;
1751 x_mask = 0;
1752 }
1753
1754 /* Store the X data into the widget. */
1755 {
1756 Arg av [10];
1757 int ac = 0;
1758 XtSetArg (av [ac], XtNiconPixmap, x_pixmap); ac++;
1759 XtSetArg (av [ac], XtNiconMask, x_mask); ac++;
1760 XtSetValues (FRAME_X_SHELL_WIDGET (f), av, ac);
1761 }
1762 }
1763
1764 static void
1765 x_set_frame_pointer (struct frame *f)
1766 {
1767 XDefineCursor (XtDisplay (FRAME_X_TEXT_WIDGET (f)),
1768 XtWindow (FRAME_X_TEXT_WIDGET (f)),
1769 XIMAGE_INSTANCE_X_CURSOR (f->pointer));
1770 XSync (XtDisplay (FRAME_X_TEXT_WIDGET (f)), 0);
1771 }
1772
1773 static Lisp_Object
1774 x_get_frame_parent (struct frame *f)
1775 {
1776 Widget parentwid = 0;
1777 Arg av[1];
1778
1779 XtSetArg (av[0], XtNtransientFor, &parentwid);
1780 XtGetValues (FRAME_X_SHELL_WIDGET (f), av, 1);
1781 /* find the frame whose wid is parentwid */
1782 if (parentwid)
1783 {
1784 Lisp_Object frmcons;
1785 DEVICE_FRAME_LOOP (frmcons, XDEVICE (FRAME_DEVICE (f)))
1786 {
1787 Lisp_Object frame = XCAR (frmcons);
1788 if (FRAME_X_SHELL_WIDGET (XFRAME (frame)) == parentwid)
1789 return frame;
1790 }
1791 }
1792 return Qnil;
1793 }
1794
1795 DEFUN ("x-window-id", Fx_window_id, Sx_window_id, 0, 1, 0 /*
1796 Get the ID of the X11 window.
1797 This gives us a chance to manipulate the Emacs window from within a
1798 different program. Since the ID is an unsigned long, we return it as
1799 a string.
1800 */ )
1801 (frame)
1802 Lisp_Object frame;
1803 {
1804 char str[255];
1805 struct frame *f = decode_x_frame (frame);
1806
1807 sprintf (str, "%lu", XtWindow (FRAME_X_TEXT_WIDGET (f)));
1808 return build_string (str);
1809 }
1810
1811
1812 /************************************************************************/
1813 /* manipulating the X window */
1814 /************************************************************************/
1815
1816 static void
1817 x_set_frame_position (struct frame *f, int xoff, int yoff)
1818 {
1819 Widget w = FRAME_X_SHELL_WIDGET (f);
1820 Display *dpy = XtDisplay (w);
1821 Dimension frame_w = DisplayWidth (dpy, DefaultScreen (dpy));
1822 Dimension frame_h = DisplayHeight (dpy, DefaultScreen (dpy));
1823 Dimension shell_w, shell_h, shell_bord;
1824 int win_gravity;
1825
1826 XtVaGetValues (w,
1827 XtNwidth, &shell_w,
1828 XtNheight, &shell_h,
1829 XtNborderWidth, &shell_bord,
1830 0);
1831
1832 win_gravity =
1833 xoff >= 0 && yoff >= 0 ? NorthWestGravity :
1834 xoff >= 0 ? SouthWestGravity :
1835 yoff >= 0 ? NorthEastGravity :
1836 SouthEastGravity;
1837 if (xoff < 0)
1838 xoff += frame_w - shell_w - 2*shell_bord;
1839 if (yoff < 0)
1840 yoff += frame_h - shell_h - 2*shell_bord;
1841
1842 /* Update the hints so that, if this window is currently iconified, it will
1843 come back at the right place. We can't look at s->visible to determine
1844 whether it is iconified because it might not be up-to-date yet (the queue
1845 might not be processed). */
1846 XtVaSetValues (w,
1847 XtNwinGravity, win_gravity,
1848 XtNx, xoff,
1849 XtNy, yoff,
1850 0);
1851 /* Sometimes you will find that
1852
1853 (set-frame-position (selected-frame) -50 -50)
1854
1855 doesn't put the frame where you expect it to:
1856 i.e. it's closer to the lower-right corner than
1857 ) it should be, and it appears that the size of
1858 the WM decorations was not taken into account.
1859 This is *not* a problem with this function.
1860 Both mwm and twm have bugs in handling this
1861 situation. (mwm ignores the window gravity
1862 and always assumes NorthWest, except the first
1863 time you map the window; twm gets things almost
1864 right, but forgets to account for the border
1865 width of the top-level window.) This function
1866 does what it's supposed to according to the ICCCM,
1867 and I'm not about to hack around window-manager
1868 bugs. */
1869
1870 #if 0
1871 /* This is not necessary under either mwm or twm */
1872 x_wm_mark_shell_position_user_specified (w);
1873 #endif
1874 }
1875
1876 /* Call this to change the size of frame S's x-window. */
1877
1878 static void
1879 x_set_frame_size (struct frame *f, int cols, int rows)
1880 {
1881 EmacsFrameSetCharSize (FRAME_X_TEXT_WIDGET (f), cols, rows);
1882 #if 0
1883 /* this is not correct. x_set_frame_size() is called from
1884 Fset_frame_size(), which may or may not have been called
1885 by the user (e.g. update_EmacsFrame() calls it when the font
1886 changes). For now, don't bother with getting this right. */
1887 x_wm_mark_shell_size_user_specified (FRAME_X_SHELL_WIDGET (f));
1888 #endif
1889 }
1890
1891 static void
1892 x_set_mouse_position (struct window *w, int x, int y)
1893 {
1894 struct frame *f = XFRAME (w->frame);
1895
1896 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
1897 XWarpPointer (display, None, XtWindow (FRAME_X_TEXT_WIDGET (f)),
1898 0, 0, 0, 0, w->pixel_left + x, w->pixel_top + y);
1899 }
1900
1901 static int
1902 x_get_mouse_position (struct device *d, Lisp_Object *frame, int *x, int *y)
1903 {
1904 Display *display = DEVICE_X_DISPLAY (d);
1905 Window child_window;
1906 Window root_window;
1907 Window win;
1908 int root_x, root_y;
1909 int win_x, win_y;
1910 unsigned int keys_and_buttons;
1911 struct frame *f;
1912
1913 if (XQueryPointer (display, RootWindow (display, DefaultScreen (display)),
1914 &root_window, &child_window, &root_x, &root_y,
1915 &win_x, &win_y, &keys_and_buttons) == False)
1916 return 0;
1917
1918 if (child_window == None)
1919 return 0; /* not over any window. */
1920
1921 while (1)
1922 {
1923 win = child_window;
1924 if (XTranslateCoordinates (display, root_window, win, root_x, root_y,
1925 &win_x, &win_y, &child_window) == False)
1926 /* Huh? */
1927 return 0;
1928
1929 if (child_window == None)
1930 break;
1931 }
1932
1933 /* At this point, win is the innermost window containing the pointer
1934 and win_x and win_y are the coordinates of that window. */
1935 f = x_any_window_to_frame (d, win);
1936 if (!f)
1937 return 0;
1938 XSETFRAME (*frame, f);
1939
1940 if (XTranslateCoordinates (display, win,
1941 XtWindow (FRAME_X_TEXT_WIDGET (f)),
1942 win_x, win_y, x, y, &child_window) == False)
1943 /* Huh? */
1944 return 0;
1945
1946 return 1;
1947 }
1948
1949 static void
1950 x_cant_notify_wm_error (void)
1951 {
1952 error ("Can't notify window manager of iconification.");
1953 }
1954
1955 /* Raise frame F. */
1956 static void
1957 x_raise_frame_1 (struct frame *f, int force)
1958 {
1959 Widget bottom_dialog;
1960 Window emacs_window;
1961 XWindowChanges xwc;
1962 unsigned int flags;
1963 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
1964
1965 if (f->visible || force)
1966 {
1967 emacs_window = XtWindow (FRAME_X_SHELL_WIDGET (f));
1968 /* first raises all the dialog boxes, then put emacs just below the
1969 * bottom most dialog box */
1970 bottom_dialog = lw_raise_all_pop_up_widgets ();
1971 if (bottom_dialog && XtWindow (bottom_dialog))
1972 {
1973 xwc.sibling = XtWindow (bottom_dialog);
1974 xwc.stack_mode = Below;
1975 flags = CWSibling | CWStackMode;
1976 }
1977 else
1978 {
1979 xwc.stack_mode = Above;
1980 flags = CWStackMode;
1981 }
1982
1983 if (!XReconfigureWMWindow (display, emacs_window,
1984 DefaultScreen (display),
1985 flags, &xwc))
1986 x_cant_notify_wm_error ();
1987 }
1988 }
1989
1990 static void
1991 x_raise_frame (struct frame *f)
1992 {
1993 x_raise_frame_1 (f, 1);
1994 }
1995
1996 /* Lower frame F. */
1997 static void
1998 x_lower_frame (struct frame *f)
1999 {
2000 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2001 XWindowChanges xwc;
2002 unsigned int flags;
2003
2004 if (f->visible)
2005 {
2006 xwc.stack_mode = Below;
2007 flags = CWStackMode;
2008 if (!XReconfigureWMWindow (display, XtWindow (FRAME_X_SHELL_WIDGET (f)),
2009 DefaultScreen (display), flags, &xwc))
2010 x_cant_notify_wm_error ();
2011 }
2012 }
2013
2014 /* Change from withdrawn state to mapped state. */
2015 static void
2016 x_make_frame_visible (struct frame *f)
2017 {
2018 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2019
2020 if (!f->visible)
2021 XMapRaised (display, XtWindow (FRAME_X_SHELL_WIDGET (f)));
2022 else
2023 x_raise_frame_1 (f, 0);
2024 }
2025
2026 /* Change from mapped state to withdrawn state. */
2027 static void
2028 x_make_frame_invisible (struct frame *f)
2029 {
2030 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2031
2032 if (!f->visible)
2033 return;
2034
2035 if (!XWithdrawWindow (display,
2036 XtWindow (FRAME_X_SHELL_WIDGET (f)),
2037 DefaultScreen (display)))
2038 x_cant_notify_wm_error ();
2039 }
2040
2041 static int
2042 x_frame_visible_p (struct frame *f)
2043 {
2044 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2045 XWindowAttributes xwa;
2046 int result;
2047
2048 if (!XGetWindowAttributes (display,
2049 XtWindow (FRAME_X_SHELL_WIDGET (f)),
2050 &xwa))
2051 result = 0;
2052 else
2053 result = xwa.map_state == IsViewable;
2054
2055 f->visible = result;
2056 return result;
2057 }
2058
2059 static int
2060 x_frame_totally_visible_p (struct frame *f)
2061 {
2062 return FRAME_X_TOTALLY_VISIBLE_P (f);
2063 }
2064
2065 /* Change window state from mapped to iconified. */
2066 static void
2067 x_iconify_frame (struct frame *f)
2068 {
2069 Display *display = DEVICE_X_DISPLAY (XDEVICE (f->device));
2070
2071 if (!XIconifyWindow (display,
2072 XtWindow (FRAME_X_SHELL_WIDGET (f)),
2073 DefaultScreen (display)))
2074 x_cant_notify_wm_error ();
2075
2076 f->iconified = 1;
2077 }
2078
2079 /* Sets the X focus to frame f. */
2080 static void
2081 x_focus_on_frame (struct frame *f)
2082 {
2083 XWindowAttributes xwa;
2084 Widget shell_widget;
2085
2086 assert (FRAME_X_P (f));
2087
2088 shell_widget = FRAME_X_SHELL_WIDGET (f);
2089 if (!XtWindow (shell_widget))
2090 return;
2091
2092 #ifdef EXTERNAL_WIDGET
2093 if (FRAME_X_EXTERNAL_WINDOW_P (f))
2094 ExternalShellSetFocus (shell_widget);
2095 #endif /* EXTERNAL_WIDGET */
2096
2097 /* Do the ICCCM focus change if the window is still visible.
2098 The s->visible flag might not be up-to-date, because we might
2099 not have processed magic events recently. So make a server
2100 round-trip to find out whether it's really mapped right now.
2101 We grab the server to do this, because that's the only way to
2102 eliminate the race condition.
2103 */
2104 XGrabServer (XtDisplay (shell_widget));
2105 if (XGetWindowAttributes (XtDisplay (shell_widget),
2106 XtWindow (shell_widget),
2107 &xwa))
2108 f->visible = xwa.map_state == IsViewable;
2109
2110 if (f->visible)
2111 {
2112 Window focus;
2113 int revert_to;
2114 XGetInputFocus (XtDisplay (shell_widget), &focus, &revert_to);
2115 /* Don't explicitly set the focus on this window unless the focus
2116 was on some other window (not PointerRoot). Note that, even when
2117 running a point-to-type window manager like *twm, there is always
2118 a focus window; the window manager maintains that based on the
2119 mouse position. If you set the "NoTitleFocus" option in these
2120 window managers, then the server itself maintains the focus via
2121 PointerRoot, and changing that to focus on the window would make
2122 the window grab the focus. Very bad.
2123 */
2124 if (focus != PointerRoot)
2125 {
2126 XSetInputFocus (XtDisplay (shell_widget),
2127 XtWindow (shell_widget),
2128 RevertToParent,
2129 DEVICE_X_MOUSE_TIMESTAMP
2130 (XDEVICE (FRAME_DEVICE (f))));
2131 XFlush (XtDisplay (shell_widget));
2132 }
2133 }
2134 XUngrabServer (XtDisplay (shell_widget));
2135 XFlush (XtDisplay (shell_widget)); /* hey, I'd like to DEBUG this... */
2136 }
2137
2138 /* Destroy the X window of frame S. */
2139 static void
2140 x_delete_frame (struct frame *f)
2141 {
2142 Widget w = FRAME_X_SHELL_WIDGET (f);
2143 Lisp_Object popup, frame;
2144
2145 if (FRAME_X_TOP_LEVEL_FRAME_P (f))
2146 x_wm_maybe_move_wm_command (f);
2147
2148 /* Frames with the popup property are using other frames as their
2149 widget parent. Deleting them are their parent has already been
2150 deleted can lead to crashes. */
2151 XSETFRAME (frame, f);
2152 popup = Fframe_property (frame, Qpopup, Qnil);
2153 if (!NILP (popup))
2154 {
2155 /* If popup isn't nil then it means the frame has that property
2156 and the value is supposed to be the parent frame. The FRAMEP
2157 check is to safeguard against it not being a frame. */
2158 if (!FRAMEP (popup) || !FRAME_LIVE_P (XFRAME (popup)))
2159 popup = Qt;
2160 else
2161 popup = Qnil;
2162 }
2163
2164 #ifdef EXTERNAL_WIDGET
2165 {
2166 Display *dpy = XtDisplay (w);
2167 expect_x_error (dpy);
2168 /* for obscure reasons having (I think) to do with the internal
2169 window-to-widget hierarchy maintained by Xt, we have to call
2170 XtUnrealizeWidget() here. Xt can really suck. */
2171 if (f->being_deleted)
2172 XtUnrealizeWidget (w);
2173 if (NILP (popup))
2174 XtDestroyWidget (w);
2175 x_error_occurred_p (dpy);
2176 }
2177 #else
2178 if (NILP (popup))
2179 XtDestroyWidget (w);
2180 #endif /* EXTERNAL_WIDGET */
2181
2182 if (FRAME_X_GEOM_FREE_ME_PLEASE (f))
2183 xfree (FRAME_X_GEOM_FREE_ME_PLEASE (f));
2184 xfree (f->frame_data);
2185 f->frame_data = 0;
2186 }
2187
2188
2189 /************************************************************************/
2190 /* initialization */
2191 /************************************************************************/
2192
2193 void
2194 syms_of_frame_x (void)
2195 {
2196 defsymbol (&Qwindow_id, "window-id");
2197 defsymbol (&Qpopup, "popup");
2198 defsymbol (&Qx_resource_name, "x-resource-name");
2199
2200 defsubr (&Sx_window_id);
2201 }
2202
2203 void
2204 console_type_create_frame_x (void)
2205 {
2206 /* frame methods */
2207 CONSOLE_HAS_METHOD (x, init_frame_1);
2208 CONSOLE_HAS_METHOD (x, init_frame_2);
2209 CONSOLE_HAS_METHOD (x, init_frame_3);
2210 CONSOLE_HAS_METHOD (x, mark_frame);
2211 CONSOLE_HAS_METHOD (x, focus_on_frame);
2212 CONSOLE_HAS_METHOD (x, delete_frame);
2213 CONSOLE_HAS_METHOD (x, get_mouse_position);
2214 CONSOLE_HAS_METHOD (x, set_mouse_position);
2215 CONSOLE_HAS_METHOD (x, raise_frame);
2216 CONSOLE_HAS_METHOD (x, lower_frame);
2217 CONSOLE_HAS_METHOD (x, make_frame_visible);
2218 CONSOLE_HAS_METHOD (x, make_frame_invisible);
2219 CONSOLE_HAS_METHOD (x, iconify_frame);
2220 CONSOLE_HAS_METHOD (x, set_frame_size);
2221 CONSOLE_HAS_METHOD (x, set_frame_position);
2222 CONSOLE_HAS_METHOD (x, frame_property);
2223 CONSOLE_HAS_METHOD (x, internal_frame_property_p);
2224 CONSOLE_HAS_METHOD (x, frame_properties);
2225 CONSOLE_HAS_METHOD (x, set_frame_properties);
2226 CONSOLE_HAS_METHOD (x, set_title_from_char);
2227 CONSOLE_HAS_METHOD (x, set_icon_name_from_char);
2228 CONSOLE_HAS_METHOD (x, frame_visible_p);
2229 CONSOLE_HAS_METHOD (x, frame_totally_visible_p);
2230 CONSOLE_HAS_METHOD (x, frame_iconified_p);
2231 CONSOLE_HAS_METHOD (x, set_frame_pointer);
2232 CONSOLE_HAS_METHOD (x, set_frame_icon);
2233 CONSOLE_HAS_METHOD (x, get_frame_parent);
2234 }
2235
2236 void
2237 vars_of_frame_x (void)
2238 {
2239 #ifdef EXTERNAL_WIDGET
2240 Fprovide (intern ("external-widget"));
2241 #endif
2242
2243 /* this call uses only safe functions from emacs.c */
2244 init_x_prop_symbols ();
2245
2246 DEFVAR_LISP ("default-x-frame-plist", &Vdefault_x_frame_plist /*
2247 Plist of default frame-creation properties for X frames.
2248 These override what is specified in the resource database and in
2249 `default-frame-plist', but are overridden by the arguments to the
2250 particular call to `make-frame'.
2251
2252 Note: In many cases, properties of a frame are available as specifiers
2253 instead of through the frame-properties mechanism.
2254
2255 Here is a list of recognized frame properties, other than those
2256 documented in `set-frame-properties' (they can be queried and
2257 set at any time, except as otherwise noted):
2258
2259 window-id The X window ID corresponding to the
2260 frame. May be set only at startup, and
2261 only if external widget support was
2262 compiled in; doing so causes the frame
2263 to be created as an \"external widget\"
2264 in another program that uses an existing
2265 window in the program rather than creating
2266 a new one.
2267 initially-unmapped If non-nil, the frame will not be visible
2268 when it is created. In this case, you
2269 need to call `make-frame-visible' to make
2270 the frame appear.
2271 popup If non-nil, it should be a frame, and this
2272 frame will be created as a \"popup\" frame
2273 whose parent is the given frame. This
2274 will make the window manager treat the
2275 frame as a dialog box, which may entail
2276 doing different things (e.g. not asking
2277 for positioning, and not iconifying
2278 separate from its parent).
2279 inter-line-space Not currently implemented.
2280 toolbar-shadow-thickness Thickness of toolbar shadows.
2281 background-toolbar-color Color of toolbar background.
2282 bottom-toolbar-shadow-color Color of bottom shadows on toolbars.
2283 (*Not* specific to the bottom-toolbar.)
2284 top-toolbar-shadow-color Color of top shadows on toolbars.
2285 (*Not* specifier to the top-toolbar.)
2286 internal-border-width Width of internal border around text area.
2287 border-width Width of external border around text area.
2288 top Y position (in pixels) of the upper-left
2289 outermost corner of the frame (i.e. the
2290 upper-left of the window-manager
2291 decorations).
2292 left X position (in pixels) of the upper-left
2293 outermost corner of the frame (i.e. the
2294 upper-left of the window-manager
2295 decorations).
2296 border-color Color of external border around text area.
2297 cursor-color Color of text cursor.
2298
2299 See also `default-frame-plist', which specifies properties which apply
2300 to all frames, not just X frames.
2301 */ );
2302 Vdefault_x_frame_plist = Qnil;
2303
2304 x_console_methods->device_specific_frame_props = &Vdefault_x_frame_plist;
2305 }