- Timestamp:
- Jun 15, 2010, 5:00:46 PM (15 years ago)
- Location:
- trunk/src/gui/painting
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/painting/qwindowsurface_pm.cpp
r746 r751 58 58 #include <qt_os2.h> 59 59 #include <qlibrary.h> 60 #include <qobject.h> 61 #include <qevent.h> 60 62 61 63 #include "qwindowsurface_pm_p.h" … … 323 325 QPMDiveWindowSurfaceFB(QWidget *widget); 324 326 ~QPMDiveWindowSurfaceFB(); 325 void doFlush( const QRect &from, const QPoint &to);327 void doFlush(QWidget *widget, const QRect &from, const QPoint &to); 326 328 }; 327 329 328 struct QPMDiveWindowSurfacePrivate 329 { 330 struct QPMDiveWindowSurfacePrivate : public QObject, private QWidget::PmEventFilter 331 { 332 QPMDiveWindowSurface *that; 333 330 334 QImage *image; 331 335 HDIVE hDive; … … 333 337 ULONG bufNum; 334 338 bool posDirty; 335 bool vrnDirty;336 339 bool vrnDisabled; 337 340 bool inDrag; 338 int windowHeight;339 341 SETUP_BLITTER setup; 340 QVector<RECTL> rcls;341 342 342 343 struct FlushArgs 343 344 { 345 QWidget *widget; 344 346 QRect from; 345 347 QPoint to; 346 348 }; 347 349 QList<FlushArgs> pending; 350 351 struct WidgetData 352 { 353 QWidget *widget; 354 int widgetHeight; 355 bool vrnDirty; 356 size_t rclCount; 357 QVector<RECTL> rcls; 358 }; 359 360 WidgetData data; 361 QMap<HWND, WidgetData> *subWidgets; 362 363 void addWidget(QWidget *widget); 364 void removeWidget(QWidget *widget); 365 366 WidgetData *widgetData(QWidget *widget) { 367 // check for the most common case (no sub-widgets with own HWNDs) 368 if (widget == that->window()) 369 return &data; 370 if (!subWidgets || !subWidgets->contains(widget->winId())) 371 return 0; 372 return &(*subWidgets)[widget->winId()]; 373 } 374 375 bool eventFilter(QObject *obj, QEvent *event); 376 bool pmEventFilter(QMSG *msg, MRESULT *result); 348 377 }; 378 379 void QPMDiveWindowSurfacePrivate::addWidget(QWidget *widget) 380 { 381 WidgetData *wd = &data; 382 if (widget != that->window()) { 383 // lazily create the sub-widget map (only when really necessary) 384 if (!subWidgets) 385 subWidgets = new QMap<HWND, WidgetData>(); 386 wd = &(*subWidgets)[widget->winId()]; 387 } 388 389 wd->widget = widget; 390 wd->vrnDirty = true; 391 wd->widgetHeight = 0; 392 wd->rclCount = 0; 393 394 if (widget == that->window()) { 395 // receive visible region change messages (note that we don't do this 396 // for sub-widgets as it causes some strange PM freezes if these widgets 397 // are embedded windows manipulated by other processes) 398 widget->addPmEventFilter(this); 399 WinSetVisibleRegionNotify(widget->winId(), TRUE); 400 } else { 401 // receive reparent/destruction messages from children 402 // to cleanup the map 403 widget->installEventFilter(this); 404 } 405 } 406 407 void QPMDiveWindowSurfacePrivate::removeWidget(QWidget *widget) 408 { 409 if (widget == that->window()) { 410 WinSetVisibleRegionNotify(widget->winId(), FALSE); 411 widget->removePmEventFilter(this); 412 } else { 413 widget->removeEventFilter(this); 414 } 415 416 if (widget != that->window()) 417 subWidgets->remove(widget->winId()); 418 } 419 420 bool QPMDiveWindowSurfacePrivate::eventFilter(QObject *obj, QEvent *event) 421 { 422 QWidget *widget = qobject_cast<QWidget *>(obj); 423 if (event->type() == QEvent::ParentAboutToChange || 424 event->type() == QEvent::Destroy) { 425 removeWidget(widget); 426 } 427 428 return false; 429 } 430 431 bool QPMDiveWindowSurfacePrivate::pmEventFilter(QMSG *msg, MRESULT *result) 432 { 433 switch (msg->msg) { 434 case WM_VRNDISABLED: { 435 if (!useFB) 436 DiveSetupBlitter(hDive, NULL); 437 vrnDisabled = true; 438 *result = 0; 439 return true; 440 } 441 case DM_DRAGOVER: { 442 inDrag = true; 443 break; 444 } 445 case DM_DRAGLEAVE: 446 case DM_DROP: { 447 inDrag = false; 448 break; 449 } 450 case WM_VRNENABLED: { 451 vrnDisabled = false; 452 // Note that when an overlapping window of *other* process is moved 453 // over this window, PM still sends WM_VRNENABLED to it but with 454 // ffVisRgnChanged set to FALSE although the visible region *does* 455 // actually change (it doesn't seem to be the case for windows of 456 // the same process). The solution is to ignore this flag and always 457 // assume that the visible region was changed when we get this msg 458 #if 0 459 if (LONGFROMMP(msg->mp1)) // window's visible region changed 460 #endif 461 { 462 // mark all widgets' visible regions as dirty 463 data.vrnDirty = true; 464 if (subWidgets) { 465 foreach(HWND hwnd, subWidgets->keys()) 466 (*subWidgets)[hwnd].vrnDirty = true; 467 } 468 } 469 posDirty = true; 470 471 // process pending flush events 472 foreach(const QPMDiveWindowSurfacePrivate::FlushArgs &args, pending) 473 that->doFlush(args.widget, args.from, args.to); 474 pending.clear(); 475 476 *result = 0; 477 return true; 478 } 479 default: 480 break; 481 } 482 483 return false; 484 } 349 485 350 486 QPMDiveWindowSurface::QPMDiveWindowSurface(QWidget* widget) 351 487 : QWindowSurface(widget), d(new QPMDiveWindowSurfacePrivate) 352 488 { 489 d->that = this; 353 490 d->image = 0; 354 491 d->hDive = NULLHANDLE; … … 356 493 d->bufNum = 0; 357 494 d->posDirty = true; 358 d->vrnDirty = true;359 495 d->vrnDisabled = false; 360 496 d->inDrag = false; 361 d-> windowHeight= 0;497 d->subWidgets = 0; 362 498 363 499 memset(&d->setup, 0, sizeof(SETUP_BLITTER)); … … 369 505 d->setup.fccDstColorFormat = FOURCC_SCRN; 370 506 371 window()->addPmEventFilter(this);372 WinSetVisibleRegionNotify(window()->winId(), TRUE);507 // add self to the map of participating widgets 508 d->addWidget(window()); 373 509 374 510 setStaticContentsSupport(true); … … 377 513 QPMDiveWindowSurface::~QPMDiveWindowSurface() 378 514 { 379 WinSetVisibleRegionNotify(window()->winId(), FALSE); 380 window()->removePmEventFilter(this); 515 if (d->subWidgets) { 516 foreach(HWND hwnd, d->subWidgets->keys()) 517 d->removeWidget((*d->subWidgets)[hwnd].widget); 518 Q_ASSERT(d->subWidgets->count() == 0); 519 delete d->subWidgets; 520 } 521 522 d->removeWidget(window()); 381 523 382 524 if (d->bufNum) … … 400 542 if (!d->image || rgn.rectCount() == 0) 401 543 return; 544 545 // make sure the widget is known to us 546 if (!d->widgetData(widget)) 547 d->addWidget(widget); 402 548 403 549 QRect br = rgn.boundingRect(); … … 465 611 if (d->vrnDisabled) { 466 612 // defer the flush 467 QPMDiveWindowSurfacePrivate::FlushArgs args = { br, wbr.topLeft() }; 613 QPMDiveWindowSurfacePrivate::FlushArgs args = { widget, 614 br, wbr.topLeft() }; 468 615 d->pending.append(args); 469 616 return; 470 617 } 471 618 472 doFlush( br, wbr.topLeft());473 } 474 475 bool QPMDiveWindowSurface::adjustSetup( )619 doFlush(widget, br, wbr.topLeft()); 620 } 621 622 bool QPMDiveWindowSurface::adjustSetup(QWidget *widget) 476 623 { 477 624 HWND hwnd = window()->winId(); … … 481 628 bool setupDirty = false; 482 629 483 if (d->posDirty || d->vrnDirty) { 630 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget); 631 Q_ASSERT(wd); 632 633 if (d->posDirty || wd->vrnDirty) { 484 634 setupDirty = true; 485 635 d->posDirty = false; 636 // the main widget moved, adjust the target poition 486 637 POINTL ptl = { 0, 0 }; 487 638 WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1); … … 494 645 } 495 646 496 if (d->vrnDirty) { 647 bool wasVrnDirty = wd->vrnDirty; 648 649 if (wd->vrnDirty) { 497 650 setupDirty = true; 498 d->vrnDirty = false;651 wd->vrnDirty = false; 499 652 500 653 HPS hps = window()->getPS(); 501 654 HRGN hrgn = GpiCreateRegion(hps, 0L, NULL); 502 655 503 RGNRECT rgnCtl;504 rgnCtl.ircStart = 1;505 rgnCtl.crc = rgnCtl.crcReturned = 0;506 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;507 508 656 ULONG rc = WinQueryVisibleRegion(hwnd, hrgn); 657 if (rc != RGN_ERROR) { 658 HWND hwndWidget = widget->winId(); 659 POINTL ptlOffset = { 0, 0 }; 660 if (hwnd != hwndWidget) { 661 // translate the main widget's visible region to this widget's 662 // coordinate space 663 WinMapWindowPoints(hwnd, hwndWidget, &ptlOffset, 1); 664 GpiOffsetRegion(hps, hrgn, &ptlOffset); 665 } 666 // substract children from the visible region, if any 667 rc = qt_WinProcessWindowObstacles(hwndWidget, NULL, hrgn, 668 CRGN_DIFF, PWO_Children); 669 if (rc != RGN_ERROR && hwnd != hwndWidget) { 670 // translate back to the main widget's coordinate space 671 ptlOffset.x = -ptlOffset.x; 672 ptlOffset.y = -ptlOffset.y; 673 GpiOffsetRegion(hps, hrgn, &ptlOffset); 674 } 675 } 676 509 677 if (rc == RGN_RECT || rc == RGN_COMPLEX) { 678 RGNRECT rgnCtl; 679 rgnCtl.ircStart = 1; 680 rgnCtl.crc = rgnCtl.crcReturned = 0; 681 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT; 510 682 if (GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL) && 511 683 rgnCtl.crcReturned) { … … 513 685 rgnCtl.crc = rgnCtl.crcReturned; 514 686 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT; 515 if (d->rcls.size() < (int)rgnCtl.crc) 516 d->rcls.resize((int)rgnCtl.crc); 517 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, d->rcls.data()); 687 if (wd->rcls.size() < (int)rgnCtl.crc) 688 wd->rcls.resize((int)rgnCtl.crc); 689 wd->rclCount = rgnCtl.crc; 690 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, wd->rcls.data()); 518 691 } 519 } 520 521 d->setup.ulNumDstRects = rgnCtl.crcReturned; 522 d->setup.pVisDstRects = rgnCtl.crcReturned ? d->rcls.data() : NULL; 523 d->setup.ulStructLen = sizeof(SETUP_BLITTER); 692 } else if (rc == RGN_NULL) { 693 wd->rclCount = 0; 694 } 524 695 525 696 GpiDestroyRegion(hps, hrgn); … … 528 699 // memorize the window height used for the additional visible region 529 700 // validation in doFlush() 530 d->windowHeight = window()->height();701 wd->widgetHeight = widget->height(); 531 702 532 703 #if defined(QDIVE_DEBUG) 533 704 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << "vrnDirty"); 534 for (size_t i = 0; i < d->setup.ulNumDstRects; ++i)535 DEBUG(() << " " << i << ":" << d->setup.pVisDstRects[i]);705 for (size_t i = 0; i < wd->rclCount; ++i) 706 DEBUG(() << " " << i << ":" << wd->rcls[i]); 536 707 #endif 537 708 } 538 709 710 // make sure setup points to the correct visible rectangle array (note that 711 // we switch it even vrnDirty is false since the widget may change) 712 if (wasVrnDirty || d->setup.ulNumDstRects != wd->rclCount || 713 (wd->rclCount && d->setup.pVisDstRects != wd->rcls.data()) || 714 (!wd->rclCount && d->setup.pVisDstRects != NULL)) { 715 setupDirty = true; 716 d->setup.ulNumDstRects = wd->rclCount; 717 d->setup.pVisDstRects = wd->rclCount ? wd->rcls.data() : NULL; 718 d->setup.ulStructLen = sizeof(SETUP_BLITTER); 719 } 720 539 721 return setupDirty; 540 722 } 541 723 542 void QPMDiveWindowSurface::doFlush( const QRect &from, const QPoint &to)543 { 544 DEBUG(() << "QPMDiveWindowSurface::doFlush:" << window() 724 void QPMDiveWindowSurface::doFlush(QWidget *widget, const QRect &from, const QPoint &to) 725 { 726 DEBUG(() << "QPMDiveWindowSurface::doFlush:" << window() << widget 545 727 << "from" << from << "to" << to); 546 728 … … 550 732 QPoint dst = to + (src.topLeft() - from.topLeft()); 551 733 552 bool setupDirty = adjustSetup( );734 bool setupDirty = adjustSetup(widget); 553 735 554 736 // note that the source image is expected to be top-left oriented … … 578 760 579 761 DiveBlitImage(d->hDive, d->bufNum, DIVE_BUFFER_SCREEN); 580 }581 582 bool QPMDiveWindowSurface::pmEventFilter(QMSG *msg, MRESULT *result)583 {584 switch (msg->msg) {585 case WM_VRNDISABLED: {586 if (!d->useFB)587 DiveSetupBlitter(d->hDive, NULL);588 d->vrnDisabled = true;589 *result = 0;590 return true;591 }592 case DM_DRAGOVER: {593 d->inDrag = true;594 break;595 }596 case DM_DRAGLEAVE:597 case DM_DROP: {598 d->inDrag = false;599 break;600 }601 case WM_VRNENABLED: {602 d->vrnDisabled = false;603 // Note that when an overlapping window of *other* process is moved604 // over this window, PM still sends WM_VRNENABLED to it but with605 // ffVisRgnChanged set to FALSE although the visible region *does*606 // actually change (it doesn't seem to be the case for windows of607 // the same process). The solution is to ignore this flag and always608 // assume that the visible region was changed when we get this msg609 #if 0610 if (LONGFROMMP(msg->mp1)) // window's visible region changed611 #endif612 d->vrnDirty = true;613 d->posDirty = true;614 615 // process pending flush events616 foreach(const QPMDiveWindowSurfacePrivate::FlushArgs &args, d->pending)617 doFlush(args.from, args.to);618 d->pending.clear();619 620 *result = 0;621 return true;622 }623 default:624 break;625 }626 627 return false;628 762 } 629 763 … … 934 1068 } 935 1069 936 void QPMDiveWindowSurfaceFB::doFlush( const QRect &from, const QPoint &to)937 { 938 DEBUG(() << "QPMDiveWindowSurfaceFB::doFlush:" << window() 1070 void QPMDiveWindowSurfaceFB::doFlush(QWidget *widget, const QRect &from, const QPoint &to) 1071 { 1072 DEBUG(() << "QPMDiveWindowSurfaceFB::doFlush:" << window() << widget 939 1073 << "from" << from << "to" << to); 940 1074 … … 946 1080 QPoint dstDelta = from.topLeft() - to; 947 1081 948 const int windowHeight = window()->height(); 1082 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget); 1083 Q_ASSERT(wd); 1084 1085 int widgetHeight = widget->height(); 949 1086 950 1087 // sometimes PM does not send WM_VRNENABLED although the window size has … … 952 1089 // application) which leads to screen corruption due to outdated visible 953 1090 // regions. A fix is to memorize the window height and check it here 954 if (wi ndowHeight != d->windowHeight)955 d->vrnDirty = true;1091 if (widgetHeight != wd->widgetHeight) 1092 wd->vrnDirty = true; 956 1093 957 1094 bool wasPosDirty = d->posDirty; 958 bool wasVrnDirty = d->vrnDirty; 959 960 adjustSetup(); 1095 bool wasVrnDirty = wd->vrnDirty; 1096 1097 adjustSetup(widget); 1098 1099 int windowHeight = window()->height(); 961 1100 962 1101 if (wasVrnDirty) { -
trunk/src/gui/painting/qwindowsurface_pm_p.h
r713 r751 63 63 struct QPMDiveWindowSurfacePrivate; 64 64 65 class QPMDiveWindowSurface : public QWindowSurface , private QWidget::PmEventFilter65 class QPMDiveWindowSurface : public QWindowSurface 66 66 { 67 67 public: … … 77 77 78 78 protected: 79 bool adjustSetup(); 80 virtual void doFlush(const QRect &from, const QPoint &to); 81 bool pmEventFilter(QMSG *msg, MRESULT *result); 79 bool adjustSetup(QWidget *widget); 80 virtual void doFlush(QWidget *widget, const QRect &from, const QPoint &to); 82 81 83 82 QScopedPointer<QPMDiveWindowSurfacePrivate> d; 83 friend struct QPMDiveWindowSurfacePrivate; 84 84 }; 85 85
Note:
See TracChangeset
for help on using the changeset viewer.