]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
Fix handling of image cache refcounts. (Bug#20802)
[gnu-emacs] / src / w32fns.c
index deda2eab26d5edee7d3b460b408a1596fb8e2429..5f40729011e91628e430580109e1eae3299c1767 100644 (file)
@@ -29,6 +29,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <c-ctype.h>
+
 #include "lisp.h"
 #include "w32term.h"
 #include "frame.h"
@@ -157,8 +159,8 @@ typedef BOOL (WINAPI * TrackMouseEvent_Proc)
 typedef LONG (WINAPI * ImmGetCompositionString_Proc)
   (IN HIMC context, IN DWORD index, OUT LPVOID buffer, IN DWORD bufLen);
 typedef HIMC (WINAPI * ImmGetContext_Proc) (IN HWND window);
-typedef HWND (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context);
-typedef HWND (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
+typedef BOOL (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context);
+typedef BOOL (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
                                                      IN COMPOSITIONFORM *form);
 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
@@ -202,7 +204,8 @@ unsigned int msh_mousewheel = 0;
 static unsigned menu_free_timer = 0;
 
 #ifdef GLYPH_DEBUG
-static int image_cache_refcount, dpyinfo_refcount;
+static ptrdiff_t image_cache_refcount;
+static int dpyinfo_refcount;
 #endif
 
 static HWND w32_visible_system_caret_hwnd;
@@ -346,10 +349,6 @@ x_real_positions (struct frame *f, int *xptr, int *yptr)
   /* 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 = rect.left;
   *yptr = rect.top;
 }
@@ -1722,6 +1721,7 @@ x_change_tool_bar_height (struct frame *f, int height)
   int old_height = FRAME_TOOL_BAR_HEIGHT (f);
   int lines = (height + unit - 1) / unit;
   int old_text_height = FRAME_TEXT_HEIGHT (f);
+  Lisp_Object fullscreen;
 
   /* Make sure we redisplay all windows in this frame.  */
   windows_or_buffers_changed = 23;
@@ -1746,7 +1746,10 @@ x_change_tool_bar_height (struct frame *f, int height)
   f->n_tool_bar_rows = 0;
 
   adjust_frame_size (f, -1, -1,
-                    (!f->tool_bar_redisplayed_once ? 1
+                    ((!f->tool_bar_redisplayed_once
+                      && (NILP (fullscreen =
+                                get_frame_param (f, Qfullscreen))
+                          || EQ (fullscreen, Qfullwidth))) ? 1
                      : (old_height == 0 || height == 0) ? 2
                      : 4),
                     false, Qtool_bar_lines);
@@ -1759,6 +1762,50 @@ x_change_tool_bar_height (struct frame *f, int height)
     x_clear_under_internal_border (f);
 }
 
+static void
+w32_set_title_bar_text (struct frame *f, Lisp_Object name)
+{
+  if (FRAME_W32_WINDOW (f))
+    {
+      block_input ();
+#ifdef __CYGWIN__
+      GUI_FN (SetWindowText) (FRAME_W32_WINDOW (f),
+                              GUI_SDATA (GUI_ENCODE_SYSTEM (name)));
+#else
+      /* The frame's title many times shows the name of the file
+        visited in the selected window's buffer, so it makes sense to
+        support non-ASCII characters outside of the current system
+        codepage in the title.  */
+      if (w32_unicode_filenames)
+       {
+         Lisp_Object encoded_title = ENCODE_UTF_8 (name);
+         wchar_t *title_w;
+         int tlen = pMultiByteToWideChar (CP_UTF8, 0, SSDATA (encoded_title),
+                                          -1, NULL, 0);
+
+         if (tlen > 0)
+           {
+             /* Windows truncates the title text beyond what fits on
+                a single line, so we can limit the length to some
+                reasonably large value, and use alloca.  */
+             if (tlen > 10000)
+               tlen = 10000;
+             title_w = alloca ((tlen + 1) * sizeof (wchar_t));
+             pMultiByteToWideChar (CP_UTF8, 0, SSDATA (encoded_title), -1,
+                                   title_w, tlen);
+             title_w[tlen] = L'\0';
+             SetWindowTextW (FRAME_W32_WINDOW (f), title_w);
+           }
+         else  /* Conversion to UTF-16 failed, so we punt.  */
+           SetWindowTextA (FRAME_W32_WINDOW (f),
+                           SSDATA (ENCODE_SYSTEM (name)));
+       }
+      else
+       SetWindowTextA (FRAME_W32_WINDOW (f), SSDATA (ENCODE_SYSTEM (name)));
+#endif
+      unblock_input ();
+    }
+}
 
 /* Change the name of frame F to NAME.  If NAME is nil, set F's name to
        w32_id_name.
@@ -1812,13 +1859,7 @@ x_set_name (struct frame *f, Lisp_Object name, bool explicit)
   if (! NILP (f->title))
     name = f->title;
 
-  if (FRAME_W32_WINDOW (f))
-    {
-      block_input ();
-      GUI_FN (SetWindowText) (FRAME_W32_WINDOW (f),
-                              GUI_SDATA (GUI_ENCODE_SYSTEM (name)));
-      unblock_input ();
-    }
+  w32_set_title_bar_text (f, name);
 }
 
 /* This function should be called when the user's lisp code has
@@ -1856,13 +1897,7 @@ x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
   if (NILP (name))
     name = f->name;
 
-  if (FRAME_W32_WINDOW (f))
-    {
-      block_input ();
-      GUI_FN (SetWindowText) (FRAME_W32_WINDOW (f),
-                              GUI_SDATA (GUI_ENCODE_SYSTEM (name)));
-      unblock_input ();
-    }
+  w32_set_title_bar_text (f, name);
 }
 
 void
@@ -3259,12 +3294,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             field being reset to nil.  */
          f = x_window_to_frame (dpyinfo, hwnd);
          if (!(f && FRAME_LIVE_P (f)))
-           break;
+           goto dflt;
          w = XWINDOW (FRAME_SELECTED_WINDOW (f));
          /* Punt if someone changed the frame's selected window
             behind our back. */
          if (w != w32_system_caret_window)
-           break;
+           goto dflt;
 
          form.dwStyle = CFS_RECT;
          form.ptCurrentPos.x = w32_system_caret_x;
@@ -3282,16 +3317,22 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
          /* Punt if the window was deleted behind our back.  */
          if (!BUFFERP (w->contents))
-           break;
+           goto dflt;
 
          context = get_ime_context_fn (hwnd);
 
          if (!context)
-           break;
+           goto dflt;
 
          set_ime_composition_window_fn (context, &form);
          release_ime_context_fn (hwnd, context);
        }
+      /* We should "goto dflt" here to pass WM_IME_STARTCOMPOSITION to
+        DefWindowProc, so that the composition window will actually
+        be displayed.  But doing so causes trouble with displaying
+        dialog boxes, such as the file selection dialog or font
+        selection dialog.  So something else is needed to fix the
+        former without breaking the latter.  See bug#11732.  */
       break;
 
     case WM_IME_ENDCOMPOSITION:
@@ -4636,8 +4677,6 @@ This function is an internal primitive--use `make-frame' instead.  */)
                       "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
   x_default_parameter (f, parameters, Qtitle, Qnil,
                       "title", "Title", RES_TYPE_STRING);
-  x_default_parameter (f, parameters, Qfullscreen, Qnil,
-                      "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
 
   f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
   f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
@@ -4696,6 +4735,12 @@ This function is an internal primitive--use `make-frame' instead.  */)
   x_wm_set_size_hint (f, window_prompting, false);
   unblock_input ();
 
+  /* Process fullscreen parameter here in the hope that normalizing a
+     fullheight/fullwidth frame will produce the size set by the last
+     adjust_frame_size call.  */
+  x_default_parameter (f, parameters, Qfullscreen, Qnil,
+                      "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
+
   /* Make the window appear on the frame and enable display, unless
      the caller says not to.  However, with explicit parent, Emacs
      cannot control visibility, so don't try.  */
@@ -5636,7 +5681,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   ptrdiff_t count = SPECPDL_INDEX ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
-  int face_change_count_before = face_change_count;
+  bool face_change_before = face_change;
   Lisp_Object buffer;
   struct buffer *old_buffer;
 
@@ -5800,7 +5845,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   SET_FRAME_COLS (f, 0);
   SET_FRAME_LINES (f, 0);
   adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f),
-                    height * FRAME_LINE_HEIGHT (f), 0, true, Qnil);
+                    height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame);
 
   /* Add `tooltip' frame parameter's default value. */
   if (NILP (Fframe_parameter (frame, Qtooltip)))
@@ -5848,11 +5893,11 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   f->can_x_set_window_size = true;
 
   /* Setting attributes of faces of the tooltip frame from resources
-     and similar will increment face_change_count, which leads to the
+     and similar will set face_change, which leads to the
      clearing of all current matrices.  Since this isn't necessary
-     here, avoid it by resetting face_change_count to the value it
+     here, avoid it by resetting face_change to the value it
      had before we created the tip frame.  */
-  face_change_count = face_change_count_before;
+  face_change = face_change_before;
 
   /* Discard the unwind_protect.  */
   return unbind_to (count, frame);
@@ -6996,7 +7041,28 @@ a ShowWindow flag:
 
 #else  /* !CYGWIN */
 
-  current_dir = ENCODE_FILE (current_dir);
+  const char file_url_str[] = "file:///";
+  const int file_url_len = sizeof (file_url_str) - 1;
+  if (strncmp (SSDATA (document), file_url_str, file_url_len) == 0)
+    {
+      /* Passing "file:///" URLs to ShellExecute causes shlwapi.dll to
+        start a thread in some rare system configurations, for
+        unknown reasons.  That thread is started in the context of
+        the Emacs process, but out of control of our code, and seems
+        to never exit afterwards.  Each such thread reserves 8MB of
+        stack space (because that's the value recorded in the Emacs
+        executable at link time: Emacs needs a large stack).  So a
+        large enough number of invocations of w32-shell-execute can
+        potentially cause the Emacs process to run out of available
+        address space, which is nasty.  To work around this, we
+        convert such URLs to local file names, which seems to prevent
+        those threads from starting.  See bug #20220.  */
+      char *p = SSDATA (document) + file_url_len;
+
+      if (c_isalpha (*p) && p[1] == ':' && IS_DIRECTORY_SEP (p[2]))
+       document = Fsubstring_no_properties (document,
+                                            make_number (file_url_len), Qnil);
+    }
   /* We have a situation here.  If DOCUMENT is a relative file name,
      but its name includes leading directories, i.e. it lives not in
      CURRENT_DIR, but in its subdirectory, then ShellExecute below
@@ -7029,6 +7095,8 @@ a ShowWindow flag:
   else
     document = ENCODE_FILE (document);
   UNGCPRO;
+
+  current_dir = ENCODE_FILE (current_dir);
   if (use_unicode)
     {
       wchar_t document_w[MAX_PATH], current_dir_w[MAX_PATH];
@@ -7468,13 +7536,13 @@ elements (all size values are in pixels).
 
 - `title-bar-height' is the height of the title bar of FRAME.
 
-- `menu-bar-external' if `t' means the menu bar is by default external
+- `menu-bar-external' if t means the menu bar is by default external
   (not included in the inner size of FRAME).
 
 - `menu-bar-size' is a cons of the width and height of the menu bar of
   FRAME.
 
-- `tool-bar-external' if `t' means the tool bar is by default external
+- `tool-bar-external' if t means the tool bar is by default external
   (not included in the inner size of FRAME).
 
 - `tool-bar-side' tells tells on which side the tool bar on FRAME is by
@@ -7526,7 +7594,7 @@ elements (all size values are in pixels).
     menu_bar_height = single_bar_height;
 
   return
-    listn (CONSTYPE_PURE, 10,
+    listn (CONSTYPE_HEAP, 10,
           Fcons (Qframe_position,
                  Fcons (make_number (frame_outer_edges.left),
                         make_number (frame_outer_edges.top))),
@@ -8200,6 +8268,15 @@ w32_sys_ring_bell (struct frame *f)
     MessageBeep (sound_type);
 }
 
+DEFUN ("w32--menu-bar-in-use", Fw32__menu_bar_in_use, Sw32__menu_bar_in_use,
+       0, 0, 0,
+       doc: /* Return non-nil when a menu-bar menu is being used.
+Internal use only.  */)
+  (void)
+{
+  return menubar_in_use ? Qt : Qnil;
+}
+
 \f
 /***********************************************************************
                            Initialization
@@ -8271,6 +8348,14 @@ syms_of_w32fns (void)
   DEFSYM (Qworkarea, "workarea");
   DEFSYM (Qmm_size, "mm-size");
   DEFSYM (Qframes, "frames");
+  DEFSYM (Qtip_frame, "tip-frame");
+  DEFSYM (Qunicode_sip, "unicode-sip");
+
+  /* Symbols used elsewhere, but only in MS-Windows-specific code.  */
+  DEFSYM (Qgnutls_dll, "gnutls");
+  DEFSYM (Qlibxml2_dll, "libxml2");
+  DEFSYM (Qserif, "serif");
+  DEFSYM (Qzlib_dll, "zlib");
 
   Fput (Qundefined_color, Qerror_conditions,
        listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));
@@ -8577,6 +8662,7 @@ only be necessary if the default setting causes problems.  */);
   defsubr (&Sw32_frame_rect);
   defsubr (&Sw32_frame_menu_bar_size);
   defsubr (&Sw32_battery_status);
+  defsubr (&Sw32__menu_bar_in_use);
 
 #ifdef WINDOWSNT
   defsubr (&Sfile_system_info);