/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2008 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "hdr/modern_commonheaders.h" #include "hdr/modern_clist.h" #include "m_api/m_skin_eng.h" #include "m_api/m_skinbutton.h" #include "hdr/modern_commonprototypes.h" #include "hdr/modern_sync.h" #define WM_DOCKCALLBACK (WM_USER+121) #define WM_CREATEDOCKED (WM_USER+122) #define EDGESENSITIVITY 3 #define DOCKED_NONE 0 #define DOCKED_LEFT 1 #define DOCKED_RIGHT 2 BOOL LockSubframeMoving=0; static int TempDock=0; static int dock_drag_dx=0; static int dock_drag_dy=0; static void Docking_GetMonitorRectFromPoint(POINT pt,RECT *rc) { HMODULE hUserInstance = GetModuleHandle(TEXT("user32")); if ( MyMonitorFromPoint ) { MONITORINFO monitorInfo; HMONITOR hMonitor = MyMonitorFromPoint(pt,MONITOR_DEFAULTTONEAREST); // always returns a valid value monitorInfo.cbSize = sizeof(MONITORINFO); if ( MyGetMonitorInfo(hMonitor,&monitorInfo)) { CopyMemory(rc,&monitorInfo.rcMonitor,sizeof(RECT)); return; } } // "generic" win95/NT support, also serves as failsafe rc->left = 0; rc->top = 0; rc->bottom = GetSystemMetrics(SM_CYSCREEN); rc->right = GetSystemMetrics(SM_CXSCREEN); } void Docking_GetMonitorRectFromWindow(HWND hWnd,RECT *rc) { POINT ptWindow; GetWindowRect(hWnd,rc); ptWindow.x = rc->left; ptWindow.y = rc->top; Docking_GetMonitorRectFromPoint(ptWindow,rc); } static void Docking_AdjustPosition(HWND hwnd,RECT *rcDisplay,RECT *rc) { APPBARDATA abd; ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=hwnd; abd.uEdge=g_CluiData.fDocked==DOCKED_LEFT?ABE_LEFT:ABE_RIGHT; abd.rc=*rc; abd.rc.top=rcDisplay->top; abd.rc.bottom=rcDisplay->bottom; if(g_CluiData.fDocked==DOCKED_LEFT) { abd.rc.right=rcDisplay->left+abd.rc.right-abd.rc.left; abd.rc.left=rcDisplay->left; } else { abd.rc.left=rcDisplay->right-(abd.rc.right-abd.rc.left); abd.rc.right=rcDisplay->right; } SHAppBarMessage(ABM_SETPOS,&abd); *rc=abd.rc; } int Docking_IsDocked(WPARAM wParam,LPARAM lParam) { return g_CluiData.fDocked; } int Docking_ProcessWindowMessage(WPARAM wParam,LPARAM lParam) { APPBARDATA abd; static int draggingTitle; MSG *msg=(MSG*)wParam; if(msg->message==WM_DESTROY) ModernWriteSettingByte(NULL,"CList","Docked",(BYTE)g_CluiData.fDocked); if (!g_CluiData.fDocked && msg->message!=WM_CREATE && msg->message!=WM_MOVING && msg->message!=WM_CREATEDOCKED && msg->message != WM_MOVE && msg->message != WM_SIZE) return 0; switch(msg->message) { case WM_CREATE: //if(GetSystemMetrics(SM_CMONITORS)>1) return 0; if(ModernGetSettingByte(NULL,"CList","Docked",0) && ModernGetSettingByte(NULL,"CLUI","DockToSides",SETTING_DOCKTOSIDES_DEFAULT)) { PostMessage(msg->hwnd,WM_CREATEDOCKED,0,0); } draggingTitle=0; return 0; case WM_CREATEDOCKED: //we need to post a message just after creation to let main message function do some work g_CluiData.fDocked=(BOOL)ModernGetSettingByte(NULL,"CList","Docked",0); if(IsWindowVisible(msg->hwnd) && !IsIconic(msg->hwnd)) { RECT rc, rcMonitor; ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; abd.lParam=0; abd.uCallbackMessage=WM_DOCKCALLBACK; SHAppBarMessage(ABM_NEW,&abd); GetWindowRect(msg->hwnd,&rc); Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); Docking_AdjustPosition(msg->hwnd,&rcMonitor,&rc); MoveWindow(msg->hwnd,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,TRUE); g_CluiData.mutexPreventDockMoving=0; Sync(CLUIFrames_OnMoving,msg->hwnd,&rc); g_CluiData.mutexPreventDockMoving=1; ModernSkinButton_ReposButtons( msg->hwnd, SBRF_DO_NOT_DRAW, NULL ); } break; case WM_CAPTURECHANGED: ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW,NULL); return 0; case WM_ACTIVATE: ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; SHAppBarMessage(ABM_ACTIVATE,&abd); return 0; case WM_SIZE: ModernSkinButton_ReposButtons( msg->hwnd, SBRF_DO_REDRAW_ALL, NULL ); return 0; case WM_WINDOWPOSCHANGED: { if (g_CluiData.fDocked) ModernSkinButton_ReposButtons( msg->hwnd,SBRF_DO_NOT_DRAW, NULL ); return 0; ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; SHAppBarMessage(ABM_WINDOWPOSCHANGED,&abd); ModernSkinButton_ReposButtons( msg->hwnd, SBRF_DO_NOT_DRAW, NULL ); return 0; } case WM_MOVING: { RECT rcMonitor; RECT rcWindow; RECT *rc; int dx=0; POINT ptCursor; if (g_CluiData.fDocked) return 0; // stop early BOOL bControlled = (BOOL)(GetAsyncKeyState(VK_CONTROL)&0x8000); // GetMessagePos() is no good, position is always unsigned GetCursorPos(&ptCursor); GetWindowRect(msg->hwnd,&rcWindow); dock_drag_dx=rcWindow.left-ptCursor.x; dock_drag_dy=rcWindow.top-ptCursor.y; Docking_GetMonitorRectFromPoint(ptCursor,&rcMonitor); if (((ptCursor.x=rcMonitor.right-EDGESENSITIVITY)) && ModernGetSettingByte(NULL,"CLUI","DockToSides",SETTING_DOCKTOSIDES_DEFAULT)) { ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; abd.lParam=0; abd.uCallbackMessage=WM_DOCKCALLBACK; SHAppBarMessage(ABM_NEW,&abd); if(ptCursor.xhwnd,(LPRECT)msg->lParam); rc=(RECT*)msg->lParam; if (g_CluiData.fDocked==DOCKED_RIGHT) dx=(rc->right>rcMonitor.right)?rc->right-rcMonitor.right:0; else dx=(rc->leftleft-rcMonitor.left:0; OffsetRect(rc,-dx,0); Docking_AdjustPosition(msg->hwnd,(LPRECT)&rcMonitor,(LPRECT)msg->lParam); SendMessage(msg->hwnd,WM_SIZE,0,0); g_CluiData.mutexPreventDockMoving=0; Sync(CLUIFrames_OnMoving,msg->hwnd,(LPRECT)msg->lParam); g_CluiData.mutexPreventDockMoving=1; mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0); ModernWriteSettingByte(NULL,"CList","Docked",(BYTE)g_CluiData.fDocked); ModernSkinButton_ReposButtons( msg->hwnd, SBRF_DO_NOT_DRAW, NULL ); return TRUE; } return 0; } case WM_EXITSIZEMOVE: { RECT rcMonitor; RECT rcWindow; if (TempDock) TempDock=0; GetWindowRect(msg->hwnd,&rcWindow); Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); Docking_AdjustPosition(msg->hwnd,&rcMonitor,&rcWindow); *((LRESULT*)lParam)=TRUE; g_CluiData.mutexPreventDockMoving=0; SetWindowPos(msg->hwnd,0,rcWindow.left,rcWindow.top,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOSENDCHANGING); Sync(CLUIFrames_OnMoving,msg->hwnd,&rcWindow); ModernSkinButton_ReposButtons( msg->hwnd, SBRF_DO_NOT_DRAW, NULL );//-=-=-= g_CluiData.mutexPreventDockMoving=1; return 1; } case WM_MOVE: { if(g_CluiData.fDocked && 0) { RECT rc, rcMonitor; Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); GetWindowRect(msg->hwnd,&rc); Docking_AdjustPosition(msg->hwnd,&rcMonitor,&rc); MoveWindow(msg->hwnd,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,TRUE); Sync(CLUIFrames_OnMoving,msg->hwnd,&rc); ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW, NULL);//-=-=-= return 1; } ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_ALT_DRAW, NULL); return 0; } case WM_SIZING: { /*RECT rcMonitor; Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); Docking_AdjustPosition(msg->hwnd,&rcMonitor,(LPRECT)msg->lParam); *((LRESULT*)lParam)=TRUE; */ RECT rc; if (g_CluiData.fDocked) ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW,NULL); return FALSE; rc=*(RECT*)(msg->lParam); g_CluiData.mutexPreventDockMoving=0; Sync(CLUIFrames_OnMoving,msg->hwnd,&rc); //-=-=-= return TRUE; } case WM_SHOWWINDOW: { if(msg->lParam) return 0; BOOL toBeDocked = (BOOL) ModernGetSettingByte(NULL,"CLUI","DockToSides",SETTING_DOCKTOSIDES_DEFAULT); if ((msg->wParam && g_CluiData.fDocked<0) || (!msg->wParam && g_CluiData.fDocked>0)) g_CluiData.fDocked=-g_CluiData.fDocked; ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; if(msg->wParam) { RECT rc, rcMonitor; Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); abd.lParam=0; abd.uCallbackMessage=WM_DOCKCALLBACK; SHAppBarMessage(ABM_NEW,&abd); GetWindowRect(msg->hwnd,&rc); Docking_AdjustPosition(msg->hwnd,&rcMonitor,&rc); MoveWindow(msg->hwnd,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,FALSE); Sync(CLUIFrames_OnMoving,msg->hwnd,&rc); ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW,NULL);//-=-=-= } else { SHAppBarMessage(ABM_REMOVE,&abd); } } return 0; case WM_NCHITTEST: { LONG result; result=DefWindowProc(msg->hwnd,WM_NCHITTEST,msg->wParam,msg->lParam); if(result==HTSIZE || result==HTTOP || result==HTTOPLEFT || result==HTTOPRIGHT || result==HTBOTTOM || result==HTBOTTOMRIGHT || result==HTBOTTOMLEFT) {*((LRESULT*)lParam)=HTCLIENT; return TRUE;} if(g_CluiData.fDocked==DOCKED_LEFT && result==HTLEFT) {*((LRESULT*)lParam)=HTCLIENT; return TRUE;} if(g_CluiData.fDocked==DOCKED_RIGHT && result==HTRIGHT) {*((LRESULT*)lParam)=HTCLIENT; return TRUE;} return 0; } case WM_SYSCOMMAND: if ((msg->wParam&0xFFF0)!=SC_MOVE) return 0; SetActiveWindow(msg->hwnd); SetCapture(msg->hwnd); draggingTitle=1; *((LRESULT*)lParam)=0; return TRUE; case WM_MOUSEMOVE: if (!draggingTitle) return 0; { RECT rc; POINT pt; GetClientRect(msg->hwnd,&rc); if (((g_CluiData.fDocked==DOCKED_LEFT || g_CluiData.fDocked==-DOCKED_LEFT) && (short)LOWORD(msg->lParam)>rc.right) || ((g_CluiData.fDocked==DOCKED_RIGHT || g_CluiData.fDocked==-DOCKED_RIGHT) && (short)LOWORD(msg->lParam)<0)) { ReleaseCapture(); draggingTitle=0; ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; SHAppBarMessage(ABM_REMOVE,&abd); g_CluiData.fDocked=0; GetCursorPos(&pt); PostMessage(msg->hwnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(pt.x,pt.y)); SetWindowPos(msg->hwnd,0,pt.x-rc.right/2,pt.y-GetSystemMetrics(SM_CYFRAME)-GetSystemMetrics(SM_CYSMCAPTION)/2,ModernGetSettingDword(NULL,"CList","Width",0),ModernGetSettingDword(NULL,"CList","Height",0),SWP_NOZORDER); ModernWriteSettingByte(NULL,"CList","Docked",(BYTE)g_CluiData.fDocked); // ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW, NULL); } return 1; } case WM_LBUTTONUP: if(draggingTitle) { ReleaseCapture(); draggingTitle=0; } return 0; case WM_DOCKCALLBACK: switch(msg->wParam) { case ABN_WINDOWARRANGE: CLUI_ShowWindowMod(msg->hwnd,msg->lParam?SW_HIDE:SW_SHOW); { RECT rc, rcMonitor; Docking_GetMonitorRectFromWindow(msg->hwnd,&rcMonitor); GetWindowRect(msg->hwnd,&rc); Docking_AdjustPosition(msg->hwnd,&rcMonitor,&rc); Sync(CLUIFrames_OnMoving,msg->hwnd,&rc); //-=-=-= ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW, NULL); g_CluiData.mutexPreventDockMoving=1; } break; } return TRUE; case WM_DESTROY: if(g_CluiData.fDocked>0) { ZeroMemory(&abd,sizeof(abd)); abd.cbSize=sizeof(abd); abd.hWnd=msg->hwnd; SHAppBarMessage(ABM_REMOVE,&abd); ModernSkinButton_ReposButtons(msg->hwnd, SBRF_DO_NOT_DRAW, NULL); } return 0; } return 0; }