From 3b2149319129ae1f6da41416c7206388a7ce6f76 Mon Sep 17 00:00:00 2001
From: Erik Charlebois <erikcharlebois@gmail.com>
Date: Wed, 14 Oct 2009 23:51:31 -0700
Subject: [PATCH] 2009-10-14  Erik Charlebois  <erikcharlebois@gmail.com>

    * w32fns.c: Added support for fullscreen Windows.

    * w32term.h: Added fullscreen window state.
---
 src/w32fns.c  |  178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/w32term.h |   12 ++++
 2 files changed, 187 insertions(+), 3 deletions(-)

diff --git a/src/w32fns.c b/src/w32fns.c
index 8003d79..adf4cdb 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -256,8 +256,14 @@ typedef HWND (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context);
 typedef HWND (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
 						      IN COMPOSITIONFORM *form);
 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
+typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
+  (IN HWND hwnd, IN DWORD dwFlags);
 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
   (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
+typedef BOOL (CALLBACK * MONITOR_ENUM_PROC)(HMONITOR, HDC, LPRECT, LPARAM);
+typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
+  (IN HDC hdc, IN LPCRECT lprcClip, IN MONITOR_ENUM_PROC lpfnEnum,
+   IN LPARAM dwData);
 
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ClipboardSequence_Proc clipboard_sequence_fn = NULL;
@@ -266,7 +272,9 @@ ImmGetContext_Proc get_ime_context_fn = NULL;
 ImmReleaseContext_Proc release_ime_context_fn = NULL;
 ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;
 MonitorFromPoint_Proc monitor_from_point_fn = NULL;
+MonitorFromWindow_Proc monitor_from_window_fn = NULL;
 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
+EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
 
 extern AppendMenuW_Proc unicode_append_menu;
 
@@ -472,6 +480,71 @@ x_real_positions (f, xptr, yptr)
 
 
 
+DEFUN ("w32-toggle-fullscreen-frame", Fw32_toggle_fullscreen_frame,
+       Sw32_toggle_fullscreen_frame, 1, 1, 0,
+       doc: /* Toggles the specified frame between a fullsreen and windowed
+state. */)
+     (frame)
+     Lisp_Object frame;
+{
+  FRAME_PTR f = check_x_frame(frame);
+
+#ifdef HAVE_WINDOW_SYSTEM
+  if (f)
+  {
+    HWND hwnd = FRAME_W32_WINDOW(f);
+
+    if (f->output_data.w32->fullscreen)
+    {
+      /* Restore the window style and placement. */
+      f->output_data.w32->fullscreen = 0;
+      SetWindowLong(hwnd, GWL_STYLE, f->output_data.w32->style);
+      SetWindowPlacement(hwnd, &f->output_data.w32->window_placement);
+      SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+          SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+    }
+    else
+    {
+      /* Save the window style and placement. */
+      struct MONITOR_INFO info;
+      RECT monitor_rect;
+      monitor_rect.left = 0;
+      monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
+      monitor_rect.top = 0;
+      monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
+
+      f->output_data.w32->fullscreen = 1;
+      f->output_data.w32->window_placement.length =
+          sizeof(WINDOWPLACEMENT);
+      GetWindowPlacement(hwnd, &f->output_data.w32->window_placement);
+
+      f->output_data.w32->style = GetWindowLong(hwnd, GWL_STYLE);
+      SetWindowLong(hwnd, GWL_STYLE,
+                    (  f->output_data.w32->style
+                     & (~(WS_CAPTION | WS_THICKFRAME))));
+
+      /* If multiple monitor support is available, make the window fullscreen
+         on the appropriate screen. */
+      if (monitor_from_window_fn && get_monitor_info_fn)
+      {
+        f->output_data.w32->monitor =
+            monitor_from_window_fn(hwnd, MONITOR_DEFAULT_TO_NEAREST);
+        info.cbSize = sizeof(struct MONITOR_INFO);
+        get_monitor_info_fn(f->output_data.w32->monitor, &info);
+        monitor_rect = info.rcMonitor;
+      }
+
+      SetWindowPos(FRAME_W32_WINDOW(f), HWND_TOP, monitor_rect.left,
+          monitor_rect.top, monitor_rect.right - monitor_rect.left,
+          monitor_rect.bottom - monitor_rect.top,
+          SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+    }
+  }
+#endif
+
+  return Qt;
+}
+
 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
        Sw32_define_rgb_color, 4, 4, 0,
        doc: /* Convert RGB numbers to a Windows color reference and associate with NAME.
@@ -2747,6 +2820,29 @@ post_character_message (hwnd, msg, wParam, lParam, modifiers)
   my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
 }
 
+struct w32_monitor_info
+{
+    HMONITOR seeking;
+    int found;
+};
+
+static BOOL CALLBACK
+w32_enum_monitors (hMonitor, hdcMonitor, lprcMonitor, dwData)
+    HMONITOR hMonitor;
+    HDC hdcMonitor;
+    LPRECT lprcMonitor;
+    LPARAM dwData;
+{
+    struct w32_monitor_info* minfo =
+        (struct w32_monitor_info*) dwData;
+    if (minfo->seeking == hMonitor)
+    {
+        minfo->found = 1;
+        return FALSE;
+    }
+    return TRUE;
+}
+
 /* Main window procedure */
 
 LRESULT CALLBACK
@@ -2808,6 +2904,49 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
 	    release_frame_dc (f, get_frame_dc (f));
 	}
       return 0;
+    case WM_DISPLAYCHANGE:
+      f = x_window_to_frame(dpyinfo, hwnd);
+      if (f && f->output_data.w32->fullscreen)
+      {
+        /* If multiple monitor support is available, check if the monitor
+           the window was fullscreened on still exists. If not, kick it out
+           of fullscreen and let Windows reposition it. */
+        if (monitor_from_window_fn && get_monitor_info_fn &&
+                enum_display_monitors_fn)
+        {
+          struct w32_monitor_info minfo = { f->output_data.w32->monitor, 0 };
+          enum_display_monitors_fn(NULL, NULL, w32_enum_monitors,
+              (LPARAM) &minfo);
+          if (!minfo.found)
+          {
+            f->output_data.w32->fullscreen = 0;
+            SetWindowLong(hwnd, GWL_STYLE, f->output_data.w32->style);
+            SetWindowPlacement(hwnd, &f->output_data.w32->window_placement);
+            SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+                SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+          }
+          else
+          {
+            /* The monitor still exists. Resize to fullscreen to account for
+               a possible resolution change. */
+            struct MONITOR_INFO info;
+            info.cbSize = sizeof(struct MONITOR_INFO);
+            get_monitor_info_fn(f->output_data.w32->monitor, &info);
+            SetWindowPos(hwnd, HWND_TOP, info.rcMonitor.left,
+              info.rcMonitor.top, info.rcMonitor.right - info.rcMonitor.left,
+              info.rcMonitor.bottom - info.rcMonitor.top,
+              SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+          }
+        }
+        else
+        {
+          /* Resize to fullscreen to account for resolution change. */
+          SetWindowPos(hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+              GetSystemMetrics(SM_CYSCREEN),
+              SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+        }
+      }
+      return 0;
     case WM_PAINT:
       {
   	PAINTSTRUCT paintStruct;
@@ -3886,9 +4025,37 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
 
     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 && f->output_data.w32->fullscreen)
+        {
+          /* Force the window to be fullscreen. This will cause frame
+             position and size changes to be ignored. It also keeps the
+             window correctly fullscreen when the menu or scroll bars are
+             toggled. */
+          if (monitor_from_window_fn && get_monitor_info_fn &&
+                  enum_display_monitors_fn)
+          {
+            struct MONITOR_INFO info;
+            info.cbSize = sizeof(struct MONITOR_INFO);
+            get_monitor_info_fn(f->output_data.w32->monitor, &info);
+            SetWindowPos(hwnd, HWND_TOP, info.rcMonitor.left,
+                info.rcMonitor.top, info.rcMonitor.right - info.rcMonitor.left,
+                info.rcMonitor.bottom - info.rcMonitor.top,
+                SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+          }
+          else
+          {
+            SetWindowPos(hwnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+                GetSystemMetrics(SM_CYSCREEN),
+                SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+          }
+        }
+        else
+        {
+          WINDOWPOS * pos = (WINDOWPOS *) wParam;
+          return SetWindowPos (hwnd, pos->hwndInsertAfter,
+			         pos->x, pos->y, pos->cx, pos->cy, pos->flags);
+        }
       }
 
     case WM_EMACS_DESTROYWINDOW:
@@ -7250,6 +7417,7 @@ only be necessary if the default setting causes problems.  */);
 
   /* W32 specific functions */
 
+  defsubr (&Sw32_toggle_fullscreen_frame);
   defsubr (&Sw32_define_rgb_color);
   defsubr (&Sw32_default_color_map);
   defsubr (&Sw32_send_sys_command);
@@ -7310,8 +7478,12 @@ globals_of_w32fns ()
 
   monitor_from_point_fn = (MonitorFromPoint_Proc)
     GetProcAddress (user32_lib, "MonitorFromPoint");
+  monitor_from_window_fn = (MonitorFromWindow_Proc)
+    GetProcAddress (user32_lib, "MonitorFromWindow");
   get_monitor_info_fn = (GetMonitorInfo_Proc)
     GetProcAddress (user32_lib, "GetMonitorInfoA");
+  enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+    GetProcAddress (user32_lib, "EnumDisplayMonitors");
 
   {
     HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
diff --git a/src/w32term.h b/src/w32term.h
index 8181d61..7f9ab29 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -372,6 +372,18 @@ struct w32_output
   /* The background for which the above relief GCs were set up.
      They are changed only when a different background is involved.  */
   unsigned long relief_background;
+
+  /* Nonzero means the frame is in fullscreen mode. */
+  char fullscreen;
+
+  /* Window placement prior to the frame going fullscreen. */
+  WINDOWPLACEMENT window_placement;
+
+  /* Window style in place when the frame went fullscreen. */
+  DWORD style;
+
+  /* Monitor that the frame is fullscreen on. */
+  HMONITOR monitor;
 };
 
 extern struct w32_output w32term_display;
-- 
1.6.4.msysgit.0

