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