]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
* lisp.h (toplevel): Add compile-time assert to verify suitable member layout
[gnu-emacs] / src / w32fns.c
index 630059c38f10faef877bff9e24674e4343f3f83c..e24148af4ff5f636453830d376555ebe55f07757 100644 (file)
@@ -96,7 +96,6 @@ static HWND hourglass_hwnd = NULL;
 #define IDC_HAND MAKEINTRESOURCE(32649)
 #endif
 
-Lisp_Object Qsuppress_icon;
 Lisp_Object Qundefined_color;
 Lisp_Object Qcancel_timer;
 Lisp_Object Qfont_param;
@@ -723,8 +722,7 @@ w32_default_color_map (void)
 
   cmap = Qnil;
 
-  for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
-       pc++, i++)
+  for (i = 0; i < ARRAYELTS (w32_color_map); pc++, i++)
     cmap = Fcons (Fcons (build_string (pc->name),
                         make_number (pc->colorref)),
                  cmap);
@@ -4245,6 +4243,17 @@ unwind_create_frame (Lisp_Object frame)
     {
 #ifdef GLYPH_DEBUG
       struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+      /* If the frame's image cache refcount is still the same as our
+        private shadow variable, it means we are unwinding a frame
+        for which we didn't yet call init_frame_faces, where the
+        refcount is incremented.  Therefore, we increment it here, so
+        that free_frame_faces, called in x_free_frame_resources
+        below, will not mistakenly decrement the counter that was not
+        incremented yet to account for this new frame.  */
+      if (FRAME_IMAGE_CACHE (f) != NULL
+         && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
+       FRAME_IMAGE_CACHE (f)->refcount++;
 #endif
 
       x_free_frame_resources (f);
@@ -4255,7 +4264,8 @@ unwind_create_frame (Lisp_Object frame)
       eassert (dpyinfo->reference_count == dpyinfo_refcount);
       eassert ((dpyinfo->terminal->image_cache == NULL
                && image_cache_refcount == 0)
-              || dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
+              || (dpyinfo->terminal->image_cache != NULL
+                  && dpyinfo->terminal->image_cache->refcount == image_cache_refcount));
 #endif
       return Qt;
     }
@@ -6871,24 +6881,33 @@ operations:
                specified DOCUMENT.
  \"find\"    - initiate search starting from DOCUMENT, which must specify
                a directory.
+ \"delete\"  - move DOCUMENT, a file or a directory, to Recycle Bin.
+ \"copy\"    - copy DOCUMENT, which must be a file or a directory, into
+               the clipboard.
+ \"cut\"     - move DOCUMENT, a file or a directory, into the clipboard.
+ \"paste\"   - paste the file whose name is in the clipboard into DOCUMENT,
+               which must be a directory.
+ \"pastelink\"
+           - create a shortcut in DOCUMENT (which must be a directory)
+               the file or directory whose name is in the clipboard.
  \"runas\"   - run DOCUMENT, which must be an excutable file, with
                elevated privileges (a.k.a. \"as Administrator\").
  \"properties\"
-           - open the the property sheet dialog for DOCUMENT; works
-               for *.lnk desktop shortcuts, and little or nothing else.
+           - open the property sheet dialog for DOCUMENT.
  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 an executable program to run, or a directory to open in the
-Windows Explorer.  If it is a file, it must be a local one; this
-function does not support remote file names.
+Windows Explorer.  If it is a file or a directory, it must be a local
+one; this function does not support remote file names.
 
 If DOCUMENT is an executable program, the optional third arg PARAMETERS
-can be a string containing command line parameters that will be passed
-to the program.  Some values of OPERATION also require parameters (e.g.,
-\"printto\" requires the printer address).  Otherwise, PARAMETERS should
-be nil or unspecified.
+can be a string containing command line parameters, separated by blanks,
+that will be passed to the program.  Some values of OPERATION also require
+parameters (e.g., \"printto\" requires the printer address).  Otherwise,
+PARAMETERS should be nil or unspecified.  Note that double quote characters
+in PARAMETERS must each be enclosed in 2 additional quotes, as in \"\"\".
 
 Optional fourth argument SHOW-FLAG can be used to control how the
 application will be displayed when it is invoked.  If SHOW-FLAG is nil
@@ -6906,11 +6925,13 @@ a ShowWindow flag:
   char *errstr;
   Lisp_Object current_dir = BVAR (current_buffer, directory);;
   wchar_t *doc_w = NULL, *params_w = NULL, *ops_w = NULL;
+#ifdef CYGWIN
   intptr_t result;
-#ifndef CYGWIN
+#else
   int use_unicode = w32_unicode_filenames;
   char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
   Lisp_Object absdoc, handler;
+  BOOL success;
   struct gcpro gcpro1;
 #endif
 
@@ -6938,7 +6959,48 @@ a ShowWindow flag:
                                     GUI_SDATA (current_dir),
                                     (INTEGERP (show_flag)
                                      ? XINT (show_flag) : SW_SHOWDEFAULT));
+
+  if (result > 32)
+    return Qt;
+
+  switch (result)
+    {
+    case SE_ERR_ACCESSDENIED:
+      errstr = w32_strerror (ERROR_ACCESS_DENIED);
+      break;
+    case SE_ERR_ASSOCINCOMPLETE:
+    case SE_ERR_NOASSOC:
+      errstr = w32_strerror (ERROR_NO_ASSOCIATION);
+      break;
+    case SE_ERR_DDEBUSY:
+    case SE_ERR_DDEFAIL:
+      errstr = w32_strerror (ERROR_DDE_FAIL);
+      break;
+    case SE_ERR_DDETIMEOUT:
+      errstr = w32_strerror (ERROR_TIMEOUT);
+      break;
+    case SE_ERR_DLLNOTFOUND:
+      errstr = w32_strerror (ERROR_DLL_NOT_FOUND);
+      break;
+    case SE_ERR_FNF:
+      errstr = w32_strerror (ERROR_FILE_NOT_FOUND);
+      break;
+    case SE_ERR_OOM:
+      errstr = w32_strerror (ERROR_NOT_ENOUGH_MEMORY);
+      break;
+    case SE_ERR_PNF:
+      errstr = w32_strerror (ERROR_PATH_NOT_FOUND);
+      break;
+    case SE_ERR_SHARE:
+      errstr = w32_strerror (ERROR_SHARING_VIOLATION);
+      break;
+    default:
+      errstr = w32_strerror (0);
+      break;
+    }
+
 #else  /* !CYGWIN */
+
   current_dir = ENCODE_FILE (current_dir);
   /* We have a situation here.  If DOCUMENT is a relative file name,
      but its name includes leading directories, i.e. it lives not in
@@ -6968,6 +7030,7 @@ a ShowWindow flag:
   if (use_unicode)
     {
       wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
+      SHELLEXECUTEINFOW shexinfo_w;
 
       /* Encode filename, current directory and parameters, and
         convert operation to UTF-16.  */
@@ -7001,14 +7064,28 @@ a ShowWindow flag:
            *d++ = *s++;
          *d = 0;
        }
-      result = (intptr_t) ShellExecuteW (NULL, ops_w, doc_w, params_w,
-                                        current_dir_w,
-                                        (INTEGERP (show_flag)
-                                         ? XINT (show_flag) : SW_SHOWDEFAULT));
+
+      /* Using ShellExecuteEx and setting the SEE_MASK_INVOKEIDLIST
+        flag succeeds with more OPERATIONs (a.k.a. "verbs"), as it is
+        able to invoke verbs from shortcut menu extensions, not just
+        static verbs listed in the Registry.  */
+      memset (&shexinfo_w, 0, sizeof (shexinfo_w));
+      shexinfo_w.cbSize = sizeof (shexinfo_w);
+      shexinfo_w.fMask =
+       SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
+      shexinfo_w.hwnd = NULL;
+      shexinfo_w.lpVerb = ops_w;
+      shexinfo_w.lpFile = doc_w;
+      shexinfo_w.lpParameters = params_w;
+      shexinfo_w.lpDirectory = current_dir_w;
+      shexinfo_w.nShow =
+       (INTEGERP (show_flag) ? XINT (show_flag) : SW_SHOWDEFAULT);
+      success = ShellExecuteExW (&shexinfo_w);
     }
   else
     {
       char document_a[MAX_PATH], current_dir_a[MAX_PATH];
+      SHELLEXECUTEINFOA shexinfo_a;
 
       filename_to_ansi (SSDATA (current_dir), current_dir_a);
       filename_to_ansi (SSDATA (document), document_a);
@@ -7023,51 +7100,27 @@ a ShowWindow flag:
          /* Assume OPERATION is pure ASCII.  */
          ops_a = SSDATA (operation);
        }
-      result = (intptr_t) ShellExecuteA (NULL, ops_a, doc_a, params_a,
-                                        current_dir_a,
-                                        (INTEGERP (show_flag)
-                                         ? XINT (show_flag) : SW_SHOWDEFAULT));
+      memset (&shexinfo_a, 0, sizeof (shexinfo_a));
+      shexinfo_a.cbSize = sizeof (shexinfo_a);
+      shexinfo_a.fMask =
+       SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
+      shexinfo_a.hwnd = NULL;
+      shexinfo_a.lpVerb = ops_a;
+      shexinfo_a.lpFile = doc_a;
+      shexinfo_a.lpParameters = params_a;
+      shexinfo_a.lpDirectory = current_dir_a;
+      shexinfo_a.nShow =
+       (INTEGERP (show_flag) ? XINT (show_flag) : SW_SHOWDEFAULT);
+      success = ShellExecuteExA (&shexinfo_a);
     }
-#endif /* !CYGWIN */
 
-  if (result > 32)
+  if (success)
     return Qt;
 
-  switch (result)
-    {
-    case SE_ERR_ACCESSDENIED:
-      errstr = w32_strerror (ERROR_ACCESS_DENIED);
-      break;
-    case SE_ERR_ASSOCINCOMPLETE:
-    case SE_ERR_NOASSOC:
-      errstr = w32_strerror (ERROR_NO_ASSOCIATION);
-      break;
-    case SE_ERR_DDEBUSY:
-    case SE_ERR_DDEFAIL:
-      errstr = w32_strerror (ERROR_DDE_FAIL);
-      break;
-    case SE_ERR_DDETIMEOUT:
-      errstr = w32_strerror (ERROR_TIMEOUT);
-      break;
-    case SE_ERR_DLLNOTFOUND:
-      errstr = w32_strerror (ERROR_DLL_NOT_FOUND);
-      break;
-    case SE_ERR_FNF:
-      errstr = w32_strerror (ERROR_FILE_NOT_FOUND);
-      break;
-    case SE_ERR_OOM:
-      errstr = w32_strerror (ERROR_NOT_ENOUGH_MEMORY);
-      break;
-    case SE_ERR_PNF:
-      errstr = w32_strerror (ERROR_PATH_NOT_FOUND);
-      break;
-    case SE_ERR_SHARE:
-      errstr = w32_strerror (ERROR_SHARING_VIOLATION);
-      break;
-    default:
-      errstr = w32_strerror (0);
-      break;
-    }
+  errstr = w32_strerror (0);
+
+#endif /* !CYGWIN */
+
   /* The error string might be encoded in the locale's encoding.  */
   if (!NILP (Vlocale_coding_system))
     {
@@ -7487,8 +7540,8 @@ If the underlying system call fails, value is nil.  */)
       (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
       = GetProcAddress (hKernel, "GetDiskFreeSpaceExA");
     bool have_pfn_GetDiskFreeSpaceEx =
-      (w32_unicode_filenames && pfn_GetDiskFreeSpaceExW
-       || !w32_unicode_filenames && pfn_GetDiskFreeSpaceExA);
+      ((w32_unicode_filenames && pfn_GetDiskFreeSpaceExW)
+       || (!w32_unicode_filenames && pfn_GetDiskFreeSpaceExA));
 
     /* On Windows, we may need to specify the root directory of the
        volume holding FILENAME.  */
@@ -8037,7 +8090,6 @@ syms_of_w32fns (void)
 
   w32_visible_system_caret_hwnd = NULL;
 
-  DEFSYM (Qsuppress_icon, "suppress-icon");
   DEFSYM (Qundefined_color, "undefined-color");
   DEFSYM (Qcancel_timer, "cancel-timer");
   DEFSYM (Qhyper, "hyper");
@@ -8052,8 +8104,6 @@ syms_of_w32fns (void)
   DEFSYM (Qworkarea, "workarea");
   DEFSYM (Qmm_size, "mm-size");
   DEFSYM (Qframes, "frames");
-  /* This is the end of symbol initialization.  */
-
 
   Fput (Qundefined_color, Qerror_conditions,
        listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));