]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
Merge from emacs--rel--22
[gnu-emacs] / src / w32fns.c
index 269e357f0a8f585bfef1373d891b71dcafd40cfa..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
@@ -2510,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 ();
@@ -2689,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;
@@ -3412,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;
@@ -3468,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;
 
@@ -3632,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);
@@ -3649,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);
@@ -3707,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)
@@ -3732,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;
@@ -7487,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
@@ -7889,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:
@@ -8045,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
@@ -8328,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.
@@ -8894,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 */
@@ -8938,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);