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 /* Win: zzzHideCaret */ 226 BOOL FASTCALL co_UserHideCaret(PWND Window OPTIONAL) 227 { 228 PTHREADINFO pti; 229 PUSER_MESSAGE_QUEUE ThreadQueue; 230 231 if (Window) ASSERT_REFS_CO(Window); 232 233 if(Window && Window->head.pti->pEThread != PsGetCurrentThread()) 234 { 235 EngSetLastError(ERROR_ACCESS_DENIED); 236 return FALSE; 237 } 238 239 pti = PsGetCurrentThreadWin32Thread(); 240 ThreadQueue = pti->MessageQueue; 241 242 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h) 243 { 244 EngSetLastError(ERROR_ACCESS_DENIED); 245 return FALSE; 246 } 247 248 if(ThreadQueue->CaretInfo.Visible) 249 { 250 PWND pwnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd); 251 IntKillTimer(pwnd, IDCARETTIMER, TRUE); 252 253 co_IntHideCaret(&ThreadQueue->CaretInfo); 254 ThreadQueue->CaretInfo.Visible = 0; 255 ThreadQueue->CaretInfo.Showing = 0; 256 } 257 258 return TRUE; 259 } 260 261 /* Win: zzzShowCaret */ 262 BOOL FASTCALL co_UserShowCaret(PWND Window OPTIONAL) 263 { 264 PTHREADINFO pti; 265 PUSER_MESSAGE_QUEUE ThreadQueue; 266 PWND pWnd = NULL; 267 268 if (Window) ASSERT_REFS_CO(Window); 269 270 if(Window && Window->head.pti->pEThread != PsGetCurrentThread()) 271 { 272 EngSetLastError(ERROR_ACCESS_DENIED); 273 return FALSE; 274 } 275 276 pti = PsGetCurrentThreadWin32Thread(); 277 ThreadQueue = pti->MessageQueue; 278 279 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h) 280 { 281 EngSetLastError(ERROR_ACCESS_DENIED); 282 return FALSE; 283 } 284 285 if (!ThreadQueue->CaretInfo.Visible) 286 { 287 ThreadQueue->CaretInfo.Visible = 1; 288 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd); 289 if (!ThreadQueue->CaretInfo.Showing && pWnd) 290 { 291 IntNotifyWinEvent(EVENT_OBJECT_SHOW, pWnd, OBJID_CARET, OBJID_CARET, 0); 292 } 293 if ((INT)gpsi->dtCaretBlink > 0) 294 { 295 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM); 296 } 297 else if (ThreadQueue->CaretInfo.Visible) 298 { 299 ThreadQueue->CaretInfo.Showing = 1; 300 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo); 301 } 302 } 303 return TRUE; 304 } 305 306 /* SYSCALLS *****************************************************************/ 307 308 BOOL 309 APIENTRY 310 NtUserCreateCaret( 311 HWND hWnd, 312 HBITMAP hBitmap, 313 int nWidth, 314 int nHeight) 315 { 316 PWND Window; 317 PTHREADINFO pti; 318 PUSER_MESSAGE_QUEUE ThreadQueue; 319 BOOL Ret = FALSE; 320 321 TRACE("Enter NtUserCreateCaret\n"); 322 UserEnterExclusive(); 323 324 if(!(Window = UserGetWindowObject(hWnd))) 325 { 326 goto Exit; // Return FALSE 327 } 328 329 if(Window->head.pti->pEThread != PsGetCurrentThread()) 330 { 331 EngSetLastError(ERROR_ACCESS_DENIED); 332 goto Exit; // Return FALSE 333 } 334 335 pti = PsGetCurrentThreadWin32Thread(); 336 ThreadQueue = pti->MessageQueue; 337 338 if (ThreadQueue->CaretInfo.Visible) 339 { 340 IntKillTimer(Window, IDCARETTIMER, TRUE); 341 co_IntHideCaret(&ThreadQueue->CaretInfo); 342 } 343 344 ThreadQueue->CaretInfo.hWnd = hWnd; 345 if(hBitmap) 346 { 347 ThreadQueue->CaretInfo.Bitmap = hBitmap; 348 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0; 349 } 350 else 351 { 352 if (nWidth == 0) 353 { 354 nWidth = UserGetSystemMetrics(SM_CXBORDER); 355 } 356 if (nHeight == 0) 357 { 358 nHeight = UserGetSystemMetrics(SM_CYBORDER); 359 } 360 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0; 361 ThreadQueue->CaretInfo.Size.cx = nWidth; 362 ThreadQueue->CaretInfo.Size.cy = nHeight; 363 } 364 ThreadQueue->CaretInfo.Visible = 0; 365 ThreadQueue->CaretInfo.Showing = 0; 366 367 IntSetTimer(Window, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM); 368 369 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_CARET, CHILDID_SELF, 0); 370 371 Ret = TRUE; 372 373 Exit: 374 TRACE("Leave NtUserCreateCaret, ret=%i\n", Ret); 375 UserLeave(); 376 return Ret; 377 } 378 379 UINT 380 APIENTRY 381 NtUserGetCaretBlinkTime(VOID) 382 { 383 UINT ret; 384 385 UserEnterShared(); 386 387 ret = gpsi->dtCaretBlink; 388 389 UserLeave(); 390 391 return ret; 392 } 393 394 BOOL 395 APIENTRY 396 NtUserGetCaretPos( 397 LPPOINT lpPoint) 398 { 399 PTHREADINFO pti; 400 PUSER_MESSAGE_QUEUE ThreadQueue; 401 NTSTATUS Status; 402 BOOL Ret = TRUE; 403 404 TRACE("Enter NtUserGetCaretPos\n"); 405 UserEnterShared(); 406 407 pti = PsGetCurrentThreadWin32Thread(); 408 ThreadQueue = pti->MessageQueue; 409 410 Status = MmCopyToCaller(lpPoint, &ThreadQueue->CaretInfo.Pos, sizeof(POINT)); 411 if(!NT_SUCCESS(Status)) 412 { 413 SetLastNtError(Status); 414 Ret = FALSE; 415 } 416 417 TRACE("Leave NtUserGetCaretPos, ret=%i\n", Ret); 418 UserLeave(); 419 return Ret; 420 } 421 422 BOOL 423 APIENTRY 424 NtUserShowCaret(HWND hWnd OPTIONAL) 425 { 426 PWND Window = NULL; 427 USER_REFERENCE_ENTRY Ref; 428 BOOL ret = FALSE; 429 430 TRACE("Enter NtUserShowCaret\n"); 431 UserEnterExclusive(); 432 433 if(hWnd && !(Window = UserGetWindowObject(hWnd))) 434 { 435 goto Exit; // Return FALSE 436 } 437 438 if (Window) UserRefObjectCo(Window, &Ref); 439 440 ret = co_UserShowCaret(Window); 441 442 if (Window) UserDerefObjectCo(Window); 443 444 Exit: 445 TRACE("Leave NtUserShowCaret, ret=%i\n", ret); 446 UserLeave(); 447 return ret; 448 } 449 450 BOOL 451 APIENTRY 452 NtUserHideCaret(HWND hWnd OPTIONAL) 453 { 454 PWND Window = NULL; 455 USER_REFERENCE_ENTRY Ref; 456 BOOL ret = FALSE; 457 458 TRACE("Enter NtUserHideCaret\n"); 459 UserEnterExclusive(); 460 461 if(hWnd && !(Window = UserGetWindowObject(hWnd))) 462 { 463 goto Exit; // Return FALSE 464 } 465 466 if (Window) UserRefObjectCo(Window, &Ref); 467 468 ret = co_UserHideCaret(Window); 469 470 if (Window) UserDerefObjectCo(Window); 471 472 Exit: 473 TRACE("Leave NtUserHideCaret, ret=%i\n", ret); 474 UserLeave(); 475 return ret; 476 } 477