]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
Merge from emacs--rel--22
[gnu-emacs] / src / w32fns.c
index 8c6a60d47bf5b2499dce9640d137b23b1b730d29..be3570231dcc2745d24094a081d19d9a42f75765 100644 (file)
@@ -1,12 +1,12 @@
 /* Graphical user interface functions for the Microsoft W32 API.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-                 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -52,6 +52,7 @@ Boston, MA 02110-1301, USA.  */
 #include <shellapi.h>
 #include <ctype.h>
 #include <winspool.h>
+#include <objbase.h>
 
 #include <dlgs.h>
 #define FILE_NAME_TEXT_FIELD edt1
@@ -297,6 +298,10 @@ extern int w32_use_visible_system_caret;
 
 static HWND w32_visible_system_caret_hwnd;
 
+/* From w32menu.c  */
+extern HMENU current_popup_menu;
+static int menubar_in_use = 0;
+
 \f
 /* Error if we are not connected to MS-Windows.  */
 void
@@ -431,20 +436,21 @@ x_real_positions (f, xptr, yptr)
   POINT pt;
   RECT rect;
 
-  GetClientRect(FRAME_W32_WINDOW(f), &rect);
-  AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
+  /* Get the bounds of the WM window.  */
+  GetWindowRect (FRAME_W32_WINDOW (f), &rect);
 
-  pt.x = rect.left;
-  pt.y = rect.top;
+  pt.x = 0;
+  pt.y = 0;
 
-  ClientToScreen (FRAME_W32_WINDOW(f), &pt);
+  /* Convert (0, 0) in the client area to screen co-ordinates.  */
+  ClientToScreen (FRAME_W32_WINDOW (f), &pt);
 
   /* Remember x_pixels_diff and y_pixels_diff.  */
   f->x_pixels_diff = pt.x - rect.left;
   f->y_pixels_diff = pt.y - rect.top;
 
-  *xptr = pt.x;
-  *yptr = pt.y;
+  *xptr = rect.left;
+  *yptr = rect.top;
 }
 
 \f
@@ -2080,35 +2086,15 @@ w32_createwindow (f)
 
   if (!hprevinst)
     {
-      Lisp_Object ifa;
-
       w32_init_class (hinst);
-
-      /* Handle the -geometry command line option and the geometry
-        settings in the registry.  They are decoded and put into
-        initial-frame-alist by w32-win.el:x-handle-geometry.  */
-      ifa = Fsymbol_value (intern ("initial-frame-alist"));
-      if (CONSP (ifa))
-       {
-         Lisp_Object lt = Fassq (Qleft, ifa);
-         Lisp_Object tp = Fassq (Qtop,  ifa);
-
-         if (!NILP (lt))
-           {
-             lt = XCDR (lt);
-             if (INTEGERP (lt))
-               left = lt;
-           }
-         if (!NILP (tp))
-           {
-             tp = XCDR (tp);
-             if (INTEGERP (tp))
-               top = tp;
-           }
-       }
     }
 
-  if (EQ (left, Qunbound) && EQ (top, Qunbound))
+  if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition)
+    {
+      XSETINT (left, f->left_pos);
+      XSETINT (top, f->top_pos);
+    }
+  else if (EQ (left, Qunbound) && EQ (top, Qunbound))
     {
       /* When called with RES_TYPE_NUMBER, w32_get_arg will return zero
         for anything that is not a number and is not Qunbound.  */
@@ -2530,6 +2516,13 @@ w32_msg_pump (deferred_msg * msg_buf)
              /* Produced by complete_deferred_msg; just ignore.  */
              break;
            case WM_EMACS_CREATEWINDOW:
+              /* Initialize COM for this window. Even though we don't use it,
+                 some third party shell extensions can cause it to be used in
+                 system dialogs, which causes a crash if it is not initialized.
+                 This is a known bug in Windows, which was fixed long ago, but
+                 the patch for XP is not publically available until XP SP3,
+                 and older versions will never be patched.  */
+              CoInitialize (NULL);
              w32_createwindow ((struct frame *) msg.wParam);
              if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
                abort ();
@@ -2709,9 +2702,8 @@ cancel_all_deferred_msgs ()
   PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
 }
 
-DWORD
-w32_msg_worker (dw)
-     DWORD dw;
+DWORD WINAPI
+w32_msg_worker (void *arg)
 {
   MSG msg;
   deferred_msg dummy_buf;
@@ -3432,11 +3424,14 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
          KillTimer (hwnd, menu_free_timer);
          menu_free_timer = 0;
          f = x_window_to_frame (dpyinfo, hwnd);
-         if (!f->output_data.w32->menu_command_in_progress)
+          /* If a popup menu is active, don't wipe its strings.  */
+         if (menubar_in_use
+              && current_popup_menu == NULL)
            {
              /* Free memory used by owner-drawn and help-echo strings.  */
              w32_free_menu_strings (hwnd);
              f->output_data.w32->menubar_active = 0;
+              menubar_in_use = 0;
            }
        }
       return 0;
@@ -3488,16 +3483,21 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
        if (find_deferred_msg (hwnd, msg) != NULL)
          abort ();
 
+        menubar_in_use = 1;
+
        return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
       }
 
     case WM_EXITMENULOOP:
       f = x_window_to_frame (dpyinfo, hwnd);
 
-      /* If a menu command is not already in progress, check again
-        after a short delay, since Windows often (always?) sends the
-        WM_EXITMENULOOP before the corresponding WM_COMMAND message.  */
-      if (f && !f->output_data.w32->menu_command_in_progress)
+      /* If a menu is still active, check again after a short delay,
+        since Windows often (always?) sends the WM_EXITMENULOOP
+        before the corresponding WM_COMMAND message.
+         Don't do this if a popup menu is active, since it is only
+         menubar menus that require cleaning up in this way.
+      */
+      if (f && menubar_in_use && current_popup_menu == NULL)
        menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
       goto dflt;
 
@@ -3652,10 +3652,10 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
        }
       goto command;
     case WM_COMMAND:
+      menubar_in_use = 0;
       f = x_window_to_frame (dpyinfo, hwnd);
       if (f && HIWORD (wParam) == 0)
        {
-         f->output_data.w32->menu_command_in_progress = 1;
          if (menu_free_timer)
            {
              KillTimer (hwnd, menu_free_timer);
@@ -3669,6 +3669,10 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       goto dflt;
 
+    case WM_DESTROY:
+      CoUninitialize ();
+      return 0;
+
     case WM_CLOSE:
       wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
@@ -3727,8 +3731,11 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
                   However for top/left sizing we will need to fix the X
                   and Y positions as well.  */
 
-               lppos->cx -= wdiff;
-               lppos->cy -= hdiff;
+               int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK);
+               int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK);
+
+               lppos->cx = max (lppos->cx - wdiff, cx_mintrack);
+               lppos->cy = max (lppos->cy - hdiff, cy_mintrack);
 
                if (wp.showCmd != SW_SHOWMAXIMIZED
                    && (lppos->flags & SWP_NOMOVE) == 0)
@@ -3752,9 +3759,6 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
       goto dflt;
 
     case WM_GETMINMAXINFO:
-      /* Hack to correct bug that allows Emacs frames to be resized
-        below the Minimum Tracking Size.  */
-      ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
       /* Hack to allow resizing the Emacs frame above the screen size.
         Note that Windows 9x limits coordinates to 16-bits.  */
       ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
@@ -7507,6 +7511,8 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
        doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
 A tooltip window is a small window displaying a string.
 
+This is an internal function; Lisp code should call `tooltip-show'.
+
 FRAME nil or omitted means use the selected frame.
 
 PARMS is an optional list of frame parameters which can be
@@ -7909,9 +7915,9 @@ If ONLY-DIR-P is non-nil, the user can only select directories.  */)
     /* Apparently NT4 crashes if you give it an unexpected size.
        I'm not sure about Windows 9x, so play it safe.  */
     if (w32_major_version > 4 && w32_major_version < 95)
-      file_details->lStructSize = sizeof (new_file_details);
+      file_details->lStructSize = sizeof (NEWOPENFILENAME);
     else
-      file_details->lStructSize = sizeof (file_details);
+      file_details->lStructSize = sizeof (OPENFILENAME);
 
     file_details->hwndOwner = FRAME_W32_WINDOW (f);
     /* Undocumented Bug in Common File Dialog:
@@ -8065,17 +8071,39 @@ DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
        doc: /* Get Windows to perform OPERATION on DOCUMENT.
 This is a wrapper around the ShellExecute system function, which
 invokes the application registered to handle OPERATION for DOCUMENT.
-OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
-nil for the default action), and DOCUMENT is typically the name of a
-document file or URL, but can also be a program executable to run or
-a directory to open in the Windows Explorer.
 
-If DOCUMENT is a program executable, PARAMETERS can be a string
-containing command line parameters, but otherwise should be nil.
-
-SHOW-FLAG can be used to control whether the invoked application is hidden
-or minimized.  If SHOW-FLAG is nil, the application is displayed normally,
-otherwise it is an integer representing a ShowWindow flag:
+OPERATION is either nil or a string that names a supported operation.
+What operations can be used depends on the particular DOCUMENT and its
+handler application, but typically it is one of the following common
+operations:
+
+ \"open\"    - open DOCUMENT, which could be a file, a directory, or an
+               executable program.  If it is an application, that
+               application is launched in the current buffer's default
+               directory.  Otherwise, the application associated with
+               DOCUMENT is launched in the buffer's default directory.
+ \"print\"   - print DOCUMENT, which must be a file
+ \"explore\" - start the Windows Explorer on DOCUMENT
+ \"edit\"    - launch an editor and open DOCUMENT for editing; which
+               editor is launched depends on the association for the
+               specified DOCUMENT
+ \"find\"    - initiate search starting from DOCUMENT which must specify
+               a directory
+ nil       - invoke the default OPERATION, or \"open\" if default is
+               not defined or unavailable
+
+DOCUMENT is typically the name of a document file or a URL, but can
+also be a program executable to run, or a directory to open in the
+Windows Explorer.
+
+If DOCUMENT is a program executable, the optional arg PARAMETERS can
+be a string containing command line parameters that will be passed to
+the program; otherwise, PARAMETERS should be nil or unspecified.
+
+Second optional argument SHOW-FLAG can be used to control how the
+application will be displayed when it is invoked.  If SHOW-FLAG is nil
+or unspceified, the application is displayed normally, otherwise it is
+an integer representing a ShowWindow flag:
 
   0 - start hidden
   1 - start normally
@@ -8348,6 +8376,30 @@ is set to off if the low bit of NEW-STATE is zero, otherwise on.  */)
     }
   return Qnil;
 }
+
+DEFUN ("w32-window-exists-p", Fw32_window_exists_p, Sw32_window_exists_p,
+       2, 2, 0,
+       doc: /* Return non-nil if a window exists with the specified CLASS and NAME.
+
+This is a direct interface to the Windows API FindWindow function.  */)
+  (class, name)
+Lisp_Object class, name;
+{
+  HWND hnd;
+
+  if (!NILP (class))
+    CHECK_STRING (class);
+  if (!NILP (name))
+    CHECK_STRING (name);
+
+  hnd = FindWindow (STRINGP (class) ? ((LPCTSTR) SDATA (class)) : NULL,
+                   STRINGP (name)  ? ((LPCTSTR) SDATA (name))  : NULL);
+  if (!hnd)
+    return Qnil;
+  return Qt;
+}
+
+
 \f
 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
        doc: /* Return storage information about the file system FILENAME is on.
@@ -8609,14 +8661,15 @@ syms_of_w32fns ()
   Vw32_color_map = Qnil;
 
   DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
-              doc: /* Non-nil if alt key presses are passed on to Windows.
-When non-nil, for example, alt pressed and released and then space will
-open the System menu.  When nil, Emacs silently swallows alt key events.  */);
+              doc: /* Non-nil if Alt key presses are passed on to Windows.
+When non-nil, for example, Alt pressed and released and then space will
+open the System menu.  When nil, Emacs processes the Alt key events, and
+then silently swallows them.  */);
   Vw32_pass_alt_to_system = Qnil;
 
   DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
-              doc: /* Non-nil if the alt key is to be considered the same as the meta key.
-When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.  */);
+              doc: /* Non-nil if the Alt key is to be considered the same as the META key.
+When nil, Emacs will translate the Alt key to the ALT modifier, not to META.  */);
   Vw32_alt_is_meta = Qt;
 
   DEFVAR_INT ("w32-quit-key", &w32_quit_key,
@@ -8625,14 +8678,32 @@ When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.  *
 
   DEFVAR_LISP ("w32-pass-lwindow-to-system",
               &Vw32_pass_lwindow_to_system,
-              doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
-When non-nil, the Start menu is opened by tapping the key.  */);
+              doc: /* If non-nil, the left \"Windows\" key is passed on to Windows.
+
+When non-nil, the Start menu is opened by tapping the key.
+If you set this to nil, the left \"Windows\" key is processed by Emacs
+according to the value of `w32-lwindow-modifier', which see.
+
+Note that some combinations of the left \"Windows\" key with other keys are
+caught by Windows at low level, and so binding them in Emacs will have no
+effect.  For example, <lwindow>-r always pops up the Windows Run dialog,
+<lwindow>-<Pause> pops up the "System Properties" dialog, etc.  However, see
+the doc string of `w32-phantom-key-code'.  */);
   Vw32_pass_lwindow_to_system = Qt;
 
   DEFVAR_LISP ("w32-pass-rwindow-to-system",
               &Vw32_pass_rwindow_to_system,
-              doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
-When non-nil, the Start menu is opened by tapping the key.  */);
+              doc: /* If non-nil, the right \"Windows\" key is passed on to Windows.
+
+When non-nil, the Start menu is opened by tapping the key.
+If you set this to nil, the right \"Windows\" key is processed by Emacs
+according to the value of `w32-rwindow-modifier', which see.
+
+Note that some combinations of the right \"Windows\" key with other keys are
+caught by Windows at low level, and so binding them in Emacs will have no
+effect.  For example, <rwindow>-r always pops up the Windows Run dialog,
+<rwindow>-<Pause> pops up the "System Properties" dialog, etc.  However, see
+the doc string of `w32-phantom-key-code'.  */);
   Vw32_pass_rwindow_to_system = Qt;
 
   DEFVAR_LISP ("w32-phantom-key-code",
@@ -8649,29 +8720,29 @@ acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
 
   DEFVAR_LISP ("w32-enable-num-lock",
               &Vw32_enable_num_lock,
-              doc: /* Non-nil if Num Lock should act normally.
-Set to nil to see Num Lock as the key `kp-numlock'.  */);
+              doc: /* If non-nil, the Num Lock key acts normally.
+Set to nil to handle Num Lock as the `kp-numlock' key.  */);
   Vw32_enable_num_lock = Qt;
 
   DEFVAR_LISP ("w32-enable-caps-lock",
               &Vw32_enable_caps_lock,
-              doc: /* Non-nil if Caps Lock should act normally.
-Set to nil to see Caps Lock as the key `capslock'.  */);
+              doc: /* If non-nil, the Caps Lock key acts normally.
+Set to nil to handle Caps Lock as the `capslock' key.  */);
   Vw32_enable_caps_lock = Qt;
 
   DEFVAR_LISP ("w32-scroll-lock-modifier",
               &Vw32_scroll_lock_modifier,
-              doc: /* Modifier to use for the Scroll Lock on state.
+              doc: /* Modifier to use for the Scroll Lock ON state.
 The value can be hyper, super, meta, alt, control or shift for the
-respective modifier, or nil to see Scroll Lock as the key `scroll'.
-Any other value will cause the key to be ignored.  */);
+respective modifier, or nil to handle Scroll Lock as the `scroll' key.
+Any other value will cause the Scroll Lock key to be ignored.  */);
   Vw32_scroll_lock_modifier = Qt;
 
   DEFVAR_LISP ("w32-lwindow-modifier",
               &Vw32_lwindow_modifier,
               doc: /* Modifier to use for the left \"Windows\" key.
 The value can be hyper, super, meta, alt, control or shift for the
-respective modifier, or nil to appear as the key `lwindow'.
+respective modifier, or nil to appear as the `lwindow' key.
 Any other value will cause the key to be ignored.  */);
   Vw32_lwindow_modifier = Qnil;
 
@@ -8679,7 +8750,7 @@ Any other value will cause the key to be ignored.  */);
               &Vw32_rwindow_modifier,
               doc: /* Modifier to use for the right \"Windows\" key.
 The value can be hyper, super, meta, alt, control or shift for the
-respective modifier, or nil to appear as the key `rwindow'.
+respective modifier, or nil to appear as the `rwindow' key.
 Any other value will cause the key to be ignored.  */);
   Vw32_rwindow_modifier = Qnil;
 
@@ -8687,7 +8758,7 @@ Any other value will cause the key to be ignored.  */);
               &Vw32_apps_modifier,
               doc: /* Modifier to use for the \"Apps\" key.
 The value can be hyper, super, meta, alt, control or shift for the
-respective modifier, or nil to appear as the key `apps'.
+respective modifier, or nil to appear as the `apps' key.
 Any other value will cause the key to be ignored.  */);
   Vw32_apps_modifier = Qnil;
 
@@ -8703,7 +8774,7 @@ Any other value will cause the key to be ignored.  */);
              &w32_mouse_button_tolerance,
              doc: /* Analogue of double click interval for faking middle mouse events.
 The value is the minimum time in milliseconds that must elapse between
-left/right button down events before they are considered distinct events.
+left and right button down events before they are considered distinct events.
 If both mouse buttons are depressed within this interval, a middle mouse
 button down event is generated instead.  */);
   w32_mouse_button_tolerance = GetDoubleClickTime () / 2;
@@ -8718,7 +8789,7 @@ reported as lisp events.  */);
 
   DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
               &w32_pass_extra_mouse_buttons_to_system,
-              doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
+              doc: /* If non-nil, the fourth and fifth mouse buttons are passed to Windows.
 Recent versions of Windows support mice with up to five buttons.
 Since most applications don't support these extra buttons, most mouse
 drivers will allow you to map them to functions at the system level.
@@ -8895,6 +8966,7 @@ versions of Windows) characters.  */);
 
     staticpro (&Qw32_charset_unicode);
     Qw32_charset_unicode = intern ("w32-charset-unicode");
+  }
 #endif
 
 #if 0 /* TODO: Port to W32 */
@@ -8939,6 +9011,7 @@ versions of Windows) characters.  */);
   defsubr (&Sw32_registered_hot_keys);
   defsubr (&Sw32_reconstruct_hot_key);
   defsubr (&Sw32_toggle_lock_key);
+  defsubr (&Sw32_window_exists_p);
   defsubr (&Sw32_find_bdf_fonts);
 
   defsubr (&Sfile_system_info);