307 lines
9.3 KiB
Lua
307 lines
9.3 KiB
Lua
|
|
local ffi = require("ffi")
|
|
|
|
win = {}
|
|
|
|
-- --------------------------------------------------------------------------------------
|
|
-- Windows stuff
|
|
if ffi.os == "Windows" then
|
|
local shell32 = ffi.load("shell32")
|
|
|
|
-- TODO: Need equivalents for OSX and Linux - probably should go in a systems utils.
|
|
ffi.cdef[[
|
|
typedef char CHAR;
|
|
typedef uint8_t BYTE;
|
|
typedef uint32_t UINT;
|
|
typedef unsigned short WORD;
|
|
typedef unsigned long DWORD;
|
|
typedef void* HINSTANCE;
|
|
typedef void* LPARAM;
|
|
typedef const char* LPCSTR;
|
|
typedef char* LPSTR;
|
|
typedef const void * HWND;
|
|
typedef void* LPVOID;
|
|
typedef int BOOL;
|
|
|
|
typedef struct RECT {
|
|
int x, y, w, h;
|
|
} RECT;
|
|
|
|
typedef struct _ITEMIDLIST {
|
|
BYTE mkid[1];
|
|
} ITEMIDLIST, *LPITEMIDLIST;
|
|
|
|
typedef int (__stdcall *BFFCALLBACK)(HWND, UINT, LPARAM, LPARAM);
|
|
|
|
typedef struct {
|
|
HWND hwndOwner;
|
|
LPCSTR pidlRoot;
|
|
LPSTR pszDisplayName;
|
|
LPCSTR lpszTitle;
|
|
UINT ulFlags;
|
|
BFFCALLBACK lpfn;
|
|
LPARAM lParam;
|
|
int iImage;
|
|
} BROWSEINFOA;
|
|
|
|
typedef struct tagOPENFILENAMEA {
|
|
DWORD lStructSize;
|
|
HWND hwndOwner;
|
|
HINSTANCE hInstance;
|
|
LPCSTR lpstrFilter;
|
|
LPSTR lpstrCustomFilter;
|
|
DWORD nMaxCustFilter;
|
|
DWORD nFilterIndex;
|
|
LPSTR lpstrFile;
|
|
DWORD nMaxFile;
|
|
LPSTR lpstrFileTitle;
|
|
DWORD nMaxFileTitle;
|
|
LPCSTR lpstrInitialDir;
|
|
LPCSTR lpstrTitle;
|
|
DWORD Flags;
|
|
WORD nFileOffset;
|
|
WORD nFileExtension;
|
|
LPCSTR lpstrDefExt;
|
|
LPARAM lCustData;
|
|
void* lpfnHook;
|
|
LPCSTR lpTemplateName;
|
|
void* pvReserved;
|
|
DWORD dwReserved;
|
|
DWORD FlagsEx;
|
|
} OPENFILENAMEA;
|
|
|
|
bool GetOpenFileNameA(OPENFILENAMEA *ofn);
|
|
|
|
LPITEMIDLIST SHBrowseForFolderA(BROWSEINFOA *bi);
|
|
BOOL SHGetPathFromIDListA(LPITEMIDLIST pidl, LPSTR pszPath);
|
|
|
|
void Sleep(uint32_t ms);
|
|
|
|
// Get the size of screen to the variable desktop
|
|
HWND GetDesktopWindow();
|
|
int GetWindowRect(HWND hwnd, RECT *hrect);
|
|
int ShowWindow(HWND hWnd, int nCmdShow);
|
|
int SetWindowPos( HWND hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint32_t uFlags);
|
|
]]
|
|
|
|
local HWND_TOP = 0x00
|
|
|
|
local SWP_NOSIZE = 0x01
|
|
local SW_SHOWMINIMIZED = 0x02
|
|
local SW_MAXIMIZE = 0x03
|
|
|
|
local comdlg32 = ffi.load("comdlg32")
|
|
local shell32 = ffi.load("shell32")
|
|
|
|
win.ShowWindow = function(hwnd, cmd)
|
|
if(cmd == 0) then
|
|
ffi.C.ShowWindow(hwnd, SW_SHOWMINIMIZED)
|
|
else
|
|
ffi.C.ShowWindow(hwnd, SW_MAXIMIZE)
|
|
end
|
|
end
|
|
win.Sleep = ffi.C.Sleep
|
|
|
|
win.SetWindowPos = function(hwnd, x, y, w, h)
|
|
ffi.C.SetWindowPos(hwnd, HWND_TOP, x, y, w, h, 0)
|
|
end
|
|
|
|
win.DetectDisplay = function()
|
|
local desktop = ffi.new("RECT[1]")
|
|
-- Get a handle to the desktop window
|
|
local hDesktop = ffi.C.GetDesktopWindow()
|
|
ffi.C.GetWindowRect(hDesktop, desktop)
|
|
return desktop[0].w, desktop[0].h
|
|
end
|
|
|
|
win.FileSelect = function()
|
|
-- buffer for returned file path
|
|
local pathBuf = ffi.new("char[260]") -- MAX_PATH
|
|
|
|
local ofn = ffi.new("OPENFILENAMEA")
|
|
ofn.lStructSize = ffi.sizeof(ofn)
|
|
ofn.hwndOwner = nil
|
|
ofn.lpstrFilter = "All Files\0*.*\0\0" -- Double null terminated
|
|
ofn.lpstrFile = pathBuf
|
|
ofn.nMaxFile = 260
|
|
ofn.Flags = 0x00080000 + 0x00001000 -- OFN_EXPLORER + OFN_FILEMUSTEXIST
|
|
|
|
local result = comdlg32.GetOpenFileNameA(ofn)
|
|
|
|
if result then
|
|
pprint("Selected file:", ffi.string(pathBuf))
|
|
return ffi.string(pathBuf)
|
|
else
|
|
pprint("No file selected (or dialog canceled).")
|
|
return nil
|
|
end
|
|
end
|
|
|
|
win.FolderSelect = function()
|
|
|
|
local pathBuf = ffi.new("char[260]") -- MAX_PATH
|
|
local displayBuf = ffi.new("char[260]")
|
|
|
|
local bi = ffi.new("BROWSEINFOA")
|
|
bi.hwndOwner = nil
|
|
bi.pidlRoot = nil -- start at Desktop
|
|
bi.pszDisplayName = displayBuf
|
|
bi.lpszTitle = "Select a folder:"
|
|
bi.ulFlags = 0x0001 + 0x00000040 + 0x00000100
|
|
|
|
local pidl = shell32.SHBrowseForFolderA(bi)
|
|
|
|
if pidl ~= nil then
|
|
if shell32.SHGetPathFromIDListA(pidl, pathBuf) ~= 0 then
|
|
pprint("Selected folder:", ffi.string(pathBuf))
|
|
return ffi.string(pathBuf)
|
|
else
|
|
pprint("Folder picked, but path could not be retrieved.")
|
|
return nil
|
|
end
|
|
else
|
|
pprint("User canceled.")
|
|
return nil
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
-- --------------------------------------------------------------------------------------
|
|
-- Linux stuff
|
|
if ffi.os == "Linux" then
|
|
|
|
ffi.cdef[[
|
|
typedef unsigned long Colormap;
|
|
|
|
typedef struct _Screen {
|
|
int width; /* width of the screen in pixels */
|
|
int height; /* height of the screen in pixels */
|
|
int mwidth; /* width of the screen in millimeters */
|
|
int mheight; /* height of the screen in millimeters */
|
|
int root; /* the root window of the screen */
|
|
int root_depth; /* the depth of the root window */
|
|
void *root_visual; /* the root window visual */
|
|
Colormap default_colormap; /* the default colormap */
|
|
int white_pixel; /* white pixel value */
|
|
int black_pixel; /* black pixel value */
|
|
int my_num; /* screen number */
|
|
bool is_installed; /* indicates whether the screen is installed */
|
|
void *saver; /* screen saver properties (if any) */
|
|
} Screen;
|
|
|
|
typedef unsigned long Atom;
|
|
typedef unsigned long Window;
|
|
typedef struct _XDisplay Display;
|
|
typedef struct _XEvent {
|
|
union {
|
|
struct {
|
|
unsigned long window;
|
|
int type;
|
|
int format;
|
|
Atom message_type;
|
|
long data[5];
|
|
} xclient;
|
|
};
|
|
} XEvent;
|
|
|
|
void usleep(unsigned int usec);
|
|
|
|
Display* XOpenDisplay(const char* display_name);
|
|
Window XRootWindow(Display* display, int screen_number);
|
|
int XGetWindowProperty(Display* display, Window w, Atom property, long long_offset,
|
|
long long_length, int delete, Atom req_type, Atom* actual_type,
|
|
int* actual_format, unsigned long* nitems,
|
|
unsigned long* bytes_after, unsigned char** prop);
|
|
int XSendEvent(Display* display, Window w, int propagate, long event_mask, XEvent* event);
|
|
Atom XInternAtom(Display* display, const char* name, int only_if_exists);
|
|
int XCloseDisplay(Display* display);
|
|
Screen *DefaultScreenOfDisplay(Display *display);
|
|
|
|
// Constants
|
|
#define AnyPropertyType 0
|
|
]]
|
|
|
|
-- Load the X11 library
|
|
local X11 = ffi.load("X11")
|
|
|
|
win.Sleep = function(ms) ffi.C.usleep(ms * 1000) end
|
|
|
|
|
|
-- Function to maximize a window
|
|
local function maximizeWindow(win)
|
|
-- Open the display
|
|
local display = X11.XOpenDisplay(nil)
|
|
if display == nil then
|
|
error("Unable to open X display")
|
|
end
|
|
|
|
-- Create the event structure
|
|
local ev = ffi.new("XEvent[1]")
|
|
|
|
-- Set up the event for the window maximize
|
|
ev[0].xclient.window = win
|
|
ev[0].xclient.type = 33 -- ClientMessage event type
|
|
ev[0].xclient.format = 32
|
|
ev[0].xclient.message_type = X11.XInternAtom(display, "_NET_WM_STATE", 0)
|
|
ev[0].xclient.data[0] = 1 -- Set to 1 to indicate we want to add the state
|
|
ev[0].xclient.data[1] = X11.XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_HORIZ", 0)
|
|
ev[0].xclient.data[2] = X11.XInternAtom(display, "_NET_WM_STATE_MAXIMIZED_VERT", 0)
|
|
ev[0].xclient.data[3] = 1 -- 1 means "active" or "add" to the state
|
|
|
|
-- Send the event to the root window
|
|
X11.XSendEvent(display, 0, false, 0x00000008, ev) -- SubstructureNotifyMask
|
|
X11.XCloseDisplay(display)
|
|
end
|
|
|
|
-- --------------------------------------------------------------------------------------
|
|
-- TODO: ShowWindow not working properly on Linux yet
|
|
win.ShowWindow = function(hwnd, state)
|
|
-- Open the display
|
|
local display = X11.XOpenDisplay(hwnd)
|
|
if display == nil then
|
|
error("Unable to open X display")
|
|
end
|
|
|
|
-- auto display = XOpenDisplay(NULL);
|
|
-- Get the root window (or get the window ID through other methods if needed)
|
|
local root_window = X11.XRootWindow(display, 0)
|
|
|
|
-- Example usage: Get the active window and maximize it
|
|
local NET_ACTIVE_WINDOW = X11.XInternAtom(display, "_NET_ACTIVE_WINDOW", 0)
|
|
local prop = ffi.new("unsigned char*[1]")
|
|
local actual_type = ffi.new("Atom[1]")
|
|
local actual_format = ffi.new("int[1]")
|
|
local nitems = ffi.new("unsigned long[1]")
|
|
local bytes_after = ffi.new("unsigned long[1]")
|
|
|
|
-- Fetch the active window ID
|
|
local result = X11.XGetWindowProperty(display, root_window, NET_ACTIVE_WINDOW, 0, 1024, 0, 0,
|
|
actual_type, actual_format, nitems, bytes_after, prop)
|
|
|
|
if result == 0 then -- Success
|
|
-- Dereference the window ID
|
|
local window_id = ffi.cast("Window", ffi.cast("intptr_t", ffi.cast("void*", prop[0])))
|
|
|
|
-- Call the maximizeWindow function
|
|
maximizeWindow(window_id)
|
|
pprint("Window maximized successfully!")
|
|
|
|
else
|
|
pprint("Failed to fetch active window.")
|
|
end
|
|
pprint("Window resized successfully.")
|
|
end
|
|
|
|
win.DetectDisplay = function()
|
|
local display = X11.XOpenDisplay(hwnd)
|
|
if display == nil then
|
|
error("Unable to open X display")
|
|
end
|
|
local s = X11.DefaultScreenOfDisplay(display)
|
|
return s.width, s.height
|
|
end
|
|
|
|
end
|