1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Caret functions 5 * FILE: win32ss/user/ntuser/caret.c 6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserCaret); 11 12 /* DEFINES *****************************************************************/ 13 14 #define MIN_CARETBLINKRATE 100 15 #define MAX_CARETBLINKRATE 10000 16 17 /* FUNCTIONS *****************************************************************/ 18 19 VOID FASTCALL 20 co_IntDrawCaret(PWND pWnd, PTHRDCARETINFO CaretInfo) 21 { 22 HDC hdc, hdcMem; 23 HBITMAP hbmOld; 24 BOOL bDone = FALSE; 25 26 if (pWnd == NULL) 27 { 28 TRACE("Null Window!\n"); 29 return; 30 } 31 32 hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE | DCX_WINDOW); 33 if (!hdc) 34 { 35 ERR("GetDC failed\n"); 36 return; 37 } 38 39 if (pWnd->hrgnUpdate) 40 { 41 NtGdiSaveDC(hdc); 42 } 43 44 if (CaretInfo->Bitmap) 45 { 46 if (!GreGetBitmapDimension(CaretInfo->Bitmap, &CaretInfo->Size)) 47 { 48 ERR("Failed to get bitmap dimensions\n"); 49 goto cleanup; 50 } 51 52 hdcMem = NtGdiCreateCompatibleDC(hdc); 53 if (hdcMem) 54 { 55 hbmOld = NtGdiSelectBitmap(hdcMem, CaretInfo->Bitmap); 56 bDone = NtGdiBitBlt(hdc, 57 CaretInfo->Pos.x, 58 CaretInfo->Pos.y, 59 CaretInfo->Size.cx, 60 CaretInfo->Size.cy, 61 hdcMem, 62 0, 63 0, 64 SRCINVERT, 65 0, 66 0); 67 NtGdiSelectBitmap(hdcMem, hbmOld); 68 GreDeleteObject(hdcMem); 69 } 70 } 71 72 if (!bDone) 73 { 74 NtGdiPatBlt(hdc, 75 CaretInfo->Pos.x, 76 CaretInfo->Pos.y, 77 CaretInfo->Size.cx, 78 CaretInfo->Size.cy, 79 DSTINVERT); 80 } 81 82 cleanup: 83 if (pWnd->hrgnUpdate) 84 { 85 NtGdiRestoreDC(hdc, -1); 86 } 87 88 UserReleaseDC(pWnd, hdc, FALSE); 89 } 90 91 VOID 92 CALLBACK 93 CaretSystemTimerProc(HWND hwnd, 94 UINT uMsg, 95 UINT_PTR idEvent, 96 DWORD dwTime) 97 { 98 PTHREADINFO pti; 99 PUSER_MESSAGE_QUEUE ThreadQueue; 100 PWND pWnd; 101 102 pti = PsGetCurrentThreadWin32Thread(); 103 ThreadQueue = pti->MessageQueue; 104 105 if (ThreadQueue->CaretInfo.hWnd != hwnd) 106 { 107 TRACE("Not the same caret window!\n"); 108 return; 109 } 110 111 if (hwnd) 112 { 113 pWnd = UserGetWindowObject(hwnd); 114 if (!pWnd) 115 { 116 ERR("Caret System Timer Proc has invalid window handle! %p Id: %u\n", hwnd, idEvent); 117 return; 118 } 119 } 120 else 121 { 122 TRACE( "Windowless Caret Timer Running!\n" ); 123 return; 124 } 125 126 switch (idEvent) 127 { 128 case IDCARETTIMER: 129 { 130 ThreadQueue->CaretInfo.Showing = (ThreadQueue->CaretInfo.Showing ? 0 : 1); 131 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo); 132 } 133 } 134 return; 135 } 136 137 static 138 BOOL FASTCALL 139 co_IntHideCaret(PTHRDCARETINFO CaretInfo) 140 { 141 PWND pWnd; 142 if(CaretInfo->hWnd && CaretInfo->Visible && CaretInfo->Showing) 143 { 144 pWnd = UserGetWindowObject(CaretInfo->hWnd); 145 CaretInfo->Showing = 0; 146 147 co_IntDrawCaret(pWnd, CaretInfo); 148 IntNotifyWinEvent(EVENT_OBJECT_HIDE, pWnd, OBJID_CARET, CHILDID_SELF, 0); 149 return TRUE; 150 } 151 return FALSE; 152 } 153 154 BOOL FASTCALL 155 co_IntDestroyCaret(PTHREADINFO Win32Thread) 156 { 157 PUSER_MESSAGE_QUEUE ThreadQueue; 158 PWND pWnd; 159 ThreadQueue = Win32Thread->MessageQueue; 160 161 if (!ThreadQueue) 162 return FALSE; 163 164 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd); 165 co_IntHideCaret(&ThreadQueue->CaretInfo); 166 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0; 167 ThreadQueue->CaretInfo.hWnd = (HWND)0; 168 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0; 169 ThreadQueue->CaretInfo.Showing = 0; 170 ThreadQueue->CaretInfo.Visible = 0; 171 if (pWnd) 172 { 173 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, pWnd, OBJID_CARET, CHILDID_SELF, 0); 174 } 175 return TRUE; 176 } 177 178 BOOL FASTCALL 179 IntSetCaretBlinkTime(UINT uMSeconds) 180 { 181 /* Don't save the new value to the registry! */ 182 183 /* Windows doesn't do this check */ 184 if((uMSeconds < MIN_CARETBLINKRATE) || (uMSeconds > MAX_CARETBLINKRATE)) 185 { 186 EngSetLastError(ERROR_INVALID_PARAMETER); 187 return FALSE; 188 } 189 190 gpsi->dtCaretBlink = uMSeconds; 191 192 return TRUE; 193 } 194 195 BOOL FASTCALL 196 co_IntSetCaretPos(int X, int Y) 197 { 198 PTHREADINFO pti; 199 PWND pWnd; 200 PUSER_MESSAGE_QUEUE ThreadQueue; 201 202 pti = PsGetCurrentThreadWin32Thread(); 203 ThreadQueue = pti->MessageQueue; 204 205 if(ThreadQueue->CaretInfo.hWnd) 206 { 207 pWnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd); 208 if(ThreadQueue->CaretInfo.Pos.x != X || ThreadQueue->CaretInfo.Pos.y != Y) 209 { 210 co_IntHideCaret(&ThreadQueue->CaretInfo); 211 ThreadQueue->CaretInfo.Showing = 1; 212 ThreadQueue->CaretInfo.Pos.x = X; 213 ThreadQueue->CaretInfo.Pos.y = Y; 214 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo); 215 216 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM); 217 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_CARET, CHILDID_SELF, 0); 218 } 219 return TRUE; 220 } 221 222 return FALSE; 223 } 224 225 BOOL FASTCALL co_UserHideCaret(PWND Window OPTIONAL) 226 { 227 PTHREADINFO pti; 228 PUSER_MESSAGE_QUEUE ThreadQueue; 229 230 if (Window) ASSERT_REFS_CO(Window); 231 232 if(Window && Window->head.pti->pEThread != PsGetCurrentThread()) 233 { 234 EngSetLastError(ERROR_ACCESS_DENIED); 235 return FALSE; 236 } 237 238 pti = PsGetCurrentThreadWin32Thread(); 239 ThreadQueue = pti->MessageQueue; 240 241 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h) 242 { 243 EngSetLastError(ERROR_ACCESS_DENIED); 244 return FALSE; 245 } 246 247 if(ThreadQueue->CaretInfo.Visible) 248 { 249 PWND pwnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd); 250 IntKillTimer(pwnd, IDCARETTIMER, TRUE); 251 252 co_IntHideCaret(&ThreadQueue->CaretInfo); 253 ThreadQueue->CaretInfo.Visible = 0; 254 ThreadQueue->CaretInfo.Showing = 0; 255 } 256 257 return TRUE; 258 } 259 260 BOOL FASTCALL co_UserShowCaret(PWND Window OPTIONAL) 261 { 262 PTHREADINFO pti; 263 PUSER_MESSAGE_QUEUE ThreadQueue; 264 PWND pWnd = NULL; 265 266 if (Window) ASSERT_REFS_CO(Window); 267 268 if(Window && Window->head.pti->pEThread != PsGetCurrentThread()) 269 { 270 EngSetLastError(ERROR_ACCESS_DENIED); 271 return FALSE; 272 } 273 274 pti = PsGetCurrentThreadWin32Thread(); 275 ThreadQueue = pti->MessageQueue; 276 277 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h) 278 { 279 EngSetLastError(ERROR_ACCESS_DENIED); 280 return FALSE; 281 } 282 283 if (!ThreadQueue->CaretInfo.Visible) 284 { 285 ThreadQueue->CaretInfo.Visible = 1; 286 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd); 287 if (!ThreadQueue->CaretInfo.Showing && pWnd) 288 { 289 IntNotifyWinEvent(EVENT_OBJECT_SHOW, pWnd, OBJID_CARET, OBJID_CARET, 0); 290 } 291 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM); 292 } 293 return TRUE; 294 } 295 296 /* SYSCALLS *****************************************************************/ 297 298 BOOL 299 APIENTRY 300 NtUserCreateCaret( 301 HWND hWnd, 302 HBITMAP hBitmap, 303 int nWidth, 304 int nHeight) 305 { 306 PWND Window; 307 PTHREADINFO pti; 308 PUSER_MESSAGE_QUEUE ThreadQueue; 309 DECLARE_RETURN(BOOL); 310 311 TRACE("Enter NtUserCreateCaret\n"); 312 UserEnterExclusive(); 313 314 if(!(Window = UserGetWindowObject(hWnd))) 315 { 316 RETURN(FALSE); 317 } 318 319 if(Window->head.pti->pEThread != PsGetCurrentThread()) 320 { 321 EngSetLastError(ERROR_ACCESS_DENIED); 322 RETURN(FALSE); 323 } 324 325 pti = PsGetCurrentThreadWin32Thread(); 326 ThreadQueue = pti->MessageQueue; 327 328 if (ThreadQueue->CaretInfo.Visible) 329 { 330 IntKillTimer(Window, IDCARETTIMER, TRUE); 331 co_IntHideCaret(&ThreadQueue->CaretInfo); 332 } 333 334 ThreadQueue->CaretInfo.hWnd = hWnd; 335 if(hBitmap) 336 { 337 ThreadQueue->CaretInfo.Bitmap = hBitmap; 338 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0; 339 } 340 else 341 { 342 if (nWidth == 0) 343 { 344 nWidth = UserGetSystemMetrics(SM_CXBORDER); 345 } 346 if (nHeight == 0) 347 { 348 nHeight = UserGetSystemMetrics(SM_CYBORDER); 349 } 350 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0; 351 ThreadQueue->CaretInfo.Size.cx = nWidth; 352 ThreadQueue->CaretInfo.Size.cy = nHeight; 353 } 354 ThreadQueue->CaretInfo.Visible = 0; 355 ThreadQueue->CaretInfo.Showing = 0; 356 357 IntSetTimer( Window, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM ); 358 359 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_CARET, CHILDID_SELF, 0); 360 361 RETURN(TRUE); 362 363 CLEANUP: 364 TRACE("Leave NtUserCreateCaret, ret=%i\n",_ret_); 365 UserLeave(); 366 END_CLEANUP; 367 } 368 369 UINT 370 APIENTRY 371 NtUserGetCaretBlinkTime(VOID) 372 { 373 UINT ret; 374 375 UserEnterShared(); 376 377 ret = gpsi->dtCaretBlink; 378 379 UserLeave(); 380 381 return ret; 382 } 383 384 BOOL 385 APIENTRY 386 NtUserGetCaretPos( 387 LPPOINT lpPoint) 388 { 389 PTHREADINFO pti; 390 PUSER_MESSAGE_QUEUE ThreadQueue; 391 NTSTATUS Status; 392 DECLARE_RETURN(BOOL); 393 394 TRACE("Enter NtUserGetCaretPos\n"); 395 UserEnterShared(); 396 397 pti = PsGetCurrentThreadWin32Thread(); 398 ThreadQueue = pti->MessageQueue; 399 400 Status = MmCopyToCaller(lpPoint, &ThreadQueue->CaretInfo.Pos, sizeof(POINT)); 401 if(!NT_SUCCESS(Status)) 402 { 403 SetLastNtError(Status); 404 RETURN(FALSE); 405 } 406 407 RETURN(TRUE); 408 409 CLEANUP: 410 TRACE("Leave NtUserGetCaretPos, ret=%i\n",_ret_); 411 UserLeave(); 412 END_CLEANUP; 413 } 414 415 BOOL 416 APIENTRY 417 NtUserShowCaret(HWND hWnd OPTIONAL) 418 { 419 PWND Window = NULL; 420 USER_REFERENCE_ENTRY Ref; 421 DECLARE_RETURN(BOOL); 422 BOOL ret; 423 424 TRACE("Enter NtUserShowCaret\n"); 425 UserEnterExclusive(); 426 427 if(hWnd && !(Window = UserGetWindowObject(hWnd))) 428 { 429 RETURN(FALSE); 430 } 431 432 if (Window) UserRefObjectCo(Window, &Ref); 433 434 ret = co_UserShowCaret(Window); 435 436 if (Window) UserDerefObjectCo(Window); 437 438 RETURN(ret); 439 440 CLEANUP: 441 TRACE("Leave NtUserShowCaret, ret=%i\n",_ret_); 442 UserLeave(); 443 END_CLEANUP; 444 } 445 446 BOOL 447 APIENTRY 448 NtUserHideCaret(HWND hWnd OPTIONAL) 449 { 450 PWND Window = NULL; 451 USER_REFERENCE_ENTRY Ref; 452 DECLARE_RETURN(BOOL); 453 BOOL ret; 454 455 TRACE("Enter NtUserHideCaret\n"); 456 UserEnterExclusive(); 457 458 if(hWnd && !(Window = UserGetWindowObject(hWnd))) 459 { 460 RETURN(FALSE); 461 } 462 463 if (Window) UserRefObjectCo(Window, &Ref); 464 465 ret = co_UserHideCaret(Window); 466 467 if (Window) UserDerefObjectCo(Window); 468 469 RETURN(ret); 470 471 CLEANUP: 472 TRACE("Leave NtUserHideCaret, ret=%i\n",_ret_); 473 UserLeave(); 474 END_CLEANUP; 475 } 476