all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Erik Charlebois <erikcharlebois@gmail.com>
To: 13053@debbugs.gnu.org
Subject: bug#13053: PATCH: Fullscreen frame support on Windows
Date: Sat, 1 Dec 2012 21:57:54 -0500	[thread overview]
Message-ID: <CAC+abJYC=9BqfnKeKCo+hrF1M9onOZzng9UJ-L823UFpUdWMDg@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 13849 bytes --]

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;

[-- Attachment #2: Type: text/html, Size: 20745 bytes --]

             reply	other threads:[~2012-12-02  2:57 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-02  2:57 Erik Charlebois [this message]
2012-12-02 17:38 ` bug#13053: PATCH: Fullscreen frame support on Windows Eli Zaretskii
2012-12-02 20:05   ` Glenn Morris
2012-12-03 10:17     ` Chong Yidong
2016-02-24  5:59       ` Lars Ingebrigtsen
2016-02-24 10:15         ` martin rudalics

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAC+abJYC=9BqfnKeKCo+hrF1M9onOZzng9UJ-L823UFpUdWMDg@mail.gmail.com' \
    --to=erikcharlebois@gmail.com \
    --cc=13053@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.