diff --git a/.gitignore b/.gitignore index 60a79cb..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +0,0 @@ -bin\ -*.dll diff --git a/README.md b/README.md index d839f71..0136e8f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ Solution: ## Configuration -**I will start by saying that the solution is pretty hacky.** The plugin consists of two ``*.dll`` files. GVim removes plugin from memory just after using it, so we need two plugins: @@ -32,63 +31,92 @@ GVim removes plugin from memory just after using it, so we need two plugins: itself from memory after Gvim closes **Repository provides you with precompiled dll libraries -for 32b and 64b system. But you need to change the name -of the files when copying into GVim installation directory.** +for 32bit and 64bit systems (located in lib/x86 and lib/x64).** -Both dll libraries need to be placed in GVim installation directory. -The default installation directory (for 64 bit system) is: -``C:\Program Files\vim\vim80`` +These dll's live in the lib directory of the package itself. No need to +copy them elsewhere! -Then we need to put those lines in our vimrc: +## Installation -```vim - " GVim settings only - if has("gui_running") +**Pathogen** +``` +IF NOT EXIST %HOMEPATH%\vimfiles\bundle mkdir %HOMEPATH%\vimfiles\bundle +cd %HOMEPATH%\vimfiles\bundle +git clone https://github.com/azzoam/FixGVimBorder.git +``` - "FixGVimBorder - if $VIM_FULLSCREEN_DLL_FIX - " dll already loaded, do nothing - else - " load the dll fix +Other Vim package managers should work fine, but I have not tested +all of them. - " auto detects background color and uses it on the border - " this works most of the time - "autocmd GUIEnter * call libcall("loadfixgvimborder.dll", "LoadFixGVimBorder", 0) +Once installed, all we need is to put these lines in our vimrc: - " permanent solution - setup border color by hand using hex format - " this is recomended solution - autocmd GUIEnter * call libcall("loadfixgvimborder.dll", "LoadFixGVimBorder", "#002B36") - let $VIM_FULLSCREEN_DLL_FIX = 1 - endif +```vim +execute pathogen#infect() +if has('gui_running') + " ... + colorscheme SOME_COLOR_SCHEME + " ... +endif - endif +call fixGVimBorder#auto() ``` +`fixGVimBorder#auto()` will do all the work to autodetect your background +color, load the dll patches, and fill in GVim's borders with the background +color. It also autodetects whether to center the screen or not to +ensure compatibility with scrollbars and menus. -**The plugin can be loaded only in GVim section.** +Please **NOTE** that the only requirement for the placement of `call fixGVimBorder#auto()` +is **after** `execute pathogen#infect()` and setting of the colorscheme. -**If you put it inside console vim then it may crasch the program.** +`fixGVimBorder#auto()` can be called either inside or outside of the +`has('gui_running')` block, it does not matter. In console Vim the code does nothing. -**The plugin can be loaded only ONCE after GVim startup!** +## Customization -**NOTE** that the recommeded use sets an environment variable -`$VIM_FULLSCREEN_DLL_FIX` to 1 when the dll loads, which prevents -the dll from being reloaded if you reload your vimrc in the same session. +The vimrc above will autodetect your background color and fill the screen +border with it. If you experience issues, or wish to specificy the color +yourself, simply pass a hex color to fixGVimBorder like below. -Reloading the plugin a second time may cause memory leaks and glitches -(not tested). +```vim +call fixGVimBorder#auto("#FF0000") +``` +or +```vim +call fixGVimBorder#withColor("#FF0000") +``` -If plugin doesn't work try loading it using ``echo`` instead of ``call`` -command to see if there are any detected errors: +If plugin doesn't work try the following in your vimrc to see if there are +any detected errors: ```vim - " GVim settings only - if has("gui_running") - " use echo instead of call to see returned message - autocmd GUIEnter * echo libcall("loadfixgvimborder.dll", "LoadFixGVimBorder", 0) - endif +call fixGVimBorder#printErrors() ``` +## Centering + +The patch can either center the VimText area or not. Centering looks +better on GVim with no menu or scrollbars present, but interferes with +several elements -- see "Scrollbar and other GUI elements issues" + +The user-facing functions can either autodetect which should occur, +or allow you to specify them yourself. + +**Autodetect centering:** +* `fixGVimBorder#auto()` +* `fixGVimBorder#withColor()` +* `fixGVimBorder#printErrors()` + +**Force centering:** +* `fixGVimBorder#center()` +* `fixGVimBorder#withColorCenter()` +* `fixGVimBorder#printErrorsCenter()` + +**Force no centering:** +* `fixGVimBorder#noCenter()` +* `fixGVimBorder#withColorNoCenter()` +* `fixGVimBorder#printErrorsNoCenter()` + # Known problems There are situations not handled by this plugin: @@ -103,7 +131,7 @@ Because the plugin tries to center the vim text area it may interfere with GUI. The well know problem is scroll bar. If you have any problems with GUI elements when using the plugin load it using -`LoadFixGVimBorderWithoutAutocentering` function instead of `LoadFixGVimBorder`. +the force no centering functions insead. # Thanks diff --git a/autoload/fixGVimBorder.vim b/autoload/fixGVimBorder.vim new file mode 100644 index 0000000..d0a36e8 --- /dev/null +++ b/autoload/fixGVimBorder.vim @@ -0,0 +1,223 @@ + +function! fixGVimBorder#auto(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + if &go =~ "m" || &go =~ "T" || &go =~ "r" || &go =~ "L" + call fixGVimBorder#noCenter(border_color) + else + call fixGVimBorder#center(border_color) + endif + + endif + +endfunction + +function! fixGVimBorder#center(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + call s:fixGVimBorder(border_color, 1, 0) + + endif + +endfunction + +function! fixGVimBorder#noCenter(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + call s:fixGVimBorder(border_color, 0, 0) + + endif + +endfunction + +function! fixGVimBorder#withColor(border_color) + + if has("gui_running") + + call fixGVimBorder#auto(a:border_color) + + endif + +endfunction + +function! fixGVimBorder#withColorCenter(border_color) + + if has("gui_running") + + call fixGVimBorder#center(a:border_color) + + endif + +endfunction + +function! fixGVimBorder#withColorNoCenter(border_color) + + if has("gui_running") + + call fixGVimBorder#noCenter(a:border_color) + + endif + +endfunction + +function! fixGVimBorder#printErrors(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + if &go =~ "m" || &go =~ "T" || &go =~ "r" || &go =~ "L" + call fixGVimBorder#printErrorsNoCenter(border_color) + else + call fixGVimBorder#printErrorsCenter(border_color) + endif + + endif + +endfunction + +function! fixGVimBorder#printErrorsCenter(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + call s:fixGVimBorder(border_color, 1, 1) + + endif + +endfunction + +function! fixGVimBorder#printErrorsNoCenter(...) + + if has("gui_running") + + if a:0 == 0 + let border_color = synIDattr(synIDtrans(hlID("Normal")), "bg", "gui") + elseif a:0 == 1 + let border_color = a:1 + else + " TODO(alex): handle this error + return 0 + endif + + call s:fixGVimBorder(border_color, 0, 1) + + endif + +endfunction + + +function! DLLIsInstalled(lib_path) + + let dll_installed = len(split(globpath(&rtp, a:lib_path), '\n')) + + return dll_installed && 1 + +endfunction + + +function! s:fixGVimBorder(border_color, auto_center, debug_mode) + + if !exists("g:gvim_border_fixed") + " load the dll fix + + if has("win32") + " Fix for Windows + call s:Win32Fix(a:border_color, a:auto_center, a:debug_mode) + else + " TODO(alex): add support for linux and macos here + + endif + + let g:gvim_border_fixed = 1 + else + " dll already loaded, do nothing + endif + +endfunction + +function! s:Win32Fix(border_color, auto_center, debug_mode) + + let first_lib_path = "lib/x86/loadfixgvimborder.dll" + let second_lib_path = "lib/x86/fixgvimborder.dll" + if has("win64") + let first_lib_path = "lib/x64/loadfixgvimborder.dll" + let second_lib_path = "lib/x64/fixgvimborder.dll" + endif + + if DLLIsInstalled(first_lib_path) && DLLIsInstalled(second_lib_path) + let $GVIM_BORDER_FIX_DLL_PATH = split(globpath(&rtp, first_lib_path))[0] + if a:debug_mode + if a:auto_center + let $GVIM_BORDER_COL = a:border_color + autocmd GUIEnter * echom libcall($GVIM_BORDER_FIX_DLL_PATH, "LoadFixGVimBorder", $GVIM_BORDER_COL) + else + let $GVIM_BORDER_COL = a:border_color + autocmd GUIEnter * echom libcall($GVIM_BORDER_FIX_DLL_PATH, "LoadFixGVimBorderWithoutAutocentering", $GVIM_BORDER_COL) + endif + else + if a:auto_center + let $GVIM_BORDER_COL = a:border_color + autocmd GUIEnter * call libcall($GVIM_BORDER_FIX_DLL_PATH, "LoadFixGVimBorder", $GVIM_BORDER_COL) + else + let $GVIM_BORDER_COL = a:border_color + autocmd GUIEnter * call libcall($GVIM_BORDER_FIX_DLL_PATH, "LoadFixGVimBorderWithoutAutocentering", $GVIM_BORDER_COL) + endif + endif + else + " TODO(alex): handle dll not installed error + return 0 + endif + +endfunction + + + + + + diff --git a/build.bat b/build.bat index 30db5fe..9ad73ab 100644 --- a/build.bat +++ b/build.bat @@ -1,17 +1,23 @@ -if "%1"=="32" ( - call initBuild32b.bat -) else ( - call initBuild64b.bat -) +@echo off + +REM set vcvarsall to wherever vcvarsall.bat is located +set vcvarsall="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" -REM cleanup before compilation -call clean.bat >nul 2>&1 +IF "%1"=="32" ( + set build32="YES" + set build64="NO" +) ELSE ( + set build32="NO" + set build64="YES" +) REM create necessary folders -if not exist ".\bin" mkdir ".\bin" +if not exist ".\lib" mkdir ".\lib" +if not exist ".\lib\x86" mkdir ".\lib\x86" +if not exist ".\lib\x64" mkdir ".\lib\x64" REM set params -set params=/LD /Fo: .\bin\ /Fd: .\bin\ /EHsc /W4 /WX /Oy /O2 +set params=/LD /Fo: .\lib\ /Fd: .\lib\ /EHsc /W4 /WX /Oy /O2 REM params explanation (hashed out are not ussed): REM /LD - create .dll library @@ -26,30 +32,25 @@ REM # /Zi - additional informations for compiler REM /Oy - maximum optimizations REM /O2 - maximize speed +IF %build32%=="YES" ( + REM 32-bit compile + call %vcvarsall% x86 + cl %params% /Fe: .\lib\x86\fixgvimborder.dll .\src\fixgvimborder.c user32.lib Gdi32.lib + cl %params% /Fe: .\lib\x86\loadfixgvimborder.dll .\src\loadfixgvimborder.c user32.lib -REM compile -%compiler% %params% /Fe: .\bin\fixgvimborder.dll fixgvimborder.c user32.lib Gdi32.lib -%compiler% %params% /Fe: .\bin\loadfixgvimborder.dll loadfixgvimborder.c user32.lib - -REM if no errors then copy files to the vim directory -if NOT ERRORLEVEL 1 ( - echo. - - copy /Y bin\fixgvimborder.dll "C:\Program Files\vim\vim80" - copy /Y bin\loadfixgvimborder.dll "C:\Program Files\vim\vim80" - - copy /Y bin\fixgvimborder.dll . - copy /Y bin\loadfixgvimborder.dll . + del .\lib\x86\*exp + del .\lib\x86\*lib +) - if "%1"=="32" ( - copy /Y bin\fixgvimborder.dll fixgvimborder32.dll - copy /Y bin\loadfixgvimborder.dll loadfixgvimborder32.dll - ) else ( - copy /Y bin\fixgvimborder.dll fixgvimborder64.dll - copy /Y bin\loadfixgvimborder.dll loadfixgvimborder64.dll - ) +IF %build64%=="YES" ( + REM 64-bit compile + call %vcvarsall% x64 + cl %params% /Fe: .\lib\x64\fixgvimborder.dll .\src\fixgvimborder.c user32.lib Gdi32.lib + cl %params% /Fe: .\lib\x64\loadfixgvimborder.dll .\src\loadfixgvimborder.c user32.lib - REM cleanup after successfull compilation - call clean.bat >nul 2>&1 + del .\lib\x64\*exp + del .\lib\x64\*lib ) +del .\lib\*obj + diff --git a/clean.bat b/clean.bat deleted file mode 100644 index c87d247..0000000 --- a/clean.bat +++ /dev/null @@ -1,2 +0,0 @@ -del /S /Q bin -rmdir bin diff --git a/fixgvimborder32.dll b/fixgvimborder32.dll deleted file mode 100644 index 5a4133f..0000000 Binary files a/fixgvimborder32.dll and /dev/null differ diff --git a/fixgvimborder64.dll b/fixgvimborder64.dll deleted file mode 100644 index 5c6d8c4..0000000 Binary files a/fixgvimborder64.dll and /dev/null differ diff --git a/initBuild32b.bat b/initBuild32b.bat deleted file mode 100644 index 6961010..0000000 --- a/initBuild32b.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -REM PATH TO THE VISUAL STUDIO TOOLS -set compilerTools32b=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin - -REM path to compiler -set compiler="%compilerTools32b%\cl.exe" - -REM set up environment -call "%compilerTools32b%\vcvars32.bat" - diff --git a/initBuild64b.bat b/initBuild64b.bat deleted file mode 100644 index dff72e6..0000000 --- a/initBuild64b.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -REM PATH TO THE VISUAL STUDIO TOOLS -set compilerTools64b=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64 - -REM path to compiler -set compiler="%compilerTools64b%\cl.exe" - -REM set up environment -call "%compilerTools64b%\vcvars64.bat" - diff --git a/lib/x64/fixgvimborder.dll b/lib/x64/fixgvimborder.dll new file mode 100644 index 0000000..6134507 Binary files /dev/null and b/lib/x64/fixgvimborder.dll differ diff --git a/lib/x64/loadfixgvimborder.dll b/lib/x64/loadfixgvimborder.dll new file mode 100644 index 0000000..b822a8c Binary files /dev/null and b/lib/x64/loadfixgvimborder.dll differ diff --git a/lib/x86/fixgvimborder.dll b/lib/x86/fixgvimborder.dll new file mode 100644 index 0000000..ace4f32 Binary files /dev/null and b/lib/x86/fixgvimborder.dll differ diff --git a/lib/x86/loadfixgvimborder.dll b/lib/x86/loadfixgvimborder.dll new file mode 100644 index 0000000..78b1bba Binary files /dev/null and b/lib/x86/loadfixgvimborder.dll differ diff --git a/loadfixgvimborder32.dll b/loadfixgvimborder32.dll deleted file mode 100644 index 5929a68..0000000 Binary files a/loadfixgvimborder32.dll and /dev/null differ diff --git a/loadfixgvimborder64.dll b/loadfixgvimborder64.dll deleted file mode 100644 index 58beb23..0000000 Binary files a/loadfixgvimborder64.dll and /dev/null differ diff --git a/common.h b/src/common.h similarity index 100% rename from common.h rename to src/common.h diff --git a/fixgvimborder.c b/src/fixgvimborder.c similarity index 85% rename from fixgvimborder.c rename to src/fixgvimborder.c index 1b78447..eabb016 100644 --- a/fixgvimborder.c +++ b/src/fixgvimborder.c @@ -1,13 +1,16 @@ #include #include "common.h" +// NOTE(alex): Autodetection of color is now handled via +// vimscript exclusively. All c code for this has been +// deleted to reflect this change. Autodetection of color +// is now stable. static WNDPROC _originalWndProc = NULL; static HINSTANCE _module = NULL; static HWND _mainWindow = NULL; static HWND _vimTextArea = NULL; static CHAR classNameBuffer[BUFFER_SIZE]; -static BOOL _autoDetectBaseColor = TRUE; static BOOL _hasEdgesProblem = FALSE; static COLORREF _baseColor = RGB(255, 0, 0); static BOOL _enableCentering = TRUE; @@ -19,7 +22,6 @@ LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lPara // replaces GVim WinProc event loop LPTSTR _declspec(dllexport) InitFixBorderHook( HINSTANCE module, - BOOL autoDetectBaseColor, COLORREF baseColor, BOOL enableCentering) { @@ -29,7 +31,6 @@ LPTSTR _declspec(dllexport) InitFixBorderHook( // we will use it to clear ourselves from memory // on GVim window close or on error _module = module; - _autoDetectBaseColor = autoDetectBaseColor; _baseColor = baseColor; _enableCentering = enableCentering; @@ -121,7 +122,7 @@ LRESULT CALLBACK SubclassWndProc( RECT rc; GetClientRect(hwnd, &rc); - // fill whole client are to obtain background color + // fill whole client area to obtain background color HBRUSH hb = CreateSolidBrush(_baseColor); FillRect(hdc, &ps.rcPaint, hb); @@ -129,12 +130,23 @@ LRESULT CALLBACK SubclassWndProc( EndPaint(hwnd, &ps); } + // NOTE(alex): + // Bug fix -- White border reappearing on minimize/maximize -- + // Maximize is handled via the WM_SIZE message. Handling the + // event explicitly ourselves and posting a WM_PAINT message via + // RedrawWindow before handing it off to the default window proc + // restores the desired behavior. + if (wm == WM_SIZE && wParam == SIZE_MAXIMIZED && hwnd == _mainWindow) { + RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW | RDW_NOCHILDREN); + } + // call default GVim WinProc LRESULT result = CallWindowProc(_originalWndProc, hwnd, wm, wParam, lParam); // center Vim TextArea in the whole window if (wm == WM_SIZE) { + RECT mainRc; GetClientRect(hwnd, &mainRc); int mainWidth = mainRc.right - mainRc.left; @@ -162,13 +174,6 @@ LRESULT CALLBACK SubclassWndProc( TRUE); } - // try to autodetect base color using pixel from right bottom corne - if (_autoDetectBaseColor && _hasEdgesProblem) - { - HDC hdc = GetDC(_vimTextArea); - _baseColor = GetPixel(hdc, textRc.right - 10, textRc.bottom - 10); - ReleaseDC(_vimTextArea, hdc); - } } // return original result from original GVim WinProc diff --git a/loadfixgvimborder.c b/src/loadfixgvimborder.c similarity index 58% rename from loadfixgvimborder.c rename to src/loadfixgvimborder.c index 1ad768e..617fd33 100644 --- a/loadfixgvimborder.c +++ b/src/loadfixgvimborder.c @@ -1,7 +1,12 @@ #include +#include #include "common.h" -typedef LPTSTR (*MYINTPROCSTR)(HINSTANCE, BOOL, COLORREF, BOOL); +// NOTE(alex): Autodetection of color is now handled via +// vimscript exclusively. All c code for this has been +// deleted to reflect this change. Autodetection of color +// is now stable. +typedef LPTSTR (*MYINTPROCSTR)(HINSTANCE, COLORREF, BOOL); static CHAR _resultBuffer[BUFFER_SIZE]; LPTSTR load(char* color, BOOL enableCentering); @@ -23,11 +28,9 @@ LPTSTR _declspec(dllexport) LoadFixGVimBorderWithoutAutocentering(char* color) LPTSTR load(char* color, BOOL enableCentering) { // parse color - BOOL autoDetectBaseColor = TRUE; COLORREF baseColor = RGB(0, 0, 0); if (color != NULL) { - autoDetectBaseColor = FALSE; int len = lstrlen(color); // expecting #RRGGBB so 7 chars @@ -71,14 +74,57 @@ LPTSTR load(char* color, BOOL enableCentering) 16*colorInts[5] + colorInts[6]); } + + // NOTE(alex): + // Automatic determination of fixgvimborder.dll path + // based on the path of loadfixgvimborder.dll. Allows + // the dll's to be installed elsewhere on disk on not + // limited to Gvim's install directory. + HMODULE this_dll_handle = GetModuleHandle("loadfixgvimborder"); + char this_dll_path[MAX_PATH]; + GetModuleFileNameA(this_dll_handle, this_dll_path, sizeof(this_dll_path)); + + // TODO(alex): + // Maybe find a cleaner/more reliable way to find the + // base path? The following works for now. + // BEGIN SLIGHTLY JANKY CODE + char *letter = this_dll_path; + char *last_slash = this_dll_path; + while (*letter != 0) { + if (*letter == '\\') { + last_slash = letter; + } + letter++; + } + + char base_path[MAX_PATH]; + letter = this_dll_path; + int i = 0; + while (letter < last_slash) { + base_path[i] = *letter; + letter++; + i++; + } + + base_path[i] = '\0'; + // END SLIGHTLY JANKY CODE + + char load_dll_path[MAX_PATH]; + if (strcpy_s(load_dll_path, sizeof(load_dll_path), base_path)) { + return GetLastErrorAsStringMessage( + "Failed to build fixgvimborder.dll path."); + } + if (strcat_s(load_dll_path, sizeof(load_dll_path), "\\fixgvimborder.dll\0")) { + return GetLastErrorAsStringMessage( + "Failed to build fixgvimborder.dll path."); + } + + // load main library - HINSTANCE module = LoadLibraryEx( - "FixGVimBorder", - NULL, - LOAD_LIBRARY_SEARCH_APPLICATION_DIR); + HINSTANCE module = LoadLibraryA(load_dll_path); if (module == NULL) - return GetLastErrorAsStringMessage("failed to load FixGVimBorder.dll"); + return GetLastErrorAsStringMessage("failed to load fixgvimborder.dll"); // find initialize function MYINTPROCSTR initFunction = (MYINTPROCSTR)GetProcAddress( @@ -94,7 +140,6 @@ LPTSTR load(char* color, BOOL enableCentering) // call initialize function LPTSTR initResult = ((MYINTPROCSTR)initFunction)( module, - autoDetectBaseColor, baseColor, enableCentering);