Subject: bug#14180: closed (Re: bug#14180: PATCH Better fullscreen frame support on Windows)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 20 Apr 2013 07:42:03 +0000

Your bug report

#14180: PATCH Better fullscreen frame support on Windows

which was filed against the emacs,w32 package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
14180: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14180
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#14180: PATCH Better fullscreen frame support on Windows
From: Eli Zaretskii <[email-masked]>
To: Erik Charlebois <[email-masked]>
Cc: [email-masked]
Date: Sat, 20 Apr 2013 10:36:55 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

> Date: Fri, 19 Apr 2013 20:42:43 -0400
> From: Erik Charlebois <[email-masked]>
> Cc: [email-masked]
> 
> The assignment should be on file now.

Indeed, it is.  Therefore, I committed your changes as trunk revision
112337.

A few comments on your ChangeLog entries (for the future; I fixed all
of the issues mentioned below):

  . We have a separate ChangeLog in src, so the file names should not
    include "src/".

  . The entries for different files should be separated by an empty
    line.

  . Each non-empty line should begin with a TAB.

  . You forgot to describe the changes in w32term.h.

FYI, here are the log entries I committed in your name:

  2013-04-20  Erik Charlebois  <[email-masked]>

	  * w32fns.c (w32_fullscreen_rect): New function to compute the
	  window rectangle for the given fullscreen mode.
	  (w32_wnd_proc): When in a fullscreen mode, WM_WINDOWPOSCHANGING no
	  longer tunes the window size.  This keeps the window's edges flush
	  with the screen and allows the taskbar to hide itself in fullboth.

	  * w32term.c (w32fullscreen_hook): 'fullboth' now shows without
	  window decorations and uses the entire screen.

	  * w32term.h  (w32_fullscreen_rect) Add prototype.
	  (struct w32_output): Replace normal_width, normal_height,
	  normal_top, and normal_left members with a single normal_placement
	  struct.
	  (FRAME_NORMAL_WIDTH, FRAME_NORMAL_HEIGHT, FRAME_NORMAL_TOP):
	  Remove macros.
	  (FRAME_NORMAL_PLACEMENT): New macro.

Thanks again for working on this.

I'm marking this bug as done.

Subject: PATCH Better fullscreen frame support on Windows
From: Erik Charlebois <[email-masked]>
To: [email-masked]
Date: Thu, 11 Apr 2013 00:59:54 -0400
List-Id: <debbugs-submit.debbugs.gnu.org>

Description

This change improves the 'fullscreen' frame support on Windows. When going
to
fullscreen, the frame gets fullscreened with no window decorations (which
causes the
Windows task bar to also disappear) on the nearest monitor.

The old fullscreen functionality was actually 'maximize' behavior so I've
moved that to
'maximize'. 'fullwidth' and 'fullheight' are now ignored because they were
buggy (at least in
Windows 8, they were not being sized correctly) and are not common Windows
idioms.
While they could be supported, I'd do it as follow on work and get it
working right on
multiple monitors as well.

I've tested corner cases such as resolution changes and disconnect
monitors; in both
cases the fullscreen window stays fullscreen (and moves to a different
monitor for the
disconnect case).

I've modified the response to WM_WINDOWPOSCHANGED to do nothing when the
frame is fullscreen. Otherwise, the size gets tuned to a multiple of the
character cells and
the fullscreen isn't perfectly matching the screen. When this happens,
Windows' special
behavior to hide the taskbar doesn't kick in.

Changelog

2013-04-11  Erik Charlebois  <[email-masked]>

* src/w32fns.c (monitor_from_window_fn): New Windows API import.
(w32_monitor_rect): New function to get nearest monitor rect.
* src/w32term.c (w32_fullscreen_hook): Renamed from w32fullscreen_hook
for consistency. Rewritten for improved fullscreen support.

(I signed the FSF copyright assignment papers in January so I'm ok on that
front.)
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [email-masked]\
#   o9fs13w6mjs5p1ox
# target_branch: file:///C:/Users/Erik/Source/emacs/trunk/
# testament_sha1: fb9276945e45ab5295c446c677d869c181d0d03d
# timestamp: 2013-04-11 00:34:28 -0400
# base_revision_id: [email-masked]
# 
# Begin patch
=== modified file 'src/w32fns.c'
--- src/w32fns.c	2013-04-07 04:41:19 +0000
+++ src/w32fns.c	2013-04-11 04:22:32 +0000
@@ -157,6 +157,8 @@
 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
   (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
+typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
+  (IN HWND hwnd, IN DWORD dwFlags);
 
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
@@ -165,6 +167,7 @@
 ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;
 MonitorFromPoint_Proc monitor_from_point_fn = NULL;
 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
+MonitorFromWindow_Proc monitor_from_window_fn = NULL;
 
 #ifdef NTGUI_UNICODE
 #define unicode_append_menu AppendMenuW
@@ -336,6 +339,34 @@
   *yptr = rect.top;
 }
 
+void
+w32_monitor_rect (struct frame *f, RECT *rect)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+  if (f)
+    {
+      /* If multiple monitor support is available, make the window
+         fullscreen on the appropriate screen. */
+      if (monitor_from_window_fn && get_monitor_info_fn)
+        {
+          HWND hwnd = FRAME_W32_WINDOW (f);
+          struct MONITOR_INFO mi = { sizeof(mi) };
+          HMONITOR monitor =
+            monitor_from_window_fn (hwnd, MONITOR_DEFAULT_TO_NEAREST);
+          get_monitor_info_fn (monitor, &mi);
+          *rect = mi.rcMonitor;
+        }
+      else
+        {
+          rect->left = 0;
+          rect->right = GetSystemMetrics (SM_CXSCREEN);
+          rect->top = 0;
+          rect->bottom = GetSystemMetrics (SM_CYSCREEN);
+        }
+    }
+#endif
+}
+
 
 
 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
@@ -3691,6 +3722,10 @@
       /* Don't restrict the sizing of tip frames.  */
       if (hwnd == tip_window)
 	return 0;
+
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f && FRAME_PREV_FSMODE (f) == FULLSCREEN_BOTH)
+        return 0;
       {
 	WINDOWPLACEMENT wp;
 	LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
@@ -3838,9 +3873,13 @@
 
     case WM_EMACS_SETWINDOWPOS:
       {
-	WINDOWPOS * pos = (WINDOWPOS *) wParam;
-	return SetWindowPos (hwnd, pos->hwndInsertAfter,
-			     pos->x, pos->y, pos->cx, pos->cy, pos->flags);
+        f = x_window_to_frame (dpyinfo, hwnd);
+        if (!f || FRAME_PREV_FSMODE (f) != FULLSCREEN_BOTH)
+          {
+            WINDOWPOS * pos = (WINDOWPOS *) wParam;
+            return SetWindowPos (hwnd, pos->hwndInsertAfter,
+                                 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
+          }
       }
 
     case WM_EMACS_DESTROYWINDOW:
@@ -7635,6 +7674,8 @@
     GetProcAddress (user32_lib, "MonitorFromPoint");
   get_monitor_info_fn = (GetMonitorInfo_Proc)
     GetProcAddress (user32_lib, "GetMonitorInfoA");
+  monitor_from_window_fn = (MonitorFromWindow_Proc)
+    GetProcAddress (user32_lib, "MonitorFromWindow");
 
   {
     HMODULE imm32_lib = GetModuleHandle ("imm32.dll");

=== modified file 'src/w32term.c'
--- src/w32term.c	2013-04-01 07:58:04 +0000
+++ src/w32term.c	2013-04-11 04:22:32 +0000
@@ -237,7 +237,7 @@
 #endif
 static void my_set_foreground_window (HWND);
 static void my_destroy_window (struct frame *, HWND);
-static void w32fullscreen_hook (FRAME_PTR);
+static void w32_fullscreen_hook (FRAME_PTR);
 
 #ifdef GLYPH_DEBUG
 static void x_check_font (struct frame *, struct font *);
@@ -4720,7 +4720,7 @@
 		 sets the WAIT flag.  */
 	      if ((msg.msg.message == WM_WINDOWPOSCHANGED || msg.msg.wParam)
 		  && (f->want_fullscreen & FULLSCREEN_WAIT))
-		w32fullscreen_hook (f);
+		w32_fullscreen_hook (f);
 	      x_check_fullscreen (f);
 	    }
 	  check_visibility = 1;
@@ -5659,92 +5659,63 @@
 }
 
 static void
-w32fullscreen_hook (FRAME_PTR f)
+w32_fullscreen_hook (FRAME_PTR f)
 {
   if (FRAME_VISIBLE_P (f))
     {
-      int width, height, top_pos, left_pos, pixel_height, pixel_width;
-      int cur_w = FRAME_COLS (f), cur_h = FRAME_LINES (f);
-      RECT workarea_rect;
+      HWND hwnd = FRAME_W32_WINDOW(f);
+      DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE);
+      MONITORINFO mi = { sizeof(mi) };
+      int prev_fsmode = FRAME_PREV_FSMODE (f);
 
       block_input ();
-      /* Record current "normal" dimensions for restoring later.  */
-      if (!(   FRAME_PREV_FSMODE (f) == FULLSCREEN_BOTH
-	    || FRAME_PREV_FSMODE (f) == FULLSCREEN_MAXIMIZED))
-	{
-	  if (FRAME_PREV_FSMODE (f) != FULLSCREEN_HEIGHT)
-	    {
-	      FRAME_NORMAL_HEIGHT (f) = cur_h;
-	      FRAME_NORMAL_TOP (f) = f->top_pos;
-	    }
-	  if (FRAME_PREV_FSMODE (f) != FULLSCREEN_WIDTH)
-	    {
-	      FRAME_NORMAL_WIDTH (f)  = cur_w;
-	      FRAME_NORMAL_LEFT (f) = f->left_pos;
-	    }
-	}
-      eassert (FRAME_NORMAL_HEIGHT (f) > 0);
-      eassert (FRAME_NORMAL_WIDTH (f) > 0);
-      x_real_positions (f, &f->left_pos, &f->top_pos);
-      x_fullscreen_adjust (f, &width, &height, &top_pos, &left_pos);
-
-      SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
-      pixel_height = workarea_rect.bottom - workarea_rect.top;
-      pixel_width  = workarea_rect.right  - workarea_rect.left;
-      /* Need to send SC_RESTORE to the window, in case we are
-	 resizing from FULLSCREEN_MAXIMIZED.  Otherwise, the mouse
-	 resize hints will not be shown by the window manager when the
-	 mouse pointer hovers over the window edges, because the WM
-	 will still think the window is maximized.  */
-      if (f->want_fullscreen != FULLSCREEN_BOTH)
-	SendMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_RESTORE, 0);
 
       FRAME_PREV_FSMODE (f) = f->want_fullscreen;
       switch (f->want_fullscreen)
 	{
 	case FULLSCREEN_BOTH:
-	  PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+          if (prev_fsmode == FULLSCREEN_MAXIMIZED)
+            SendMessage (hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+
+          if (prev_fsmode != FULLSCREEN_BOTH)
+            GetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
+
+          RECT rect;
+          w32_monitor_rect (f, &rect);
+          SetWindowLong (hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
+
+          SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
+                        rect.right - rect.left, rect.bottom - rect.top,
+                        SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
 	  break;
 	case FULLSCREEN_MAXIMIZED:
-	  height =
-	    FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixel_height)
-	    - XINT (Ftool_bar_lines_needed (selected_frame))
-	    + (NILP (Vmenu_bar_mode) ? 1 : 0);
-	  width  =
-	    FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixel_width)
-	    - FRAME_SCROLL_BAR_COLS (f);
-	  left_pos = workarea_rect.left;
-	  top_pos = workarea_rect.top;
+          if (prev_fsmode == FULLSCREEN_BOTH)
+            {
+              SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
+              SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
+              SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
+                           SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+                           SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
+            }
+
+          PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
 	  break;
 	case FULLSCREEN_WIDTH:
-	  width  =
-	    FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixel_width)
-	    - FRAME_SCROLL_BAR_COLS (f);
-	  height = FRAME_NORMAL_HEIGHT (f);
-	  left_pos = workarea_rect.left;
-	  break;
 	case FULLSCREEN_HEIGHT:
-	  height =
-	    FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixel_height)
-	    - XINT (Ftool_bar_lines_needed (selected_frame))
-	    + (NILP (Vmenu_bar_mode) ? 1 : 0);
-	  width = FRAME_NORMAL_WIDTH (f);
-	  top_pos = workarea_rect.top;
-	  break;
 	case FULLSCREEN_NONE:
-	  height = FRAME_NORMAL_HEIGHT (f);
-	  width = FRAME_NORMAL_WIDTH (f);
-	  left_pos = FRAME_NORMAL_LEFT (f);
-	  top_pos = FRAME_NORMAL_TOP (f);
+          if (prev_fsmode == FULLSCREEN_BOTH)
+            {
+              SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
+              SetWindowPlacement (hwnd, &FRAME_NORMAL_PLACEMENT (f));
+              SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
+                           SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+                           SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
+            }
+          else if (prev_fsmode == FULLSCREEN_MAXIMIZED)
+            SendMessage (hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
 	  break;
 	}
 
-      if (cur_w != width || cur_h != height)
-	{
-	  x_set_offset (f, left_pos, top_pos, 1);
-	  x_set_window_size (f, 1, width, height);
-	  do_pending_window_change (0);
-	}
       f->want_fullscreen = FULLSCREEN_NONE;
       unblock_input ();
     }
@@ -6439,7 +6410,7 @@
   terminal->mouse_position_hook = w32_mouse_position;
   terminal->frame_rehighlight_hook = w32_frame_rehighlight;
   terminal->frame_raise_lower_hook = w32_frame_raise_lower;
-  terminal->fullscreen_hook = w32fullscreen_hook;
+  terminal->fullscreen_hook = w32_fullscreen_hook;
   terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
   terminal->condemn_scroll_bars_hook = w32_condemn_scroll_bars;
   terminal->redeem_scroll_bar_hook = w32_redeem_scroll_bar;

=== modified file 'src/w32term.h'
--- src/w32term.h	2013-04-07 04:41:19 +0000
+++ src/w32term.h	2013-04-11 04:22:32 +0000
@@ -71,6 +71,7 @@
 };
 
 extern void w32_regenerate_palette (struct frame *f);
+extern void w32_monitor_rect (struct frame *f, RECT *rect);
 
 
 /* For each display (currently only one on w32), we have a structure that
@@ -362,7 +363,7 @@
   /* Frame geometry and full-screen mode before it was resized by
      specifying the 'fullscreen' frame parameter.  Used to restore the
      geometry when 'fullscreen' is reset to nil.  */
-  int normal_width, normal_height, normal_top, normal_left;
+  WINDOWPLACEMENT normal_placement;
   int prev_fsmode;
 };
 
@@ -396,11 +397,8 @@
 #define FRAME_SMALLEST_FONT_HEIGHT(F) \
      FRAME_W32_DISPLAY_INFO(F)->smallest_font_height
 
-#define FRAME_NORMAL_WIDTH(F)  ((F)->output_data.w32->normal_width)
-#define FRAME_NORMAL_HEIGHT(F) ((F)->output_data.w32->normal_height)
-#define FRAME_NORMAL_TOP(F)    ((F)->output_data.w32->normal_top)
-#define FRAME_NORMAL_LEFT(F)   ((F)->output_data.w32->normal_left)
-#define FRAME_PREV_FSMODE(F)   ((F)->output_data.w32->prev_fsmode)
+#define FRAME_NORMAL_PLACEMENT(F) ((F)->output_data.w32->normal_placement)
+#define FRAME_PREV_FSMODE(F)      ((F)->output_data.w32->prev_fsmode)
 
 
 /* W32-specific scroll bar stuff.  */

# Begin bundle