bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#13053: PATCH: Fullscreen frame support on Windows


From: Erik Charlebois
Subject: bug#13053: PATCH: Fullscreen frame support on Windows
Date: Sat, 1 Dec 2012 21:57:54 -0500

I've kept this patch going for a few years; probably time I get it in for real. I have not signed the FSF copyright assignment. If someone could give me some guidance on that (I'm Canadian), I'd appreciate it.

This patch adds fullscreen frame support to Windows so that setting the frame parameter 'fullscreen to 'fullboth makes the frame take up the entire screen, with no window decoration and covering the taskbar. The function:

(defun toggle-fullscreen ()
  "Toggle full screen on X11"
  (interactive)
  (set-frame-parameter
   nil 'fullscreen
   (when (not (frame-parameter nil 'fullscreen)) 'fullboth)))

now has the same behavior on X11 and Windows. There's a bit of added complexity to support multiple monitors and resolution changes correctly.



2012-12-01  Erik Charlebois  <erikcharlebois@gmail.com>

        * src/w32fns.c: Add w32_set_fullscreen for switching to
        fullscreen. Handle WM_DISPLAYCHANGE for changes in resolution
        and monitor configuration. Handle frame-parameter 'fullscreen
        changes by possibly going to fullscreen.
        * src/w32term.h: Add state to w32_output for tracking monitor
        and window placement.
        * src/w32term.c: Use w32_set_fullscreen for fullscreen_hook.




=== modified file 'src/w32fns.c'
*** src/w32fns.c 2012-11-21 04:47:55 +0000
--- src/w32fns.c 2012-12-01 23:11:52 +0000
*************** typedef HWND (WINAPI * ImmSetComposition
*** 162,167 ****
--- 162,173 ----
  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);
+ 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;
  ImmGetCompositionString_Proc get_composition_string_fn = NULL;
*************** ImmReleaseContext_Proc release_ime_conte
*** 170,175 ****
--- 176,183 ----
  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;
+ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
  
  #ifdef NTGUI_UNICODE
  #define unicode_append_menu AppendMenuW
*************** x_real_positions (FRAME_PTR f, int *xptr
*** 372,377 ****
--- 380,454 ----
    *yptr = rect.top;
  }
  
+ void
+ w32_set_fullscreen (struct frame *f)
+ {
+ #ifdef HAVE_WINDOW_SYSTEM
+   if (f)
+     {
+       HWND hwnd = FRAME_W32_WINDOW (f);
+       if (f->want_fullscreen != FULLSCREEN_BOTH
+           && f->output_data.w32->fullscreen)
+         {
+           /* Restore the window style and placement. */
+           f->output_data.w32->fullscreen = 0;
+           if (f->output_data.w32->window_placement.showCmd == SW_HIDE)
+             {
+               SetWindowLong (hwnd, GWL_STYLE,
+                   f->output_data.w32->dwStyle | WS_CLIPCHILDREN);
+               SetWindowPos (hwnd, HWND_TOP, 30, 30, 640, 480,
+                   SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+             }
+           else
+             {
+               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 if (f->want_fullscreen == FULLSCREEN_BOTH
+                && !f->output_data.w32->fullscreen)
+         {
+           /* 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
+ }
 
  
  DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
*************** post_character_message (HWND hwnd, UINT
*** 2706,2711 ****
--- 2783,2810 ----
    my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
  }
  
+ struct w32_monitor_info
+ {
+     HMONITOR seeking;
+     int found;
+ };
+ static BOOL
+ w32_enum_monitors (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 */
  
  static LRESULT CALLBACK
*************** w32_wnd_proc (HWND hwnd, UINT msg, WPARA
*** 2763,2768 ****
--- 2862,2926 ----
     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;
+                   if (f->output_data.w32->window_placement.showCmd == SW_HIDE)
+                     {
+                       SetWindowLong (hwnd, GWL_STYLE,
+                           f->output_data.w32->dwStyle | WS_CLIPCHILDREN);
+                       SetWindowPos (hwnd, HWND_TOP, 30, 30, 640, 480,
+                           SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
+                     }
+                   else
+                     {
+                       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;
*************** w32_wnd_proc (HWND hwnd, UINT msg, WPARA
*** 3861,3869 ****
  
      case WM_EMACS_SETWINDOWPOS:
        {
! WINDOWPOS * pos = (WINDOWPOS *) wParam;
! return SetWindowPos (hwnd, pos->hwndInsertAfter,
!     pos->x, pos->y, pos->cx, pos->cy, pos->flags);
        }
  
      case WM_EMACS_DESTROYWINDOW:
--- 4019,4061 ----
  
      case WM_EMACS_SETWINDOWPOS:
        {
!         f = x_window_to_frame (dpyinfo, hwnd);
!         if (f && f->output_data.w32->fullscreen)
!           {
!             SetWindowLong (hwnd, GWL_STYLE,
!                            (  f->output_data.w32->style
!                             & (~(WS_CAPTION | WS_THICKFRAME))));
!             /* 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);
!                 return 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
!               {
!                 return 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:
*************** globals_of_w32fns (void)
*** 7685,7690 ****
--- 7877,7886 ----
      GetProcAddress (user32_lib, "MonitorFromPoint");
    get_monitor_info_fn = (GetMonitorInfo_Proc)
      GetProcAddress (user32_lib, "GetMonitorInfoA");
+   monitor_from_window_fn = (MonitorFromWindow_Proc)
+     GetProcAddress (user32_lib, "MonitorFromWindow");
+   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+     GetProcAddress (user32_lib, "EnumDisplayMonitors");
  
    {
      HMODULE imm32_lib = GetModuleHandle ("imm32.dll");

=== modified file 'src/w32term.c'
*** src/w32term.c 2012-12-01 02:38:11 +0000
--- src/w32term.c 2012-12-01 22:56:36 +0000
*************** w32_create_terminal (struct w32_display_
*** 6211,6217 ****
    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 = XTfullscreen_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;
--- 6211,6217 ----
    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 = w32_set_fullscreen;
    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 2012-11-23 15:39:48 +0000
--- src/w32term.h 2012-12-01 22:57:00 +0000
*************** struct w32_palette_entry {
*** 71,76 ****
--- 71,77 ----
  };
  
  extern void w32_regenerate_palette (struct frame *f);
+ extern void w32_set_fullscreen (struct frame *f);
  
 
  /* For each display (currently only one on w32), we have a structure that
*************** struct w32_output
*** 361,366 ****
--- 362,379 ----
    /* 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;


reply via email to

[Prev in Thread] Current Thread [Next in Thread]