Merge pull request #14 from chaosddp/master

add defos.toggle_maximize, defos.is_maximize
master
Chaos Yu 2017-05-11 22:23:59 +08:00 committed by GitHub
commit c9ee8af20c
1 changed files with 111 additions and 63 deletions

View File

@ -11,10 +11,20 @@ according to the document, we do not need to load user32.dll manually:
local C = ffi.C
if ffi.os == "Windows" then
local GWL_STYLE = -16
local WS_POPUP = 0x80000000
local WS_CAPTION = 0x00C00000
local WS_SYSMENU = 0x00080000
local WS_SIZEBOX = 0x00040000
local WS_MAXIMIZEBOX = 0x00010000
local WS_MINIMIZEBOX = 0x00020000
local SWP_NOZORDER = 0x0004
local SW_MAXIMIZE = 3
-- add definitions here,
-- to make it clear and avoid re-define exception (for struct) when calling a method more than 1 time
ffi.cdef([[
typedef long LONG;
typedef int BOOL;
typedef unsigned long DWORD;
@ -32,7 +42,7 @@ if ffi.os == "Windows" then
typedef HANDLE HWND;
typedef HICON HCURSOR;
typedef BYTE BCHAR;
static const int CCHDEVICENAME = 32;
static const int CCHFORMNAME = 32;
@ -49,7 +59,7 @@ if ffi.os == "Windows" then
LONG x;
LONG y;
} POINT, *PPOINT, *NPPOINT, *LPPOINT;
typedef struct _POINTL
{
LONG x;
@ -75,7 +85,7 @@ if ffi.os == "Windows" then
HCURSOR hCursor;
POINT ptScreenPos;
} CURSORINFO, *PCURSORINFO, *LPCURSORINFO;
typedef struct _devicemode {
BCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
@ -98,7 +108,7 @@ if ffi.os == "Windows" then
DWORD dmDisplayOrientation;
DWORD dmDisplayFixedOutput;
};
short dmColor;
short dmDuplex;
short dmYResolution;
@ -123,8 +133,17 @@ if ffi.os == "Windows" then
DWORD dmPanningWidth;
DWORD dmPanningHeight;
} DEVMODE, *PDEVMODE;
typedef struct tagWINDOWPLACEMENT {
UINT length;
UINT flags;
UINT showCmd;
POINT ptMinPosition;
POINT ptMaxPosition;
RECT rcNormalPosition;
} WINDOWPLACEMENT, *PWINDOWPLACEMENT, *LPWINDOWPLACEMENT;
int GetSystemMetrics(int nIndex);
@ -151,8 +170,14 @@ if ffi.os == "Windows" then
BOOL GetMonitorInfoW(HMONITOR hMonitor, LPMONITORINFO lpmi);
BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint);
HWND GetDesktopWindow(void);
BOOL GetWindowPlacement(HWND hWnd, WINDOWPLACEMENT *lpwndpl);
BOOL SetWindowPlacement(HWND hWnd,const WINDOWPLACEMENT *lpwndpl);
BOOL ShowWindow(HWND hWnd,int nCmdShow);
]])
@ -189,8 +214,6 @@ if ffi.os == "Windows" then
-- @usage set_window_style(bit.band(bit.bnot(WS_MAXIMIZEBOX), bit.bnot(WS_MINIMIZEBOX))) or set_window_style(bit.bnot(WS_SIZEBOX))
-- @return true if success to change style, or false
local function set_window_style(style)
local GWL_STYLE = -16
local ptr = C.GetActiveWindow()
local value = C.GetWindowLongPtrA(ptr, GWL_STYLE)
@ -202,12 +225,12 @@ if ffi.os == "Windows" then
local function get_monitor_info()
--https://blogs.msdn.microsoft.com/oldnewthing/20050505-04/?p=35703/
local MONITOR_DEFAULTTONULL = 0x00000000 -- Returns NULL.
local MONITOR_DEFAULTTOPRIMARY = 0x00000001 -- Returns a handle to the primary display monitor.
--local MONITOR_DEFAULTTONULL = 0x00000000 -- Returns NULL.
--local MONITOR_DEFAULTTOPRIMARY = 0x00000001 -- Returns a handle to the primary display monitor.
local MONITOR_DEFAULTTONEAREST = 0x00000002 -- Returns a handle to the display monitor that is nearest to the window.
local hwnd = C.GetActiveWindow()
local monitor = C.MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
local monitor = C.MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
local mi = ffi.new("MONITORINFO")
mi.cbSize = ffi.sizeof("MONITORINFO")
@ -217,10 +240,53 @@ if ffi.os == "Windows" then
return (success and mi) or nil
end
-- https://github.com/glfw/glfw-legacy/tree/master/lib
-- https://github.com/luapower/winapi/blob/master/winapi/window.lua
--http://www.glfw.org/GLFWReference27.pdf
function M.get_mouse_pos()
-- Retrieves the show state and the restored, minimized, and maximized positions of window.
-- @return WINDOWPLACEMENT if success, or nil
local function get_window_placement(hwnd)
local placement = ffi.new("WINDOWPLACEMENT")
placement.length = ffi.sizeof("WINDOWPLACEMENT")
local successed = C.GetWindowPlacement(hwnd, placement)
return (successed > 0 and placement) or nil
end
-- set the window placement, always used to restore window state
local function set_window_placement(hwnd, placement)
if hwnd and placement then
C.SetWindowPlacement(hwnd, placement)
end
end
local is_maximize = false
local is_fullscreen = false;
local previous_state = {style = nil, placement=nil}
function M.is_maximize()
return is_maximize
end
function M.toggle_maximize()
if is_fullscreen then
M.toggle_fullscreen()
end
local hwnd = C.GetActiveWindow()
if is_maximize then
set_window_placement(hwnd, previous_state.placement)
is_maximize = false
else
previous_state.placement = get_window_placement(hwnd)
C.ShowWindow(hwnd, SW_MAXIMIZE)
is_maximize = true
end
end
-- https://github.com/glfw/glfw-legacy/tree/master/lib
-- https://github.com/luapower/winapi/blob/master/winapi/window.lua
--http://www.glfw.org/GLFWReference27.pdf
function M.get_mouse_pos()
-- definitions
--ffi.cdef[[
@ -238,69 +304,57 @@ function M.get_mouse_pos()
return {x = pci.ptScreenPos.x, y = pci.ptScreenPos.y}
end
local is_fullscreen = false;
local previous_state = {style = nil, rect = nil}
function M.is_fullscreen()
return is_fullscreen
end
function M.toggle_fullscreen()
-- TODO: shall we move const to out to make it re-usable?
local GWL_STYLE = -16
local WS_POPUP = 0x80000000
local WS_CAPTION = 0x00C00000
local WS_SYSMENU = 0x00080000
local WS_MINIMIZEBOX = 0x00020000
local WS_MAXIMIZEBOX = 0x00010000
local SWP_NOZORDER = 0x0004
if is_maximize then
-- if itis maximized, then we need to restore it then toggle fullscreen
M.toggle_maximize()
end
local hwnd = C.GetActiveWindow()
if not is_fullscreen then
-- first remember current style and rect
local prect = ffi.new("RECT")
C.GetWindowRect(hwnd, prect)
-- TODO: exception handle?
previous_state.rect = prect
previous_state.style = C.GetWindowLongPtrA(hwnd, GWL_STYLE)
previous_state.placement = get_window_placement(hwnd)
-- get desktop rect, or we can use get_monitor_info?
local rc = ffi.new("RECT")
local dhwnd = C.GetDesktopWindow() -- get desktop handle, or we can use get_monitor_info
C.GetWindowRect(dhwnd, rc) -- get desktop rect
local windowed_fullscreen_style = bit.band(bit.bnot(WS_CAPTION), bit.bnot(WS_SYSMENU), bit.bnot(WS_MINIMIZEBOX), bit.bnot(WS_MAXIMIZEBOX))
local dhwnd = C.GetDesktopWindow()
C.GetWindowRect(dhwnd, rc)
-- for fullscreen, we remove these styles
local windowed_fullscreen_style = bit.band(
bit.bnot(WS_CAPTION),
bit.bnot(WS_SYSMENU),
bit.bnot(WS_MINIMIZEBOX),
bit.bnot(WS_MAXIMIZEBOX),
bit.bnot(WS_SIZEBOX))
if set_window_style(windowed_fullscreen_style) then
if C.SetWindowPos(hwnd, nil, 0, 0, rc.right, rc.bottom, SWP_NOZORDER) then
if C.SetWindowPos(hwnd, nil, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER) then
-- we are in fullscreen mode
is_fullscreen = true
end
end
else
-- TODO: exception handle?
-- restore the style
-- restore the style and position/size
C.SetWindowLongPtrA(hwnd, GWL_STYLE, previous_state.style)
C.SetWindowPos(hwnd,
nil,
previous_state.rect.left,
previous_state.rect.top,
previous_state.rect.right - previous_state.rect.left,
previous_state.rect.bottom - previous_state.rect.top,
SWP_NOZORDER)
set_window_placement(hwnd, previous_state.placement)
is_fullscreen = false
end
end
function M.set_window_size(pos_x, pos_y, width, height)
local HWND_TOP = 0
local SWP_NOMOVE = 0x0002
local SWP_NOZORDER = 0x0004
--local HWND_TOP = 0
--local SWP_NOMOVE = 0x0002
--local SWP_NOZORDER = 0x0004
local SM_CXSCREEN = 0
local SM_CYSCREEN = 1
@ -327,22 +381,16 @@ function M.get_mouse_pos()
function M.disable_window_resize()
local WS_SIZEBOX = 0x00040000
set_window_style(bit.bnot(WS_SIZEBOX))
end
function M.disable_maximize_button()
local WS_MAXIMIZEBOX = 0x00010000
set_window_style(bit.bnot(WS_MAXIMIZEBOX))
end
function M.disable_minimize_button()
local WS_MINIMIZEBOX = 0x00020000
set_window_style(bit.bnot(WS_MINIMIZEBOX))
end