├── data └── screenshot.gif ├── Makefile ├── README.md ├── plugin └── particle.vim └── particle.c /data/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/vim-particle/HEAD/data/screenshot.gif -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all : particle.exe 2 | 3 | particle.exe : particle.c 4 | gcc -Wall -Werror -o particle.exe -mwindows particle.c -lgdi32 5 | 6 | clean : 7 | rm particle.exe 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-particle 2 | 3 | ![](https://raw.githubusercontent.com/mattn/vim-particle/master/data/screenshot.gif) 4 | 5 | ## Usage 6 | 7 | ```vim 8 | :ParticleOn 9 | ``` 10 | 11 | ## Requirements 12 | 13 | Windows! 14 | 15 | ## Installation 16 | 17 | ``` 18 | mingw32-make 19 | ``` 20 | 21 | ## License 22 | 23 | MIT 24 | 25 | ## Author 26 | 27 | Yasuhiro Matsumoto (a.k.a mattn) 28 | -------------------------------------------------------------------------------- /plugin/particle.vim: -------------------------------------------------------------------------------- 1 | let s:exe = fnamemodify(expand(':h:h') . '\particle.exe', ':p') 2 | 3 | let s:seed = 0 4 | function! s:srand(seed) abort 5 | let s:seed = a:seed 6 | endfunction 7 | 8 | function! s:rand() abort 9 | let s:seed = s:seed * 214013 + 2531011 10 | return (s:seed < 0 ? s:seed - 0x80000000 : s:seed) / 0x10000 % 0x8000 11 | endfunction 12 | 13 | call s:srand(localtime()) 14 | 15 | let s:ctb = [ 16 | \ '000000', 'aa0000', '00aa00', '0000aa', 'aa5500', 'aa00aa', '00aaaa', 'aaaaaa', 17 | \ '555555', 'ff5555', '55ff55', 'ffff55', '5555ff', 'ff55ff', '55ffff', 'ffffff' 18 | \] 19 | let [s:oldx, s:oldy] = [0, 0] 20 | function! s:particle() 21 | let [x, y] = [getwinposx(), getwinposy()] 22 | let x += (abs(s:rand()) % 11 - 5) 23 | let y += (abs(s:rand()) % 11 - 5) 24 | exe 'winpos' x y 25 | let c = synIDattr(synIDtrans(synID(line("."), col(".")-1, 1)), "fg") 26 | if c =~ '^#' 27 | let c = c[1:] 28 | elseif c =~ '^[0-9]\+$' 29 | let c = s:ctb[c] 30 | else 31 | let c = 'ffffff' 32 | endif 33 | 34 | let [x, y] = [screencol(), screenrow()] 35 | if x == 10000 || y == 10000 36 | let [x, y] = [s:oldx, s:oldy] 37 | endif 38 | "silent exe "!start" printf("%s %d,%d,%d,%d,%d %s", s:exe, v:windowid, x, y, &columns, &lines, c) 39 | let s:job = job_start(['cmd', '/c', printf("start %s %d,%d,%d,%d,%d %s", s:exe, v:windowid, x, y, &columns, &lines, c)]) 40 | let [s:oldx, s:oldy] = [x, y] 41 | endfunction 42 | 43 | function! s:install(flag) 44 | augroup ParticleVim 45 | au! 46 | if a:flag 47 | au TextChangedI * call s:particle() 48 | endif 49 | augroup END 50 | endfunction 51 | 52 | command! -nargs=0 ParticleOn call install(1) 53 | command! -nargs=0 ParticleOff call install(0) 54 | -------------------------------------------------------------------------------- /particle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | HWND hwnd; 7 | int x; 8 | int y; 9 | int dx; 10 | int dy; 11 | } particle; 12 | 13 | static particle p[4] = {0}; 14 | static HBRUSH hb = NULL; 15 | 16 | LRESULT CALLBACK 17 | WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 18 | HDC hdc = NULL; 19 | RECT rc = {0}; 20 | PAINTSTRUCT ps; 21 | 22 | switch (uMsg) { 23 | case WM_PAINT: 24 | hdc = BeginPaint(hwnd, &ps); 25 | GetClientRect(hwnd, &rc); 26 | FillRect(hdc, &rc, hb); 27 | EndPaint(hwnd, &ps); 28 | return 0; 29 | case WM_DESTROY: 30 | PostQuitMessage(0); 31 | return 0; 32 | default: 33 | break; 34 | } 35 | return DefWindowProc(hwnd, uMsg, wParam, lParam); 36 | } 37 | 38 | void CALLBACK 39 | UpdateProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { 40 | int i; 41 | for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) { 42 | p[i].x += p[i].dx; 43 | p[i].y += p[i].dy; 44 | p[i].dy += 2; 45 | if (p[i].dy >= 30) { 46 | DestroyWindow(p[i].hwnd); 47 | break; 48 | } 49 | SetWindowPos(p[i].hwnd, NULL, p[i].x, p[i].y, 0, 0, 50 | SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER); 51 | } 52 | } 53 | 54 | int WINAPI 55 | WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow) { 56 | TCHAR app[] = TEXT("particle"); 57 | MSG msg; 58 | WNDCLASSEX wc; 59 | int i; 60 | int exit_code = 1; 61 | int argc; 62 | LPWSTR *argv; 63 | int r = 0xff, g = 0xff, b = 0xff; 64 | RECT rc = {0}; 65 | POINT pt = {200, 200}; 66 | HWND hwnd; 67 | int w = 0, h = 0; 68 | wchar_t *pos = NULL; 69 | HRGN hrgn; 70 | 71 | srand((unsigned)time(NULL)); 72 | 73 | argv = CommandLineToArgvW(GetCommandLineW(), &argc); 74 | 75 | if (argc >= 2) { 76 | pos = wcschr(argv[1], ','); 77 | if (pos) *pos++ = 0; 78 | hwnd = (HWND) _wtoi64(argv[1]); 79 | } 80 | if (hwnd == NULL) hwnd = GetForegroundWindow(); 81 | 82 | if (pos && swscanf(pos, L"%d,%d,%d,%d", &pt.x, &pt.y, &w, &h) == 4) { 83 | GetWindowRect(hwnd, &rc); 84 | pt.x = (rc.right - rc.left) / w * pt.x; 85 | pt.y = (rc.bottom - rc.top) / h * pt.y; 86 | ClientToScreen(hwnd, &pt); 87 | } else { 88 | if (GetWindowRect(hwnd, &rc)) { 89 | pt.x = (rc.left + rc.right) / 2 + rand() % 200 - 100; 90 | pt.y = (rc.top + rc.bottom) / 2 + rand() % 200 - 100; 91 | ClientToScreen(hwnd, &pt); 92 | } 93 | } 94 | 95 | if (argc >= 3) { 96 | swscanf(argv[2], L"%02x%02x%02x", &r, &g, &b); 97 | } else { 98 | r = rand() % 256; 99 | g = rand() % 256; 100 | b = rand() % 256; 101 | } 102 | 103 | wc.cbSize = sizeof(WNDCLASSEX); 104 | wc.style = 0; 105 | wc.lpfnWndProc = WindowProc; 106 | wc.cbClsExtra = 0; 107 | wc.cbWndExtra = 0; 108 | wc.hInstance = hinst; 109 | wc.hIcon = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED); 110 | wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); 111 | wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 112 | wc.lpszMenuName = NULL; 113 | wc.lpszClassName = app; 114 | wc.hIconSm = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED); 115 | if (!RegisterClassEx(&wc)) goto leave; 116 | 117 | hb = CreateSolidBrush(RGB(r, g, b)); 118 | for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) { 119 | p[i].hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_NOACTIVATE, 120 | app, app, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 121 | 10, 10, NULL, NULL, hinst, NULL); 122 | if (p[i].hwnd == NULL) goto leave; 123 | SetLayeredWindowAttributes(p[i].hwnd, RGB(0xFF, 0xFF, 0xFF), 70, LWA_ALPHA); 124 | 125 | p[i].x = pt.x; 126 | p[i].y = pt.y; 127 | p[i].dx = (rand() % 10) - 5; 128 | p[i].dy = -10 - (rand() % 10); 129 | 130 | hrgn = CreateEllipticRgn(0, 0, 10, 10); 131 | if (hrgn != NULL) 132 | SetWindowRgn(p[i].hwnd, hrgn, TRUE); 133 | ShowWindow(p[i].hwnd, nCmdShow); 134 | UpdateWindow(p[i].hwnd); 135 | } 136 | SetTimer(NULL, 0, 1, UpdateProc); 137 | while (GetMessage(&msg, NULL, 0, 0) > 0) { 138 | TranslateMessage(&msg); 139 | DispatchMessage(&msg); 140 | } 141 | exit_code = (int)msg.wParam; 142 | 143 | leave: 144 | if (argv) LocalFree(argv); 145 | return exit_code; 146 | } 147 | 148 | /* vim:set et sw=2: */ 149 | --------------------------------------------------------------------------------