import -ko -b 1.1.3 XEmacs XEmacs-21_2 r21-2-35
[chise/xemacs-chise.git.1] / src / frame-msw.c
1 /* Functions for the mswindows 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 /* Authorship:
25
26    Ultimately based on FSF.
27    Substantially rewritten for XEmacs by Ben Wing.
28    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
29    Graphics features added and frame resizing fiddled with by Andy Piper.
30  */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "buffer.h"
36 #include "elhash.h"
37 #include "console-msw.h"
38 #include "glyphs-msw.h"
39 #include "elhash.h"
40 #include "events.h"
41 #include "faces.h"
42 #include "frame.h"
43 #include "redisplay.h"
44 #include "window.h"
45
46 #define MSWINDOWS_FRAME_STYLE (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW)
47 #define MSWINDOWS_POPUP_STYLE (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP \
48                                | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX)
49
50 #define MSWINDOWS_FRAME_EXSTYLE WS_EX_OVERLAPPEDWINDOW
51 #define MSWINDOWS_POPUP_EXSTYLE WS_EX_PALETTEWINDOW
52
53 /* Default popup left top corner offset from the same
54    corner of the parent frame, in pixel */
55 #define POPUP_OFFSET 30
56
57 /* Default popup size, in characters */
58 #define POPUP_WIDTH 30
59 #define POPUP_HEIGHT 10
60
61 /* Default regular frame size, in characters */
62 #define DEFAULT_FRAME_WIDTH 80
63 #define DEFAULT_FRAME_HEIGHT 35
64
65 #ifdef HAVE_MENUBARS
66 #define ADJR_MENUFLAG TRUE
67 #else
68 #define ADJR_MENUFLAG FALSE
69 #endif
70
71 /* Default properties to use when creating frames.  */
72 Lisp_Object Vdefault_mswindows_frame_plist;
73 Lisp_Object Vdefault_msprinter_frame_plist;
74 Lisp_Object Vmswindows_use_system_frame_size_defaults;
75
76 /* This does not need to be GC protected, as it holds a
77    frame Lisp_Object already protected by Fmake_frame */
78 Lisp_Object Vmswindows_frame_being_created;
79
80 /*---------------------------------------------------------------------*/
81 /*-----                    DISPLAY FRAME                          -----*/
82 /*---------------------------------------------------------------------*/
83
84 HWND
85 mswindows_get_selected_frame_hwnd (void)
86 {
87   Lisp_Object frame, device;
88
89   device = Ffind_device (Qnil, Qmswindows);
90   if (NILP (device))
91     return NULL;
92   frame = DEVICE_SELECTED_FRAME (XDEVICE (device));
93   if (NILP (frame))
94     return NULL;
95
96   return FRAME_MSWINDOWS_HANDLE (XFRAME (frame));
97 }
98
99 static void
100 mswindows_init_frame_1 (struct frame *f, Lisp_Object props)
101 {
102   Lisp_Object initially_unmapped;
103   Lisp_Object name, height, width, popup, top, left;
104   Lisp_Object frame_obj = Qnil;
105   RECT rect;
106   XEMACS_RECT_WH rect_default;
107   DWORD style, exstyle;
108   HWND hwnd, hwnd_parent;
109
110   /* Pick up relevant properties */
111   initially_unmapped = Fplist_get (props, Qinitially_unmapped, Qnil);
112   name = Fplist_get (props, Qname, Qnil);
113   
114   popup = Fplist_get (props, Qpopup, Qnil);
115   if (EQ (popup, Qt))
116     popup = Fselected_frame (Qnil);
117
118   left = Fplist_get (props, Qleft, Qnil);
119   if (!NILP (left))
120     CHECK_INT (left);
121
122   top = Fplist_get (props, Qtop, Qnil);
123   if (!NILP (top))
124     CHECK_INT (top);
125
126   width = Fplist_get (props, Qwidth, Qnil);
127   if (!NILP (width))
128     CHECK_INT (width);
129
130   height = Fplist_get (props, Qheight, Qnil);
131   if (!NILP (height))
132     CHECK_INT (height);
133
134   f->frame_data = xnew_and_zero (struct mswindows_frame);
135   FRAME_MSWINDOWS_TARGET_RECT (f) = xnew_and_zero (XEMACS_RECT_WH);
136
137   FRAME_MSWINDOWS_TARGET_RECT (f)->left = NILP (left) ? -1 : abs (XINT (left));
138   FRAME_MSWINDOWS_TARGET_RECT (f)->top = NILP (top) ? -1 : abs (XINT (top));
139   FRAME_MSWINDOWS_TARGET_RECT (f)->width = NILP (width) ? -1 : 
140     abs (XINT (width));
141   FRAME_MSWINDOWS_TARGET_RECT (f)->height = NILP (height) ? -1 : 
142     abs (XINT (height));
143       
144   /* Misc frame stuff */
145   FRAME_MSWINDOWS_MENU_HASH_TABLE(f) = Qnil;
146 #ifdef HAVE_TOOLBARS
147   FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE(f) = 
148     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
149 #endif
150   /* hashtable of instantiated glyphs on the frame. */
151   FRAME_MSWINDOWS_WIDGET_HASH_TABLE1 (f) = 
152     make_lisp_hash_table (50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQUAL);
153   FRAME_MSWINDOWS_WIDGET_HASH_TABLE2 (f) = 
154     make_lisp_hash_table (50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQUAL);
155   FRAME_MSWINDOWS_WIDGET_HASH_TABLE3 (f) = 
156     make_lisp_hash_table (50, HASH_TABLE_VALUE_WEAK, HASH_TABLE_EQUAL);
157   /* Will initialize these in WM_SIZE handler. We cannot do it now,
158      because we do not know what is CW_USEDEFAULT height and width */
159   FRAME_WIDTH (f) = 0;
160   FRAME_HEIGHT (f) = 0;
161   FRAME_PIXWIDTH (f) = 0;
162   FRAME_PIXHEIGHT (f) = 0;
163
164   if (NILP (popup))
165     {
166       style = MSWINDOWS_FRAME_STYLE;
167       exstyle = MSWINDOWS_FRAME_EXSTYLE;
168       hwnd_parent = NULL;
169
170       rect_default.left = rect_default.top = CW_USEDEFAULT;
171       rect_default.width = rect_default.height = CW_USEDEFAULT;
172     }
173   else
174     {
175       style = MSWINDOWS_POPUP_STYLE;
176       exstyle = MSWINDOWS_POPUP_EXSTYLE;
177
178       CHECK_MSWINDOWS_FRAME (popup);
179       hwnd_parent = FRAME_MSWINDOWS_HANDLE (XFRAME (popup));
180       assert (IsWindow (hwnd_parent));
181
182       /* We cannot use CW_USEDEFAULT when creating a popup window.
183          So by default, we offset the new popup 30 pixels right
184          and down from its parent, and give it size of 30x10 characters.
185          These dimensions look adequate on both high and low res monitors */
186       GetWindowRect (hwnd_parent, &rect);
187       rect_default.left = rect.left + POPUP_OFFSET;
188       rect_default.top = rect.top + POPUP_OFFSET;
189       char_to_real_pixel_size (f, POPUP_WIDTH, POPUP_HEIGHT,
190                                &rect_default.width, &rect_default.height);
191     }
192
193   AdjustWindowRectEx(&rect, style, ADJR_MENUFLAG, exstyle);
194
195   XSETFRAME (frame_obj, f);
196
197   Vmswindows_frame_being_created = frame_obj;
198
199   hwnd = CreateWindowEx (exstyle,
200                          XEMACS_CLASS,
201                          STRINGP(f->name) ? XSTRING_DATA(f->name) :
202                          (STRINGP(name) ? 
203                           (const Extbyte*)XSTRING_DATA(name) : 
204                           (const Extbyte*)XEMACS_CLASS),
205                          style,
206                          rect_default.left, rect_default.top,
207                          rect_default.width, rect_default.height,
208                          hwnd_parent, NULL, NULL, NULL);
209
210   Vmswindows_frame_being_created = Qnil;
211
212   if (hwnd == NULL)
213     error ("System call to create frame failed");
214                            
215   FRAME_MSWINDOWS_HANDLE(f) = hwnd;
216
217   SetWindowLong (hwnd, XWL_FRAMEOBJ, (LONG)LISP_TO_VOID(frame_obj));
218   FRAME_MSWINDOWS_DC(f) = GetDC (hwnd);
219   SetTextAlign (FRAME_MSWINDOWS_DC(f), TA_BASELINE | TA_LEFT | TA_NOUPDATECP);
220 }
221
222 static void
223 mswindows_init_frame_2 (struct frame *f, Lisp_Object props)
224 {
225   if (NILP (Vmswindows_use_system_frame_size_defaults))
226     {
227       /* I don't think anything can set the frame size before this
228          since we don't have X resources. This may change if we look
229          at the registry. Even so these values can get overridden
230          later.*/
231       XEMACS_RECT_WH dest = { -1, -1, DEFAULT_FRAME_WIDTH, 
232                               DEFAULT_FRAME_HEIGHT };
233       mswindows_size_frame_internal (f, &dest);
234     }
235 }
236
237 /* Called after frame's properties are set */
238 static void
239 mswindows_init_frame_3 (struct frame *f)
240 {
241   /* Don't do this earlier or we get a WM_PAINT before the frame is ready.
242    * The SW_x parameter in the first call that an app makes to ShowWindow is
243    * ignored, and the parameter specified in the caller's STARTUPINFO is 
244    * substituted instead. That parameter is SW_HIDE if we were started by
245    * runemacs, so call this twice. #### runemacs is evil */
246   ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_SHOWNORMAL);
247   ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_SHOWNORMAL);
248   SetForegroundWindow (FRAME_MSWINDOWS_HANDLE(f));
249   DragAcceptFiles (FRAME_MSWINDOWS_HANDLE(f), TRUE);
250 }
251
252 static void
253 mswindows_after_init_frame (struct frame *f, int first_on_device,
254                             int first_on_console)
255 {
256   /* Windows, unlike X, is very synchronous. After the initial
257      frame is created, it will never be displayed, except for 
258      hollow border, unless we start pumping messages. Load progress
259      messages show in the bottom of the hollow frame, which is ugly.
260      We redisplay the initial frame here, so modeline and root window
261      background show.
262   */
263   if (first_on_console)
264     redisplay ();
265 }
266
267 static void
268 mswindows_mark_frame (struct frame *f)
269 {
270   mark_object (FRAME_MSWINDOWS_MENU_HASH_TABLE (f));
271 #ifdef HAVE_TOOLBARS
272   mark_object (FRAME_MSWINDOWS_TOOLBAR_HASH_TABLE (f));
273 #endif
274   mark_object (FRAME_MSWINDOWS_WIDGET_HASH_TABLE1 (f));
275   mark_object (FRAME_MSWINDOWS_WIDGET_HASH_TABLE2 (f));
276   mark_object (FRAME_MSWINDOWS_WIDGET_HASH_TABLE3 (f));
277 }
278
279 static void
280 mswindows_focus_on_frame (struct frame *f)
281 {
282   SetForegroundWindow (FRAME_MSWINDOWS_HANDLE(f));
283 }
284
285 static void
286 mswindows_delete_frame (struct frame *f)
287 {
288   if (f->frame_data)
289     {
290       ReleaseDC(FRAME_MSWINDOWS_HANDLE(f), FRAME_MSWINDOWS_DC(f));
291       DestroyWindow(FRAME_MSWINDOWS_HANDLE(f));
292       xfree (f->frame_data);
293     }
294   f->frame_data = 0;
295 }
296
297 static void
298 mswindows_set_frame_size (struct frame *f, int width, int height)
299 {
300   RECT rect;
301   rect.left = rect.top = 0;
302   rect.right = width;
303   rect.bottom = height;
304
305   AdjustWindowRectEx (&rect,
306                       GetWindowLong (FRAME_MSWINDOWS_HANDLE(f), GWL_STYLE),
307                       GetMenu (FRAME_MSWINDOWS_HANDLE(f)) != NULL,
308                       GetWindowLong (FRAME_MSWINDOWS_HANDLE(f), GWL_EXSTYLE));
309
310   if (IsIconic (FRAME_MSWINDOWS_HANDLE(f)) || IsZoomed (FRAME_MSWINDOWS_HANDLE(f)))
311     ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_RESTORE);
312
313   SetWindowPos (FRAME_MSWINDOWS_HANDLE(f), NULL, 
314                 0, 0, rect.right-rect.left, rect.bottom-rect.top,
315                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOMOVE);
316 }
317
318 static void
319 mswindows_set_frame_position (struct frame *f, int xoff, int yoff)
320 {
321   SetWindowPos (FRAME_MSWINDOWS_HANDLE(f), NULL, 
322                 xoff, yoff, 0, 0,
323                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE);
324 }
325
326 static void
327 mswindows_make_frame_visible (struct frame *f) 
328 {
329   if (!FRAME_VISIBLE_P(f))
330     ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_RESTORE);
331   else
332     ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_SHOW);
333   f->visible = 1;
334   f->iconified = 0;
335 }
336
337 static void
338 mswindows_make_frame_invisible (struct frame *f) 
339 {
340   if (!FRAME_VISIBLE_P(f))
341     return;
342
343   ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_HIDE);
344   f->visible = 0;
345 }
346
347 static int
348 mswindows_frame_totally_visible_p (struct frame *f)
349 {
350   RECT rc_me, rc_other, rc_temp;
351   HWND hwnd = FRAME_MSWINDOWS_HANDLE(f);
352
353   /* We test against not a whole window rectangle, only against its
354      client part. So, if non-client are is covered and client area is
355      not, we return true. */
356   GetClientRect (hwnd, &rc_me);
357   MapWindowPoints (hwnd, HWND_DESKTOP, (LPPOINT)&rc_me, 2);
358
359   /* First see if we're off the desktop */
360   GetWindowRect (GetDesktopWindow(), &rc_other);
361   UnionRect(&rc_temp, &rc_me, &rc_other);
362   if (!EqualRect (&rc_temp, &rc_other))
363     return 0;
364   
365   /* Then see if any window above us obscures us */
366   while ((hwnd = GetWindow (hwnd, GW_HWNDPREV)) != NULL)
367     if (IsWindowVisible (hwnd))
368       {
369         GetWindowRect (hwnd, &rc_other);
370         if (IntersectRect(&rc_temp, &rc_me, &rc_other))
371           return 0;
372       }
373
374   return 1;
375 }
376
377 static int
378 mswindows_frame_visible_p (struct frame *f)
379 {
380   return IsWindowVisible (FRAME_MSWINDOWS_HANDLE(f))
381     && !IsIconic (FRAME_MSWINDOWS_HANDLE(f));
382 }
383
384
385 static void
386 mswindows_iconify_frame (struct frame *f)
387 {
388   ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_MINIMIZE);
389   f->visible = 0;
390   f->iconified = 1;
391 }
392
393 static int
394 mswindows_frame_iconified_p (struct frame *f)
395 {
396   return IsIconic (FRAME_MSWINDOWS_HANDLE(f));
397 }
398
399 static void
400 mswindows_set_frame_icon (struct frame *f)
401 {
402   if (IMAGE_INSTANCEP (f->icon)
403       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (f->icon)))
404     {
405       if (!XIMAGE_INSTANCE_MSWINDOWS_ICON (f->icon))
406         {
407           mswindows_initialize_image_instance_icon (XIMAGE_INSTANCE (f->icon), 
408                                                     FALSE);
409         }
410       
411       SetClassLong (FRAME_MSWINDOWS_HANDLE (f), GCL_HICON, 
412                     (LONG) XIMAGE_INSTANCE_MSWINDOWS_ICON (f->icon));
413     }
414 }
415
416 static void
417 mswindows_set_frame_pointer (struct frame *f)
418 {
419   if (IMAGE_INSTANCEP (f->pointer)
420       && IMAGE_INSTANCE_TYPE (XIMAGE_INSTANCE (f->pointer)) == IMAGE_POINTER)
421     {
422       SetClassLong (FRAME_MSWINDOWS_HANDLE (f), GCL_HCURSOR,
423                     (LONG) XIMAGE_INSTANCE_MSWINDOWS_ICON (f->pointer));
424       /* we only have to do this because GC doesn't cause a mouse
425          event and doesn't give time to event processing even if it
426          did. */
427       SetCursor (XIMAGE_INSTANCE_MSWINDOWS_ICON (f->pointer));
428     }
429 }
430
431 static void
432 mswindows_set_mouse_position (struct window *w, int x, int y)
433 {
434   struct frame *f = XFRAME (w->frame);
435   POINT pt;
436
437   pt.x = w->pixel_left + x;
438   pt.y = w->pixel_top  + y;
439   ClientToScreen (FRAME_MSWINDOWS_HANDLE(f), &pt);
440   SetCursorPos (pt.x, pt.y);
441 }
442
443 static int
444 mswindows_get_mouse_position (struct device *d, Lisp_Object *frame, int *x, int *y)
445 {
446   POINT pt;
447   HWND hwnd;
448
449   GetCursorPos (&pt);
450
451   /* What's under cursor? */
452   hwnd = WindowFromPoint (pt);
453   if (hwnd == NULL)
454     return 0;
455
456   /* Get grandest parent of the window */
457   {
458     HWND hwnd_parent;
459     while ((hwnd_parent = GetParent (hwnd)) != NULL)
460       hwnd = hwnd_parent;
461   }
462
463   /* Make sure it belongs to us */
464   if (GetWindowThreadProcessId (hwnd, NULL) != GetCurrentThreadId ())
465     return 0;
466
467   /* And that the window is an XEmacs frame */
468   {
469     char class_name [sizeof(XEMACS_CLASS) + 1];
470     if (!GetClassName (hwnd, class_name, sizeof(XEMACS_CLASS))
471         || strcmp (class_name, XEMACS_CLASS) != 0)
472       return 0;
473   }
474
475   /* Yippie! */
476   ScreenToClient (hwnd, &pt);
477   VOID_TO_LISP (*frame, GetWindowLong (hwnd, XWL_FRAMEOBJ));
478   *x = pt.x;
479   *y = pt.y;
480   return 1;
481 }
482
483 static void
484 mswindows_raise_frame (struct frame *f)
485 {
486   BringWindowToTop (FRAME_MSWINDOWS_HANDLE(f));
487 }
488
489 static void
490 mswindows_lower_frame (struct frame *f)
491 {
492   SetWindowPos (FRAME_MSWINDOWS_HANDLE(f), HWND_BOTTOM, 0, 0, 0, 0,
493                 SWP_NOSIZE | SWP_NOMOVE | SWP_NOSENDCHANGING);
494 }
495
496 static void
497 mswindows_set_title_from_bufbyte (struct frame *f, Bufbyte *title) 
498 {
499   unsigned int new_checksum = hash_string (title, strlen (title));
500   if (new_checksum != FRAME_MSWINDOWS_TITLE_CHECKSUM(f))
501     {
502       FRAME_MSWINDOWS_TITLE_CHECKSUM(f) = new_checksum;
503       SetWindowText (FRAME_MSWINDOWS_HANDLE(f), title);
504     }
505 }
506
507 static Lisp_Object
508 mswindows_frame_property (struct frame *f, Lisp_Object property)
509 {
510   if (EQ (Qleft, property) || EQ (Qtop, property))
511     {
512       RECT rc;
513       GetWindowRect (FRAME_MSWINDOWS_HANDLE(f), &rc);
514       return make_int (EQ (Qtop,  property) ? rc.top : rc.left);
515     }
516   return Qunbound;
517 }
518
519 static int
520 mswindows_internal_frame_property_p (struct frame *f, Lisp_Object property)
521 {
522   return EQ (property, Qleft)
523     || EQ (property, Qtop);
524   /* #### frame-x.c has also this. Why?
525     || STRINGP (property);
526   */
527 }
528
529 static Lisp_Object
530 mswindows_frame_properties (struct frame *f)
531 {
532   Lisp_Object props = Qnil;
533   RECT rc;
534   GetWindowRect (FRAME_MSWINDOWS_HANDLE(f), &rc);
535
536   props = cons3 (Qtop,  make_int (rc.top), props);
537   props = cons3 (Qleft, make_int (rc.left), props);
538
539   return props;
540 }
541
542 static void
543 mswindows_set_frame_properties (struct frame *f, Lisp_Object plist)
544 {
545   int x=-1, y=-1;
546   int width = -1, height = -1;
547   BOOL width_specified_p = FALSE;
548   BOOL height_specified_p = FALSE;
549   BOOL x_specified_p = FALSE;
550   BOOL y_specified_p = FALSE;
551   Lisp_Object tail;
552
553   /* Extract the properties from plist */
554   for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
555     {
556       Lisp_Object prop = Fcar (tail);
557       Lisp_Object val = Fcar (Fcdr (tail));
558
559       if (SYMBOLP (prop))
560         {
561           /* Kludge to handle the font property. */
562           if (EQ (prop, Qfont))
563             {
564               /* If the value is not a string we silently ignore it. */
565               if (STRINGP (val))
566                 {
567                   Lisp_Object frm, font_spec;
568                   
569                   XSETFRAME (frm, f);
570                   font_spec = Fget (Fget_face (Qdefault), Qfont, Qnil);
571
572                   Fadd_spec_to_specifier (font_spec, val, frm, Qnil, Qnil);
573                   update_frame_face_values (f);
574                 }
575             }
576           else if (EQ (prop, Qwidth))
577             {
578               CHECK_INT (val);
579               width = XINT (val);
580               width_specified_p = TRUE;
581             }
582           else if (EQ (prop, Qheight))
583             {
584               CHECK_INT (val);
585               height = XINT (val);
586               height_specified_p = TRUE;
587             }
588           else if (EQ (prop, Qleft))
589             {
590               CHECK_INT (val);
591               x = XINT (val);
592               x_specified_p = TRUE;
593             }
594           else if (EQ (prop, Qtop))
595             {
596               CHECK_INT (val);
597               y = XINT (val);
598               y_specified_p = TRUE;
599             }
600         }
601     }
602
603   /* Now we've extracted the properties, apply them.
604      Do not apply geometric properties during frame creation. This
605      is excessive anyways, and this loses becuase WM_SIZE has not
606      been sent yet, so frame width and height fields are not initialized.
607      
608      unfortunately WM_SIZE loses as well since the resize is only
609      applied once and the first time WM_SIZE is applied not everything
610      is initialised in the frame (toolbars for instance). enabling
611      this always makes no visible difference and fixes a whole host of
612      bugs (and is more consistent with X) so I am going to reenable it.
613      --andyp */
614   if ( FRAME_PIXWIDTH (f) && FRAME_PIXHEIGHT (f)
615        && (width_specified_p || height_specified_p
616            || x_specified_p || y_specified_p))
617     {
618       XEMACS_RECT_WH dest = { x, y, width, height };
619
620       mswindows_size_frame_internal (f, &dest);
621     }
622 }
623
624 void mswindows_size_frame_internal (struct frame* f, XEMACS_RECT_WH* dest)
625 {
626   RECT rect, ws_rect;
627   int pixel_width, pixel_height;
628   int size_p = (dest->width >=0 || dest->height >=0);
629   int move_p = (dest->top >=0 || dest->left >=0);
630   char_to_real_pixel_size (f, dest->width, dest->height, &pixel_width, &pixel_height);
631   
632   if (dest->width < 0)
633     pixel_width = FRAME_PIXWIDTH (f);
634   if (dest->height < 0)
635     pixel_height = FRAME_PIXHEIGHT (f);
636
637   GetWindowRect (FRAME_MSWINDOWS_HANDLE(f), &rect);
638   if (dest->left < 0)
639     dest->left = rect.left;
640   if (dest->top < 0)
641     dest->top = rect.top;
642   
643   rect.left = rect.top = 0;
644   rect.right = pixel_width;
645   rect.bottom = pixel_height;
646
647   AdjustWindowRectEx (&rect,
648                       GetWindowLong (FRAME_MSWINDOWS_HANDLE(f), GWL_STYLE),
649                       GetMenu (FRAME_MSWINDOWS_HANDLE(f)) != NULL,
650                       GetWindowLong (FRAME_MSWINDOWS_HANDLE(f), GWL_EXSTYLE));
651
652   /* resize and move the window so that it fits in the workspace. This is
653   not restrictive since this will happen later anyway in WM_SIZE.  We
654   have to do this after adjusting the rect to account for menubar
655   etc. */
656   mswindows_get_workspace_coords (&ws_rect);
657   pixel_width = rect.right - rect.left;
658   pixel_height = rect.bottom - rect.top;
659   if (pixel_width > ws_rect.right - ws_rect.left)
660     {
661       pixel_width = ws_rect.right - ws_rect.left;
662       size_p=1;
663     }
664   if (pixel_height > ws_rect.bottom - ws_rect.top)
665     {
666       pixel_height = ws_rect.bottom - ws_rect.top;
667       size_p=1;
668     }
669
670   /* adjust position so window is in workspace */
671   if (dest->left + pixel_width > ws_rect.right)
672     {
673       dest->left = ws_rect.right - pixel_width;
674       move_p=1;
675     }
676   if (dest->left < ws_rect.left)
677     {
678       dest->left = ws_rect.left;
679       move_p=1;
680     }
681
682   if (dest->top + pixel_height > ws_rect.bottom)
683     {
684       dest->top = ws_rect.bottom - pixel_height;
685       move_p=1;
686     }
687   if (dest->top < ws_rect.top)
688     {
689       dest->top = ws_rect.top;
690       move_p=1;
691     }
692
693   if (IsIconic (FRAME_MSWINDOWS_HANDLE(f)) 
694       || IsZoomed (FRAME_MSWINDOWS_HANDLE(f)))
695     ShowWindow (FRAME_MSWINDOWS_HANDLE(f), SW_RESTORE);
696
697   SetWindowPos (FRAME_MSWINDOWS_HANDLE(f), NULL, 
698                 dest->left, dest->top, pixel_width, pixel_height,
699                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING
700                 | (size_p ? 0 : SWP_NOSIZE)
701                 | (move_p ? 0 : SWP_NOMOVE));
702 }
703
704 static Lisp_Object
705 mswindows_get_frame_parent (struct frame *f)
706 {
707   HWND hwnd = FRAME_MSWINDOWS_HANDLE(f);
708   hwnd = GetParent (hwnd);
709   if (hwnd)
710     {
711       Lisp_Object parent;
712       VOID_TO_LISP (parent, GetWindowLong (hwnd, XWL_FRAMEOBJ));
713       assert (FRAME_MSWINDOWS_P (XFRAME (parent)));
714       return parent;
715     }
716   else
717     return Qnil;
718 }
719
720 static void
721 mswindows_update_frame_external_traits (struct frame* frm, Lisp_Object name)
722 {
723 }
724
725 static int
726 mswindows_frame_size_fixed_p (struct frame *f)
727 {
728   /* Frame size cannot change if the frame is maximized */
729   return IsZoomed (FRAME_MSWINDOWS_HANDLE (f));
730 }
731
732 /*---------------------------------------------------------------------*/
733 /*-----                    PRINTER FRAME                          -----*/
734 /*---------------------------------------------------------------------*/
735
736 /*
737  * With some drvier/os combination (I discovered this with HP drviers
738  * under W2K), DC geometry is reset upon StartDoc and EndPage
739  * calls. This is called every time one of these calls is made.
740  */
741 static void
742 apply_dc_geometry (struct frame* f)
743 {
744   HDC hdc = DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f)));
745   SetTextAlign (hdc, TA_BASELINE | TA_LEFT | TA_NOUPDATECP);
746   SetViewportOrgEx (hdc, FRAME_MSPRINTER_PIXLEFT(f),
747                     FRAME_MSPRINTER_PIXTOP(f), NULL);
748 }
749
750 void
751 msprinter_start_page (struct frame *f)
752 {
753   if (!FRAME_MSPRINTER_PAGE_STARTED (f))
754     {
755       FRAME_MSPRINTER_PAGE_STARTED (f) = 1;
756       StartPage (DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f))));
757       apply_dc_geometry (f);
758     }
759 }
760
761 static void
762 error_frame_unsizable (struct frame *f)
763 {
764   Lisp_Object frame;
765   XSETFRAME (frame, f);
766   signal_simple_error ("Cannot resize frame (margins)"
767                        " after print job has started.", frame);
768 }
769
770 static void
771 maybe_error_if_job_active (struct frame *f)
772 {
773   if (FRAME_MSPRINTER_JOB_STARTED (f))
774     error_frame_unsizable (f);
775 }
776
777 static void
778 msprinter_init_frame_1 (struct frame *f, Lisp_Object props)
779 {
780   /* Make sure this is the only frame on device. Windows printer can
781      handle only one job at a time. */
782   if (!NILP (DEVICE_FRAME_LIST (XDEVICE (FRAME_DEVICE (f)))))
783     error ("Only one frame (print job) at a time is allowed on "
784            "this printer device.");
785
786   f->frame_data = xnew_and_zero (struct msprinter_frame);
787
788   /* Default margin size is 1" = 1440 twips */
789   FRAME_MSPRINTER_TOP_MARGIN(f) = 1440;
790   FRAME_MSPRINTER_BOTTOM_MARGIN(f) = 1440;
791   FRAME_MSPRINTER_LEFT_MARGIN(f) = 1440;
792   FRAME_MSPRINTER_RIGHT_MARGIN(f) = 1440;
793
794   /* Negative for "uinspecified" */
795   FRAME_MSPRINTER_CHARWIDTH(f) = -1;
796   FRAME_MSPRINTER_CHARHEIGHT(f) = -1;
797 }
798
799 static void
800 msprinter_init_frame_3 (struct frame *f)
801 {
802   DOCINFO di;
803   struct device *device = XDEVICE (FRAME_DEVICE (f));
804   HDC hdc;
805   int frame_left, frame_top, frame_width, frame_height;
806
807   /* DC might be recreated in msprinter_apply_devmode,
808      so do not initialize until now */
809   hdc = DEVICE_MSPRINTER_HDC (device);
810
811   /* Compute geometry properties */
812   frame_left = (MulDiv (GetDeviceCaps (hdc, LOGPIXELSX),
813                         FRAME_MSPRINTER_LEFT_MARGIN(f), 1440)
814                 - GetDeviceCaps (hdc, PHYSICALOFFSETX));
815   
816   if (FRAME_MSPRINTER_CHARWIDTH(f) > 0)
817     {
818       char_to_real_pixel_size (f, FRAME_MSPRINTER_CHARWIDTH(f), 0,
819                                &frame_width, NULL);
820       FRAME_MSPRINTER_RIGHT_MARGIN(f) = 
821         MulDiv (GetDeviceCaps (hdc, PHYSICALWIDTH)
822                 - (frame_left + frame_width), 1440,
823                 GetDeviceCaps (hdc, LOGPIXELSX));
824     }           
825   else
826     frame_width = (GetDeviceCaps (hdc, PHYSICALWIDTH)
827                    - frame_left
828                    - MulDiv (GetDeviceCaps (hdc, LOGPIXELSX),
829                              FRAME_MSPRINTER_RIGHT_MARGIN(f), 1440));
830
831   frame_top = (MulDiv (GetDeviceCaps (hdc, LOGPIXELSY),
832                        FRAME_MSPRINTER_TOP_MARGIN(f), 1440)
833                - GetDeviceCaps (hdc, PHYSICALOFFSETY));
834
835   if (FRAME_MSPRINTER_CHARHEIGHT(f) > 0)
836     {
837       char_to_real_pixel_size (f, 0, FRAME_MSPRINTER_CHARHEIGHT(f),
838                                NULL, &frame_height);
839
840       FRAME_MSPRINTER_BOTTOM_MARGIN(f) = 
841         MulDiv (GetDeviceCaps (hdc, PHYSICALHEIGHT)
842                 - (frame_top + frame_height), 1440,
843                 GetDeviceCaps (hdc, LOGPIXELSY));
844     }           
845   else
846     frame_height = (GetDeviceCaps (hdc, PHYSICALHEIGHT)
847                     - frame_top
848                     - MulDiv (GetDeviceCaps (hdc, LOGPIXELSY),
849                               FRAME_MSPRINTER_BOTTOM_MARGIN(f), 1440));
850
851   /* Geometry sanity checks */
852   if (!frame_pixsize_valid_p (f, frame_width, frame_height))
853     error ("Area inside print margins has shrunk to naught.");
854
855   if (frame_left < 0
856       || frame_top < 0
857       || frame_left + frame_width > GetDeviceCaps (hdc, HORZRES)
858       || frame_top + frame_height > GetDeviceCaps (hdc, VERTRES))
859     error ("Print area is ouside of the printer's hardware printable area.");
860
861   /* Apply XEmacs frame geometry and layout windows */
862   {
863     int rows, columns;
864     FRAME_PIXWIDTH(f) = frame_width;
865     FRAME_PIXHEIGHT(f) = frame_height;
866     pixel_to_char_size (f, frame_width, frame_height, &columns, &rows);
867     change_frame_size (f, rows, columns, 0);
868   }
869
870   FRAME_MSPRINTER_PIXLEFT(f) = frame_left;
871   FRAME_MSPRINTER_PIXTOP(f) = frame_top;
872
873   /* Start print job */
874   di.cbSize = sizeof (di);
875   di.lpszDocName = (STRINGP(f->name)
876                     ? (char*) XSTRING_DATA(f->name)
877                     : "XEmacs print document");
878   di.lpszOutput = NULL;
879   di.lpszDatatype = NULL;
880   di.fwType = 0;
881
882   if (StartDoc (hdc, &di) <= 0)
883     error ("Cannot start print job");
884
885   apply_dc_geometry (f);
886
887   /* Finish frame setup */
888   FRAME_MSPRINTER_JOB_STARTED (f) = 1;
889   FRAME_VISIBLE_P(f) = 0;
890 }
891
892 static void
893 msprinter_mark_frame (struct frame *f)
894 {
895 }
896
897 static void
898 msprinter_delete_frame (struct frame *f)
899 {
900   if (f->frame_data)
901     {
902       HDC hdc = DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f)));
903       if (FRAME_MSPRINTER_PAGE_STARTED (f))
904         EndPage (hdc);
905       if (FRAME_MSPRINTER_JOB_STARTED (f))
906         EndDoc (hdc);
907       xfree (f->frame_data);
908     }
909
910   f->frame_data = 0;
911 }
912
913 static Lisp_Object
914 msprinter_frame_property (struct frame *f, Lisp_Object property)
915 {
916   if (EQ (Qleft_margin, property))
917     return make_int (FRAME_MSPRINTER_LEFT_MARGIN(f));
918   else if (EQ (Qtop_margin, property))
919     return make_int (FRAME_MSPRINTER_TOP_MARGIN(f));
920   if (EQ (Qright_margin, property))
921     return make_int (FRAME_MSPRINTER_RIGHT_MARGIN(f));
922   else if (EQ (Qbottom_margin, property))
923     return make_int (FRAME_MSPRINTER_BOTTOM_MARGIN(f));
924   else
925     return Qunbound;
926 }
927
928 static int
929 msprinter_internal_frame_property_p (struct frame *f, Lisp_Object property)
930 {
931   return (EQ (Qleft_margin, property) || EQ (Qtop_margin, property) ||
932           EQ (Qright_margin, property) || EQ (Qbottom_margin, property));
933 }
934
935 static Lisp_Object
936 msprinter_frame_properties (struct frame *f)
937 {
938   Lisp_Object props = Qnil;
939   props = cons3 (Qbottom_margin,
940                  make_int (FRAME_MSPRINTER_BOTTOM_MARGIN(f)), props);
941   props = cons3 (Qright_margin,
942                  make_int (FRAME_MSPRINTER_RIGHT_MARGIN(f)), props);
943   props = cons3 (Qtop_margin,
944                  make_int (FRAME_MSPRINTER_TOP_MARGIN(f)), props);
945   props = cons3 (Qleft_margin,
946                  make_int (FRAME_MSPRINTER_LEFT_MARGIN(f)), props);
947   return props;
948 }
949
950 static void
951 msprinter_set_frame_properties (struct frame *f, Lisp_Object plist)
952 {
953   Lisp_Object tail;
954
955   /* Extract the properties from plist */
956   for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
957     {
958       Lisp_Object prop = Fcar (tail);
959       Lisp_Object val = Fcar (Fcdr (tail));
960
961       if (SYMBOLP (prop))
962         {
963           if (EQ (prop, Qwidth))
964             {
965               maybe_error_if_job_active (f);
966               if (!NILP (val))
967                 {
968                   CHECK_NATNUM (val);
969                   FRAME_MSPRINTER_CHARWIDTH(f) = XINT (val);
970                 }
971             }
972           if (EQ (prop, Qheight))
973             {
974               maybe_error_if_job_active (f);
975               if (!NILP (val))
976                 {
977                   CHECK_NATNUM (val);
978                   FRAME_MSPRINTER_CHARHEIGHT(f) = XINT (val);
979                 }
980             }
981           else if (EQ (prop, Qleft_margin))
982             {
983               maybe_error_if_job_active (f);
984               CHECK_NATNUM (val);
985               FRAME_MSPRINTER_LEFT_MARGIN(f) = XINT (val);
986             }
987           else if (EQ (prop, Qtop_margin))
988             {
989               maybe_error_if_job_active (f);
990               CHECK_NATNUM (val);
991               FRAME_MSPRINTER_TOP_MARGIN(f) = XINT (val);
992             }
993           else if (EQ (prop, Qright_margin))
994             {
995               maybe_error_if_job_active (f);
996               CHECK_NATNUM (val);
997               FRAME_MSPRINTER_RIGHT_MARGIN(f) = XINT (val);
998             }
999           else if (EQ (prop, Qbottom_margin))
1000             {
1001               maybe_error_if_job_active (f);
1002               CHECK_NATNUM (val);
1003               FRAME_MSPRINTER_BOTTOM_MARGIN(f) = XINT (val);
1004             }
1005         }
1006     }
1007 }
1008
1009 static void
1010 msprinter_set_frame_size (struct frame *f, int width, int height)
1011 {
1012   /* We're absolutely unsizeable */
1013   error_frame_unsizable (f);
1014 }
1015
1016 static void
1017 msprinter_eject_page (struct frame *f)
1018 {
1019   /* #### Should we eject empty pages? */
1020   if (FRAME_MSPRINTER_PAGE_STARTED (f))
1021     {
1022       FRAME_MSPRINTER_PAGE_STARTED (f) = 0;
1023       EndPage (DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f))));
1024       apply_dc_geometry (f);
1025     }
1026 }
1027
1028 \f
1029 void
1030 console_type_create_frame_mswindows (void)
1031 {
1032   /* Display frames */
1033   CONSOLE_HAS_METHOD (mswindows, init_frame_1);
1034   CONSOLE_HAS_METHOD (mswindows, init_frame_2); 
1035   CONSOLE_HAS_METHOD (mswindows, init_frame_3);
1036   CONSOLE_HAS_METHOD (mswindows, after_init_frame);
1037   CONSOLE_HAS_METHOD (mswindows, mark_frame);
1038   CONSOLE_HAS_METHOD (mswindows, focus_on_frame);
1039   CONSOLE_HAS_METHOD (mswindows, delete_frame);
1040   CONSOLE_HAS_METHOD (mswindows, get_mouse_position);
1041   CONSOLE_HAS_METHOD (mswindows, set_mouse_position);
1042   CONSOLE_HAS_METHOD (mswindows, raise_frame);
1043   CONSOLE_HAS_METHOD (mswindows, lower_frame);
1044   CONSOLE_HAS_METHOD (mswindows, make_frame_visible);
1045   CONSOLE_HAS_METHOD (mswindows, make_frame_invisible);
1046   CONSOLE_HAS_METHOD (mswindows, iconify_frame);
1047   CONSOLE_HAS_METHOD (mswindows, set_frame_size);
1048   CONSOLE_HAS_METHOD (mswindows, set_frame_position);
1049   CONSOLE_HAS_METHOD (mswindows, frame_property);
1050   CONSOLE_HAS_METHOD (mswindows, internal_frame_property_p);
1051   CONSOLE_HAS_METHOD (mswindows, frame_properties);
1052   CONSOLE_HAS_METHOD (mswindows, set_frame_properties);
1053   CONSOLE_HAS_METHOD (mswindows, set_title_from_bufbyte);
1054 /*  CONSOLE_HAS_METHOD (mswindows, set_icon_name_from_bufbyte); */
1055   CONSOLE_HAS_METHOD (mswindows, frame_visible_p);
1056   CONSOLE_HAS_METHOD (mswindows, frame_totally_visible_p);
1057   CONSOLE_HAS_METHOD (mswindows, frame_iconified_p);
1058   CONSOLE_HAS_METHOD (mswindows, set_frame_pointer); 
1059   CONSOLE_HAS_METHOD (mswindows, set_frame_icon); 
1060   CONSOLE_HAS_METHOD (mswindows, get_frame_parent);
1061   CONSOLE_HAS_METHOD (mswindows, update_frame_external_traits);
1062   CONSOLE_HAS_METHOD (mswindows, frame_size_fixed_p);
1063
1064   /* Printer frames, aka print jobs */
1065   CONSOLE_HAS_METHOD (msprinter, init_frame_1);
1066   CONSOLE_HAS_METHOD (msprinter, init_frame_3);
1067   CONSOLE_HAS_METHOD (msprinter, mark_frame);
1068   CONSOLE_HAS_METHOD (msprinter, delete_frame);
1069   CONSOLE_HAS_METHOD (msprinter, frame_property);
1070   CONSOLE_HAS_METHOD (msprinter, internal_frame_property_p);
1071   CONSOLE_HAS_METHOD (msprinter, frame_properties);
1072   CONSOLE_HAS_METHOD (msprinter, set_frame_properties);
1073   CONSOLE_HAS_METHOD (msprinter, set_frame_size);
1074   CONSOLE_HAS_METHOD (msprinter, eject_page);
1075 }
1076
1077 void
1078 syms_of_frame_mswindows (void)
1079 {
1080 }
1081
1082 void
1083 reinit_vars_of_frame_mswindows (void)
1084 {
1085   /* Needn't staticpro -- see comment above.  */
1086   Vmswindows_frame_being_created = Qnil;
1087 }
1088
1089 void
1090 vars_of_frame_mswindows (void)
1091 {
1092   reinit_vars_of_frame_mswindows ();
1093
1094   DEFVAR_LISP ("mswindows-use-system-frame-size-defaults", &Vmswindows_use_system_frame_size_defaults /*
1095 Controls whether to use system or XEmacs defaults for frame size.
1096 If nil then reasonable defaults are used for intial frame sizes. If t
1097 then the system will choose default sizes for the frame.
1098 */ );
1099   Vmswindows_use_system_frame_size_defaults = Qnil;
1100   
1101   DEFVAR_LISP ("default-mswindows-frame-plist", &Vdefault_mswindows_frame_plist /*
1102 Plist of default frame-creation properties for mswindows frames.
1103 These override what is specified in `default-frame-plist', but are
1104 overridden by the arguments to the particular call to `make-frame'.
1105
1106 Note: In many cases, properties of a frame are available as specifiers
1107 instead of through the frame-properties mechanism.
1108
1109 Here is a list of recognized frame properties, other than those
1110 documented in `set-frame-properties' (they can be queried and
1111 set at any time, except as otherwise noted):
1112
1113   initially-unmapped            If non-nil, the frame will not be visible
1114                                 when it is created.  In this case, you
1115                                 need to call `make-frame-visible' to make
1116                                 the frame appear.
1117   popup                         If non-nil, it should be a frame, and this
1118                                 frame will be created as a "popup" frame
1119                                 whose parent is the given frame.  This
1120                                 will make the window manager treat the
1121                                 frame as a dialog box, which may entail
1122                                 doing different things (e.g. not asking
1123                                 for positioning, and not iconifying
1124                                 separate from its parent).
1125   top                           Y position (in pixels) of the upper-left
1126                                 outermost corner of the frame (i.e. the
1127                                 upper-left of the window-manager
1128                                 decorations).
1129   left                          X position (in pixels) of the upper-left
1130                                 outermost corner of the frame (i.e. the
1131                                 upper-left of the window-manager
1132                                 decorations).
1133
1134 See also `default-frame-plist', which specifies properties which apply
1135 to all frames, not just mswindows frames.
1136 */ );
1137   Vdefault_mswindows_frame_plist = Qnil;
1138
1139   mswindows_console_methods->device_specific_frame_props =
1140     &Vdefault_mswindows_frame_plist;
1141
1142   DEFVAR_LISP ("default-msprinter-frame-plist", &Vdefault_msprinter_frame_plist /*
1143 Plist of default frame-creation properties for msprinter print job frames.
1144 These override what is specified in `default-frame-plist', but are
1145 overridden by the arguments to the particular call to `make-frame'.
1146
1147 Note: In many cases, properties of a frame are available as specifiers
1148 instead of through the frame-properties mechanism.
1149
1150 Here is a list of recognized frame properties, other than those
1151 documented in `set-frame-properties' (they can be queried and
1152 set at any time, except as otherwise noted):
1153
1154   left-margin                   Margin of the page, in twips. Twip is a
1155   top-margin                    typographical unit of measurement,
1156   right-margin                  equal to 1/1440 of an inch, or 1/20 of a
1157   bottom-margin                 point, and roughly equal to 7/400 of a
1158                                 millimeter. If not specifified, each margin
1159                                 defaults to one inch (25.4 mm).
1160
1161      MARGINS NOTE. right-margin and bottom-margin are overridden by
1162        the height and width properties. If you want to specify size
1163        of the printable area in character, as with the rest of XEmacs,
1164        use these properties. If height and/or width are nil, then
1165        corresponding margin setting is taken into account. If you
1166        specify height and/or width in `default-frame-plist', but still
1167        want to specify right/bottom margins, set height/width in this
1168        plist to nil, as in this example:
1169
1170           (setq default-frame-plist '(height 55 'width 80)
1171                 default-msprinter-frame-plist '(height nil 'width nil))
1172
1173 See also `default-frame-plist', which specifies properties which apply
1174 to all frames, not just mswindows frames.
1175 */ );
1176   Vdefault_msprinter_frame_plist = Qnil;
1177
1178   msprinter_console_methods->device_specific_frame_props =
1179     &Vdefault_msprinter_frame_plist;
1180 }