00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "client.h"
00020 #include "workspace.h"
00021
00022 #include <kapplication.h>
00023 #include <kglobal.h>
00024 #include <qpainter.h>
00025 #include <kwin.h>
00026
00027 #include "placement.h"
00028 #include "notifications.h"
00029 #include "geometrytip.h"
00030
00031 extern Time qt_x_time;
00032
00033 namespace KWinInternal
00034 {
00035
00036
00037
00038
00039
00043 void Workspace::desktopResized()
00044 {
00045 updateClientArea();
00046 checkElectricBorders();
00047 }
00048
00061 void Workspace::updateClientArea( bool force )
00062 {
00063 QRect* new_areas = new QRect[ numberOfDesktops() + 1 ];
00064 QRect all = QApplication::desktop()->geometry();
00065 for( int i = 1;
00066 i <= numberOfDesktops();
00067 ++i )
00068 new_areas[ i ] = all;
00069 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it)
00070 {
00071 QRect r = (*it)->adjustedClientArea( all );
00072 if( r == all )
00073 continue;
00074 if( (*it)->isOnAllDesktops())
00075 for( int i = 1;
00076 i <= numberOfDesktops();
00077 ++i )
00078 new_areas[ i ] = new_areas[ i ].intersect( r );
00079 else
00080 new_areas[ (*it)->desktop() ] = new_areas[ (*it)->desktop() ].intersect( r );
00081 }
00082 if( topmenu_space != NULL )
00083 {
00084 QRect topmenu_area = all;
00085 topmenu_area.setTop( topMenuHeight());
00086 for( int i = 1;
00087 i <= numberOfDesktops();
00088 ++i )
00089 new_areas[ i ] = new_areas[ i ].intersect( topmenu_area );
00090 }
00091
00092 bool changed = force;
00093 for( int i = 1;
00094 !changed && i <= numberOfDesktops();
00095 ++i )
00096 if( workarea[ i ] != new_areas[ i ] )
00097 changed = true;
00098 if ( changed )
00099 {
00100 delete[] workarea;
00101 workarea = new_areas;
00102 new_areas = NULL;
00103 NETRect r;
00104 for( int i = 1; i <= numberOfDesktops(); i++)
00105 {
00106 r.pos.x = workarea[ i ].x();
00107 r.pos.y = workarea[ i ].y();
00108 r.size.width = workarea[ i ].width();
00109 r.size.height = workarea[ i ].height();
00110 rootInfo->setWorkArea( i, r );
00111 }
00112
00113 updateTopMenuGeometry();
00114 for( ClientList::ConstIterator it = clients.begin();
00115 it != clients.end();
00116 ++it)
00117 (*it)->checkWorkspacePosition();
00118 }
00119 delete[] new_areas;
00120 }
00121
00122 void Workspace::updateClientArea()
00123 {
00124 updateClientArea( false );
00125 }
00126
00127
00135 QRect Workspace::clientArea( clientAreaOption opt, const QPoint& p, int desktop ) const
00136 {
00137 if( desktop == NETWinInfo::OnAllDesktops || desktop == 0 )
00138 desktop = currentDesktop();
00139 QRect rect = QApplication::desktop()->geometry();
00140 QDesktopWidget *desktopwidget = KApplication::desktop();
00141
00142 switch (opt)
00143 {
00144 case MaximizeArea:
00145 case MaximizeFullArea:
00146 if (options->xineramaMaximizeEnabled)
00147 rect = desktopwidget->screenGeometry(desktopwidget->screenNumber(p));
00148 break;
00149 case PlacementArea:
00150 if (options->xineramaPlacementEnabled)
00151 rect = desktopwidget->screenGeometry(desktopwidget->screenNumber(p));
00152 break;
00153 case MovementArea:
00154 if (options->xineramaMovementEnabled)
00155 rect = desktopwidget->screenGeometry(desktopwidget->screenNumber(p));
00156 break;
00157 case WorkArea:
00158 case FullArea:
00159 break;
00160 case ScreenArea:
00161 rect = desktopwidget->screenGeometry(desktopwidget->screenNumber(p));
00162 break;
00163 }
00164
00165 if( workarea[ desktop ].isNull() || opt == FullArea || opt == MaximizeFullArea
00166 || opt == ScreenArea || opt == MovementArea )
00167 return rect;
00168
00169 return workarea[ desktop ].intersect(rect);
00170 }
00171
00172 QRect Workspace::clientArea( clientAreaOption opt, const Client* c ) const
00173 {
00174 return clientArea( opt, c->geometry().center(), c->desktop());
00175 }
00176
00182 QPoint Workspace::adjustClientPosition( Client* c, QPoint pos )
00183 {
00184
00185
00186
00187 if (options->windowSnapZone || options->borderSnapZone )
00188 {
00189 bool sOWO=options->snapOnlyWhenOverlapping;
00190 QRect maxRect = clientArea(MovementArea, pos+c->rect().center(), c->desktop());
00191 int xmin = maxRect.left();
00192 int xmax = maxRect.right()+1;
00193 int ymin = maxRect.top();
00194 int ymax = maxRect.bottom()+1;
00195
00196 int cx(pos.x());
00197 int cy(pos.y());
00198 int cw(c->width());
00199 int ch(c->height());
00200 int rx(cx+cw);
00201 int ry(cy+ch);
00202
00203 int nx(cx), ny(cy);
00204 int deltaX(xmax);
00205 int deltaY(ymax);
00206
00207 int lx, ly, lrx, lry;
00208
00209
00210 int snap = options->borderSnapZone;
00211 if (snap)
00212 {
00213 if ((sOWO?(cx<xmin):true) && (QABS(xmin-cx)<snap))
00214 {
00215 deltaX = xmin-cx;
00216 nx = xmin;
00217 }
00218 if ((sOWO?(rx>xmax):true) && (QABS(rx-xmax)<snap) && (QABS(xmax-rx) < deltaX))
00219 {
00220 deltaX = rx-xmax;
00221 nx = xmax - cw;
00222 }
00223
00224 if ((sOWO?(cy<ymin):true) && (QABS(ymin-cy)<snap))
00225 {
00226 deltaY = ymin-cy;
00227 ny = ymin;
00228 }
00229 if ((sOWO?(ry>ymax):true) && (QABS(ry-ymax)<snap) && (QABS(ymax-ry) < deltaY))
00230 {
00231 deltaY =ry-ymax;
00232 ny = ymax - ch;
00233 }
00234 }
00235
00236
00237 snap = options->windowSnapZone;
00238 if (snap)
00239 {
00240 QValueList<Client *>::ConstIterator l;
00241 for (l = clients.begin();l != clients.end();++l )
00242 {
00243 if ((*l)->isOnDesktop(currentDesktop()) &&
00244 !(*l)->isMinimized()
00245 && (*l) != c )
00246 {
00247 lx = (*l)->x();
00248 ly = (*l)->y();
00249 lrx = lx + (*l)->width();
00250 lry = ly + (*l)->height();
00251
00252 if ( (( cy <= lry ) && ( cy >= ly )) ||
00253 (( ry >= ly ) && ( ry <= lry )) ||
00254 (( cy <= ly ) && ( ry >= lry )) )
00255 {
00256 if ((sOWO?(cx<lrx):true) && (QABS(lrx-cx)<snap) && ( QABS(lrx -cx) < deltaX) )
00257 {
00258 deltaX = QABS( lrx - cx );
00259 nx = lrx;
00260 }
00261 if ((sOWO?(rx>lx):true) && (QABS(rx-lx)<snap) && ( QABS( rx - lx )<deltaX) )
00262 {
00263 deltaX = QABS(rx - lx);
00264 nx = lx - cw;
00265 }
00266 }
00267
00268 if ( (( cx <= lrx ) && ( cx >= lx )) ||
00269 (( rx >= lx ) && ( rx <= lrx )) ||
00270 (( cx <= lx ) && ( rx >= lrx )) )
00271 {
00272 if ((sOWO?(cy<lry):true) && (QABS(lry-cy)<snap) && (QABS( lry -cy ) < deltaY))
00273 {
00274 deltaY = QABS( lry - cy );
00275 ny = lry;
00276 }
00277
00278 if ((sOWO?(ry>ly):true) && (QABS(ry-ly)<snap) && (QABS( ry - ly ) < deltaY ))
00279 {
00280 deltaY = QABS( ry - ly );
00281 ny = ly - ch;
00282 }
00283 }
00284 }
00285 }
00286 }
00287 pos = QPoint(nx, ny);
00288 }
00289 return pos;
00290 }
00291
00295 void Workspace::setClientIsMoving( Client *c )
00296 {
00297 Q_ASSERT(!c || !movingClient);
00298
00299 movingClient = c;
00300 if (movingClient)
00301 ++block_focus;
00302 else
00303 --block_focus;
00304 }
00305
00309 void Workspace::cascadeDesktop()
00310 {
00311
00312 Q_ASSERT( block_stacking_updates == 0 );
00313 ClientList::ConstIterator it(stackingOrder().begin());
00314 bool re_init_cascade_at_first_client = true;
00315 for (; it != stackingOrder().end(); ++it)
00316 {
00317 if((!(*it)->isOnDesktop(currentDesktop())) ||
00318 ((*it)->isMinimized()) ||
00319 ((*it)->isOnAllDesktops()) ||
00320 (!(*it)->isMovable()) )
00321 continue;
00322 initPositioning->placeCascaded(*it, QRect(), re_init_cascade_at_first_client);
00323
00324 if (re_init_cascade_at_first_client)
00325 re_init_cascade_at_first_client = false;
00326 }
00327 }
00328
00333 void Workspace::unclutterDesktop()
00334 {
00335 ClientList::Iterator it(clients.fromLast());
00336 for (; it != clients.end(); --it)
00337 {
00338 if((!(*it)->isOnDesktop(currentDesktop())) ||
00339 ((*it)->isMinimized()) ||
00340 ((*it)->isOnAllDesktops()) ||
00341 (!(*it)->isMovable()) )
00342 continue;
00343 initPositioning->placeSmart(*it, QRect());
00344 }
00345 }
00346
00347
00348 void Workspace::updateTopMenuGeometry( Client* c )
00349 {
00350 if( !managingTopMenus())
00351 return;
00352 if( c != NULL )
00353 {
00354 XEvent ev;
00355 ev.xclient.display = qt_xdisplay();
00356 ev.xclient.type = ClientMessage;
00357 ev.xclient.window = c->window();
00358 static Atom msg_type_atom = XInternAtom( qt_xdisplay(), "_KDE_TOPMENU_MINSIZE", False );
00359 ev.xclient.message_type = msg_type_atom;
00360 ev.xclient.format = 32;
00361 ev.xclient.data.l[0] = qt_x_time;
00362 ev.xclient.data.l[1] = topmenu_space->width();
00363 ev.xclient.data.l[2] = topmenu_space->height();
00364 ev.xclient.data.l[3] = 0;
00365 ev.xclient.data.l[4] = 0;
00366 XSendEvent( qt_xdisplay(), c->window(), False, NoEventMask, &ev );
00367 KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 );
00368 c->checkWorkspacePosition();
00369 return;
00370 }
00371
00372 QRect area;
00373 area = clientArea( MaximizeFullArea, QPoint( 0, 0 ), 1 );
00374 area.setHeight( topMenuHeight());
00375 topmenu_space->setGeometry( area );
00376 for( ClientList::ConstIterator it = topmenus.begin();
00377 it != topmenus.end();
00378 ++it )
00379 updateTopMenuGeometry( *it );
00380 }
00381
00382
00383
00384
00385
00386
00387 void Client::keepInArea( const QRect& area )
00388 {
00389 if ( geometry().right() > area.right() && width() < area.width() )
00390 move( area.right() - width(), y() );
00391 if ( geometry().bottom() > area.bottom() && height() < area.height() )
00392 move( x(), area.bottom() - height() );
00393 if( !area.contains( geometry().topLeft() ))
00394 {
00395 int tx = x();
00396 int ty = y();
00397 if ( tx < area.x() )
00398 tx = area.x();
00399 if ( ty < area.y() )
00400 ty = area.y();
00401 move( tx, ty );
00402 }
00403 }
00404
00410
00411 QRect Client::adjustedClientArea( const QRect& area ) const
00412 {
00413 QRect r = area;
00414
00415 if( isTopMenu())
00416 return r;
00417 NETStrut strut = info->strut();
00418 if ( strut.left > 0 )
00419 r.setLeft( r.left() + (int) strut.left );
00420 if ( strut.top > 0 )
00421 r.setTop( r.top() + (int) strut.top );
00422 if ( strut.right > 0 )
00423 r.setRight( r.right() - (int) strut.right );
00424 if ( strut.bottom > 0 )
00425 r.setBottom( r.bottom() - (int) strut.bottom );
00426 return r;
00427 }
00428
00429
00430
00431
00432 void Client::updateWorkareaDiffs()
00433 {
00434 QRect area = workspace()->clientArea( WorkArea, this );
00435 QRect geom = geometry();
00436 workarea_diff_x = computeWorkareaDiff( geom.left(), geom.right(), area.left(), area.right());
00437 workarea_diff_y = computeWorkareaDiff( geom.top(), geom.bottom(), area.top(), area.bottom());
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 int Client::computeWorkareaDiff( int left, int right, int a_left, int a_right )
00449 {
00450 int left_diff = left - a_left;
00451 int right_diff = a_right - right;
00452 if( left_diff < 0 || right_diff < 0 )
00453 return INT_MIN;
00454 else
00455 {
00456
00457 int max_diff = ( a_right - a_left ) / 10;
00458 if( left_diff < right_diff )
00459 return left_diff < max_diff ? -left_diff - 1 : INT_MAX;
00460 else if( left_diff > right_diff )
00461 return right_diff < max_diff ? right_diff + 1 : INT_MAX;
00462 return INT_MAX;
00463 }
00464 }
00465
00466 void Client::checkWorkspacePosition()
00467 {
00468 if( maximizeMode() != MaximizeRestore )
00469
00470 changeMaximize( false, false, true );
00471
00472 if( isFullScreen())
00473 {
00474 QRect area = workspace()->clientArea( MaximizeFullArea, this );
00475 if( geometry() != area )
00476 setGeometry( area );
00477 return;
00478 }
00479 if( isDock())
00480 return;
00481 if( isOverride())
00482 return;
00483 if( isTopMenu())
00484 {
00485 if( workspace()->managingTopMenus())
00486 {
00487 QRect area;
00488 ClientList mainclients = mainClients();
00489 if( mainclients.count() == 1 )
00490 area = workspace()->clientArea( MaximizeFullArea, mainclients.first());
00491 else
00492 area = workspace()->clientArea( MaximizeFullArea, QPoint( 0, 0 ), desktop());
00493 area.setHeight( workspace()->topMenuHeight());
00494
00495 setGeometry( area );
00496 }
00497 return;
00498 }
00499
00500 if( !isShade())
00501 {
00502 int old_diff_x = workarea_diff_x;
00503 int old_diff_y = workarea_diff_y;
00504 updateWorkareaDiffs();
00505
00506
00507
00508
00509
00510
00511 if( workspace()->initializing())
00512 return;
00513
00514 QRect area = workspace()->clientArea( WorkArea, this );
00515 QRect new_geom = geometry();
00516 QRect tmp_rect_x( new_geom.left(), 0, new_geom.width(), 0 );
00517 QRect tmp_area_x( area.left(), 0, area.width(), 0 );
00518 checkDirection( workarea_diff_x, old_diff_x, tmp_rect_x, tmp_area_x );
00519
00520 QRect tmp_rect_y( new_geom.top(), 0, new_geom.height(), 0 );
00521 QRect tmp_area_y( area.top(), 0, area.height(), 0 );
00522 checkDirection( workarea_diff_y, old_diff_y, tmp_rect_y, tmp_area_y );
00523 new_geom = QRect( tmp_rect_x.left(), tmp_rect_y.left(), tmp_rect_x.width(), tmp_rect_y.width());
00524 QRect final_geom( new_geom.topLeft(), adjustedSize( new_geom.size()));
00525 if( final_geom != new_geom )
00526 {
00527 if( old_diff_x != INT_MAX && old_diff_x > 0 )
00528 final_geom.moveRight( area.right() - ( old_diff_x - 1 ));
00529 if( old_diff_y != INT_MAX && old_diff_y > 0 )
00530 final_geom.moveBottom( area.bottom() - ( old_diff_y - 1 ));
00531 }
00532 if( final_geom != geometry() )
00533 setGeometry( final_geom );
00534
00535 }
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 void Client::checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area )
00549 {
00550 if( old_diff != INT_MIN )
00551 {
00552 if( old_diff == INT_MAX )
00553 {
00554 if( new_diff == INT_MIN )
00555 {
00556 rect.setLeft( area.left());
00557 rect.setRight( area.right());
00558 }
00559 return;
00560 }
00561 if( isResizable())
00562 {
00563 if( rect.width() > area.width())
00564 rect.setWidth( area.width());
00565 if( rect.width() >= area.width() / 2 )
00566 {
00567 if( old_diff < 0 )
00568 rect.setLeft( area.left() + ( -old_diff - 1 ) );
00569 else
00570 rect.setRight( area.right() - ( old_diff - 1 ));
00571 }
00572 }
00573 if( isMovable())
00574 {
00575 if( old_diff < 0 )
00576 rect.moveLeft( area.left() + ( -old_diff - 1 ));
00577 else
00578 rect.moveRight( area.right() - ( old_diff - 1 ));
00579 }
00580
00581
00582
00583 if( isResizable())
00584 {
00585 if( old_diff < 0 )
00586 rect.setLeft( area.left() + ( -old_diff - 1 ) );
00587 else
00588 rect.setRight( area.right() - ( old_diff - 1 ));
00589 }
00590 }
00591 if( rect.right() < area.left() + 5 || rect.left() > area.right() - 5 )
00592 {
00593 if( isMovable())
00594 {
00595 if( rect.left() < area.left() + 5 )
00596 rect.moveRight( area.left() + 5 );
00597 if( rect.right() > area.right() - 5 )
00598 rect.moveLeft( area.right() - 5 );
00599 }
00600 }
00601 }
00602
00606 QSize Client::adjustedSize( const QSize& frame, Sizemode mode ) const
00607 {
00608
00609
00610 QSize wsize( frame.width() - ( border_left + border_right ),
00611 frame.height() - ( border_top + border_bottom ));
00612
00613 return sizeForClientSize( wsize, mode );
00614 }
00615
00624 QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode ) const
00625 {
00626 int w = wsize.width();
00627 int h = wsize.height();
00628 if (w<1) w = 1;
00629 if (h<1) h = 1;
00630
00631
00632
00633 QSize min_size( xSizeHint.min_width, xSizeHint.min_height );
00634 QSize max_size( xSizeHint.max_width, xSizeHint.max_height );
00635 if( decoration != NULL )
00636 {
00637 QSize decominsize = decoration->minimumSize();
00638 QSize border_size( border_left + border_right, border_top + border_bottom );
00639 if( border_size.width() > decominsize.width())
00640 decominsize.setWidth( border_size.width());
00641 if( border_size.height() > decominsize.height())
00642 decominsize.setHeight( border_size.height());
00643 if( decominsize.width() > min_size.width())
00644 min_size.setWidth( decominsize.width());
00645 if( decominsize.height() > min_size.height())
00646 min_size.setHeight( decominsize.height());
00647 }
00648 w = QMIN( max_size.width(), w );
00649 h = QMIN( max_size.height(), h );
00650 w = QMAX( min_size.width(), w );
00651 h = QMAX( min_size.height(), h );
00652
00653 int width_inc = xSizeHint.width_inc;
00654 int height_inc = xSizeHint.height_inc;
00655 int basew_inc = xSizeHint.min_width;
00656 int baseh_inc = xSizeHint.min_height;
00657 w = int(( w - basew_inc ) / width_inc ) * width_inc + basew_inc;
00658 h = int(( h - baseh_inc ) / height_inc ) * height_inc + baseh_inc;
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 if( xSizeHint.flags & PAspect )
00675 {
00676 double min_aspect_w = xSizeHint.min_aspect.x;
00677 double min_aspect_h = xSizeHint.min_aspect.y;
00678 double max_aspect_w = xSizeHint.max_aspect.x;
00679 double max_aspect_h = xSizeHint.max_aspect.y;
00680 w -= xSizeHint.base_width;
00681 h -= xSizeHint.base_height;
00682 int max_width = max_size.width() - xSizeHint.base_width;
00683 int min_width = min_size.width() - xSizeHint.base_width;
00684 int max_height = max_size.height() - xSizeHint.base_height;
00685 int min_height = min_size.height() - xSizeHint.base_height;
00686 #define ASPECT_CHECK_GROW_W \
00687 if( min_aspect_w * h > min_aspect_h * w ) \
00688 { \
00689 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
00690 if( w + delta <= max_width ) \
00691 w += delta; \
00692 }
00693 #define ASPECT_CHECK_SHRINK_H_GROW_W \
00694 if( min_aspect_w * h > min_aspect_h * w ) \
00695 { \
00696 int delta = int( h - w * min_aspect_h / min_aspect_w ) / height_inc * height_inc; \
00697 if( h - delta >= min_height ) \
00698 h -= delta; \
00699 else \
00700 { \
00701 int delta = int( min_aspect_w * h / min_aspect_h - w ) / width_inc * width_inc; \
00702 if( w + delta <= max_width ) \
00703 w += delta; \
00704 } \
00705 }
00706 #define ASPECT_CHECK_GROW_H \
00707 if( max_aspect_w * h < max_aspect_h * w ) \
00708 { \
00709 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
00710 if( h + delta <= max_height ) \
00711 h += delta; \
00712 }
00713 #define ASPECT_CHECK_SHRINK_W_GROW_H \
00714 if( max_aspect_w * h < max_aspect_h * w ) \
00715 { \
00716 int delta = int( w - max_aspect_w * h / max_aspect_h ) / width_inc * width_inc; \
00717 if( w - delta >= min_width ) \
00718 w -= delta; \
00719 else \
00720 { \
00721 int delta = int( w * max_aspect_h / max_aspect_w - h ) / height_inc * height_inc; \
00722 if( h + delta <= max_height ) \
00723 h += delta; \
00724 } \
00725 }
00726 switch( mode )
00727 {
00728 case SizemodeAny:
00729 {
00730 ASPECT_CHECK_SHRINK_H_GROW_W
00731 ASPECT_CHECK_SHRINK_W_GROW_H
00732 ASPECT_CHECK_GROW_H
00733 ASPECT_CHECK_GROW_W
00734 break;
00735 }
00736 case SizemodeFixedW:
00737 {
00738
00739 ASPECT_CHECK_GROW_H
00740 ASPECT_CHECK_SHRINK_H_GROW_W
00741 ASPECT_CHECK_SHRINK_W_GROW_H
00742 ASPECT_CHECK_GROW_W
00743 break;
00744 }
00745 case SizemodeFixedH:
00746 {
00747 ASPECT_CHECK_GROW_W
00748 ASPECT_CHECK_SHRINK_W_GROW_H
00749 ASPECT_CHECK_SHRINK_H_GROW_W
00750 ASPECT_CHECK_GROW_H
00751 break;
00752 }
00753 case SizemodeMax:
00754 {
00755
00756 ASPECT_CHECK_SHRINK_H_GROW_W
00757 ASPECT_CHECK_SHRINK_W_GROW_H
00758 ASPECT_CHECK_GROW_W
00759 ASPECT_CHECK_GROW_H
00760 break;
00761 }
00762 case SizemodeShaded:
00763 break;
00764 }
00765 #undef ASPECT_CHECK_SHRINK_H_GROW_W
00766 #undef ASPECT_CHECK_SHRINK_W_GROW_H
00767 #undef ASPECT_CHECK_GROW_W
00768 #undef ASPECT_CHECK_GROW_H
00769 w += xSizeHint.base_width;
00770 h += xSizeHint.base_height;
00771 }
00772
00773 if ( mode == SizemodeShaded && wsize.height() == 0 )
00774 h = 0;
00775 return QSize( w + border_left + border_right, h + border_top + border_bottom );
00776 }
00777
00781 void Client::getWmNormalHints()
00782 {
00783 long msize;
00784 if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 )
00785 xSizeHint.flags = 0;
00786
00787
00788
00789
00790
00791 if( xSizeHint.flags & PBaseSize )
00792 {
00793 if( ! ( xSizeHint.flags & PMinSize ))
00794 {
00795 xSizeHint.flags |= PMinSize;
00796 xSizeHint.min_width = xSizeHint.base_width;
00797 xSizeHint.min_height = xSizeHint.base_height;
00798 }
00799 }
00800 else
00801 xSizeHint.base_width = xSizeHint.base_height = 0;
00802 if( ! ( xSizeHint.flags & PMinSize ))
00803 xSizeHint.min_width = xSizeHint.min_height = 0;
00804 if( ! ( xSizeHint.flags & PMaxSize ))
00805 xSizeHint.max_width = xSizeHint.max_height = INT_MAX;
00806 if( xSizeHint.flags & PResizeInc )
00807 {
00808 xSizeHint.width_inc = kMax( xSizeHint.width_inc, 1 );
00809 xSizeHint.height_inc = kMax( xSizeHint.height_inc, 1 );
00810 }
00811 else
00812 {
00813 xSizeHint.width_inc = 1;
00814 xSizeHint.height_inc = 1;
00815 }
00816 if( xSizeHint.flags & PAspect )
00817 {
00818 xSizeHint.min_aspect.y = kMax( xSizeHint.min_aspect.y, 1 );
00819 xSizeHint.max_aspect.y = kMax( xSizeHint.max_aspect.y, 1 );
00820 }
00821 else
00822 {
00823 xSizeHint.min_aspect.x = 1;
00824 xSizeHint.min_aspect.y = INT_MAX;
00825 xSizeHint.max_aspect.x = INT_MAX;
00826 xSizeHint.max_aspect.y = 1;
00827 }
00828 if( ! ( xSizeHint.flags & PWinGravity ))
00829 xSizeHint.win_gravity = NorthWestGravity;
00830 if( isManaged())
00831 {
00832 QSize new_size = adjustedSize( size());
00833 if( new_size != size() && !isShade())
00834 resizeWithChecks( new_size );
00835 }
00836 updateAllowedActions();
00837 }
00838
00844 void Client::sendSyntheticConfigureNotify()
00845 {
00846 XConfigureEvent c;
00847 c.type = ConfigureNotify;
00848 c.send_event = True;
00849 c.event = window();
00850 c.window = window();
00851 c.x = x() + clientPos().x();
00852 c.y = y() + clientPos().y();
00853 c.width = clientSize().width();
00854 c.height = clientSize().height();
00855 c.border_width = 0;
00856 c.above = None;
00857 c.override_redirect = 0;
00858 XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
00859 }
00860
00861 const QPoint Client::calculateGravitation( bool invert, int gravity ) const
00862 {
00863 int dx, dy;
00864 dx = dy = 0;
00865
00866 if( gravity == 0 )
00867 gravity = xSizeHint.win_gravity;
00868
00869
00870 switch (gravity)
00871 {
00872 case NorthWestGravity:
00873 default:
00874 dx = border_left;
00875 dy = border_top;
00876 break;
00877 case NorthGravity:
00878 dx = 0;
00879 dy = border_top;
00880 break;
00881 case NorthEastGravity:
00882 dx = -border_right;
00883 dy = border_top;
00884 break;
00885 case WestGravity:
00886 dx = border_left;
00887 dy = 0;
00888 break;
00889 case CenterGravity:
00890 break;
00891 case StaticGravity:
00892 dx = 0;
00893 dy = 0;
00894 break;
00895 case EastGravity:
00896 dx = -border_right;
00897 dy = 0;
00898 break;
00899 case SouthWestGravity:
00900 dx = border_left ;
00901 dy = -border_bottom;
00902 break;
00903 case SouthGravity:
00904 dx = 0;
00905 dy = -border_bottom;
00906 break;
00907 case SouthEastGravity:
00908 dx = -border_right;
00909 dy = -border_bottom;
00910 break;
00911 }
00912 if( gravity != CenterGravity )
00913 {
00914 dx -= border_left;
00915 dy -= border_top;
00916 }
00917 else
00918 {
00919 dx = - ( border_left + border_right ) / 2;
00920 dy = - ( border_top + border_bottom ) / 2;
00921 }
00922 if( !invert )
00923 return QPoint( x() + dx, y() + dy );
00924 else
00925 return QPoint( x() - dx, y() - dy );
00926 }
00927
00928 void Client::configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity )
00929 {
00930 if( gravity == 0 )
00931 gravity = xSizeHint.win_gravity;
00932 if( value_mask & ( CWX | CWY ))
00933 {
00934 QPoint new_pos = calculateGravitation( true, gravity );
00935 if ( value_mask & CWX )
00936 new_pos.setX( rx );
00937 if ( value_mask & CWY )
00938 new_pos.setY( ry );
00939
00940
00941
00942
00943
00944 if ( new_pos.x() == x() + clientPos().x() &&
00945 new_pos.y() == y() + clientPos().y() && gravity == NorthWestGravity )
00946 {
00947 new_pos.setX( x());
00948 new_pos.setY( y());
00949 }
00950
00951 int nw = clientSize().width();
00952 int nh = clientSize().height();
00953 if ( value_mask & CWWidth )
00954 nw = rw;
00955 if ( value_mask & CWHeight )
00956 nh = rh;
00957 QSize ns = sizeForClientSize( QSize( nw, nh ) );
00958
00959
00960 if ( maximizeMode() != MaximizeFull
00961 || ns != size())
00962 {
00963 resetMaximize();
00964 ++block_geometry;
00965 move( new_pos );
00966 plainResize( ns );
00967 --block_geometry;
00968 setGeometry( QRect( calculateGravitation( false, gravity ), size()), ForceGeometrySet );
00969 }
00970 }
00971
00972 if ( value_mask & (CWWidth | CWHeight )
00973 && ! ( value_mask & ( CWX | CWY )) )
00974 {
00975 if ( isShade())
00976 setShade( ShadeNone );
00977
00978 int nw = clientSize().width();
00979 int nh = clientSize().height();
00980 if ( value_mask & CWWidth )
00981 nw = rw;
00982 if ( value_mask & CWHeight )
00983 nh = rh;
00984 QSize ns = sizeForClientSize( QSize( nw, nh ) );
00985
00986 if( ns != size())
00987 {
00988 resetMaximize();
00989 int save_gravity = xSizeHint.win_gravity;
00990 xSizeHint.win_gravity = gravity;
00991 resizeWithChecks( ns );
00992 xSizeHint.win_gravity = save_gravity;
00993 }
00994 }
00995
00996
00997
00998 }
00999
01000 void Client::resizeWithChecks( int w, int h, ForceGeometry_t force )
01001 {
01002 int newx = x();
01003 int newy = y();
01004 QRect area = workspace()->clientArea( WorkArea, this );
01005
01006 if( w > area.width())
01007 w = area.width();
01008 if( h > area.height())
01009 h = area.height();
01010 QSize tmp = adjustedSize( QSize( w, h ));
01011 w = tmp.width();
01012 h = tmp.height();
01013 switch( xSizeHint.win_gravity )
01014 {
01015 case NorthWestGravity:
01016 default:
01017 break;
01018 case NorthGravity:
01019 newx = ( newx + width() / 2 ) - ( w / 2 );
01020 break;
01021 case NorthEastGravity:
01022 newx = newx + width() - w;
01023 break;
01024 case WestGravity:
01025 newy = ( newy + height() / 2 ) - ( h / 2 );
01026 break;
01027 case CenterGravity:
01028 newx = ( newx + width() / 2 ) - ( w / 2 );
01029 newy = ( newy + height() / 2 ) - ( h / 2 );
01030 break;
01031 case StaticGravity:
01032
01033 break;
01034 case EastGravity:
01035 newx = newx + width() - w;
01036 newy = ( newy + height() / 2 ) - ( h / 2 );
01037 break;
01038 case SouthWestGravity:
01039 newy = newy + height() - h;
01040 break;
01041 case SouthGravity:
01042 newx = ( newx + width() / 2 ) - ( w / 2 );
01043 newy = newy + height() - h;
01044 break;
01045 case SouthEastGravity:
01046 newx = newx + width() - w;
01047 newy = newy + height() - h;
01048 break;
01049 }
01050
01051
01052 if( workarea_diff_x != INT_MIN && w <= area.width())
01053 {
01054 if( newx < area.left())
01055 newx = area.left();
01056 if( newx + w > area.right() + 1 )
01057 newx = area.right() + 1 - w;
01058 assert( newx >= area.left() && newx + w <= area.right() + 1 );
01059 }
01060 if( workarea_diff_y != INT_MIN && h <= area.height())
01061 {
01062 if( newy < area.top())
01063 newy = area.top();
01064 if( newy + h > area.bottom() + 1 )
01065 newy = area.bottom() + 1 - h;
01066 assert( newy >= area.top() && newy + h <= area.bottom() + 1 );
01067 }
01068 setGeometry( newx, newy, w, h, force );
01069 }
01070
01071
01072 void Client::NETMoveResizeWindow( int flags, int x, int y, int width, int height )
01073 {
01074 int gravity = flags & 0xff;
01075 int value_mask = 0;
01076 if( flags & ( 1 << 8 ))
01077 value_mask |= CWX;
01078 if( flags & ( 1 << 9 ))
01079 value_mask |= CWY;
01080 if( flags & ( 1 << 10 ))
01081 value_mask |= CWWidth;
01082 if( flags & ( 1 << 11 ))
01083 value_mask |= CWHeight;
01084 configureRequest( value_mask, x, y, width, height, gravity );
01085 }
01086
01090 bool Client::isResizable() const
01091 {
01092 if ( !isMovable() || !motif_may_resize || isSplash())
01093 return FALSE;
01094
01095 if ( ( xSizeHint.flags & PMaxSize) == 0 || (xSizeHint.flags & PMinSize ) == 0 )
01096 return TRUE;
01097 return ( xSizeHint.min_width < xSizeHint.max_width ) ||
01098 ( xSizeHint.min_height < xSizeHint.max_height );
01099 }
01100
01101
01102
01103
01104 bool Client::isMaximizable() const
01105 {
01106 if ( maximizeMode() != MaximizeRestore )
01107 return TRUE;
01108 if( !isResizable() || isToolbar())
01109 return false;
01110 if( xSizeHint.max_height < 32767 || xSizeHint.max_width < 32767 )
01111 return false;
01112 return true;
01113 }
01114
01115
01119 void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
01120 {
01121 if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h ))
01122 return;
01123 frame_geometry = QRect( x, y, w, h );
01124 if( !isShade())
01125 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01126 else
01127 {
01128
01129 if( !shade_geometry_change && h != border_top + border_bottom )
01130 {
01131 kdDebug() << "h:" << h << ":t:" << border_top << ":b:" << border_bottom << endl;
01132 assert( false );
01133 }
01134 client_size = QSize( w - border_left - border_right, client_size.height());
01135 }
01136 updateWorkareaDiffs();
01137 if( block_geometry == 0 )
01138 {
01139 XMoveResizeWindow( qt_xdisplay(), frameId(), x, y, w, h );
01140 resizeDecoration( QSize( w, h ));
01141 if( !isShade())
01142 {
01143 QSize cs = clientSize();
01144 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01145 cs.width(), cs.height());
01146
01147 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01148 }
01149 if( shape())
01150 updateShape();
01151
01152 updateWorkareaDiffs();
01153 sendSyntheticConfigureNotify();
01154 }
01155 }
01156
01157 void Client::plainResize( int w, int h, ForceGeometry_t force )
01158 {
01159 if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h ))
01160 return;
01161 frame_geometry.setSize( QSize( w, h ));
01162 if( !isShade())
01163 client_size = QSize( w - border_left - border_right, h - border_top - border_bottom );
01164 else
01165 {
01166
01167 if( !shade_geometry_change && h != border_top + border_bottom )
01168 {
01169 kdDebug() << "h:" << h << ":t:" << border_top << ":b:" << border_bottom << endl;
01170 assert( false );
01171 }
01172 client_size = QSize( w - border_left - border_right, client_size.height());
01173 }
01174 updateWorkareaDiffs();
01175 if( block_geometry == 0 )
01176 {
01177
01178 XResizeWindow( qt_xdisplay(), frameId(), w, h );
01179 resizeDecoration( QSize( w, h ));
01180 if( !isShade())
01181 {
01182 QSize cs = clientSize();
01183 XMoveResizeWindow( qt_xdisplay(), wrapperId(), clientPos().x(), clientPos().y(),
01184 cs.width(), cs.height());
01185 XMoveResizeWindow( qt_xdisplay(), window(), 0, 0, cs.width(), cs.height());
01186 }
01187 if( shape())
01188 updateShape();
01189 updateWorkareaDiffs();
01190 sendSyntheticConfigureNotify();
01191 }
01192 }
01193
01197 void Client::move( int x, int y, ForceGeometry_t force )
01198 {
01199 if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y ))
01200 return;
01201 frame_geometry.moveTopLeft( QPoint( x, y ));
01202 updateWorkareaDiffs();
01203 if( block_geometry == 0 )
01204 {
01205 XMoveWindow( qt_xdisplay(), frameId(), x, y );
01206 sendSyntheticConfigureNotify();
01207 }
01208 }
01209
01210
01211 void Client::maximize( MaximizeMode m )
01212 {
01213 setMaximize( m & MaximizeVertical, m & MaximizeHorizontal );
01214 }
01215
01219 void Client::setMaximize( bool vertically, bool horizontally )
01220 {
01221 changeMaximize(
01222 max_mode & MaximizeVertical ? !vertically : vertically,
01223 max_mode & MaximizeHorizontal ? !horizontally : horizontally,
01224 false );
01225 }
01226
01227 void Client::changeMaximize( bool vertical, bool horizontal, bool adjust )
01228 {
01229 if( !isMaximizable())
01230 return;
01231
01232 ++block_geometry;
01233
01234 if( isShade())
01235 setShade( ShadeNone );
01236
01237 MaximizeMode old_mode = max_mode;
01238
01239 if( !adjust )
01240 {
01241 if( vertical )
01242 max_mode = MaximizeMode( max_mode ^ MaximizeVertical );
01243 if( horizontal )
01244 max_mode = MaximizeMode( max_mode ^ MaximizeHorizontal );
01245 }
01246
01247
01248 Q_ASSERT( !( vertical && horizontal )
01249 || (( max_mode & MaximizeVertical != 0 ) == ( max_mode & MaximizeHorizontal != 0 )));
01250
01251
01252 bool maximalizing = false;
01253 if( vertical && !(old_mode & MaximizeVertical ))
01254 {
01255 geom_restore.setTop( y());
01256 geom_restore.setHeight( height());
01257 maximalizing = true;
01258 }
01259 if( horizontal && !( old_mode & MaximizeHorizontal ))
01260 {
01261 geom_restore.setLeft( x());
01262 geom_restore.setWidth( width());
01263 maximalizing = true;
01264 }
01265
01266 if( !adjust )
01267 {
01268 if( maximalizing )
01269 Notify::raise( Notify::Maximize );
01270 else
01271 Notify::raise( Notify::UnMaximize );
01272 }
01273
01274 if( decoration != NULL )
01275 decoration->borders( border_left, border_right, border_top, border_bottom );
01276
01277 QRect clientArea = workspace()->clientArea( MaximizeArea, this );
01278
01279 switch (max_mode)
01280 {
01281
01282 case MaximizeVertical:
01283 {
01284 if( old_mode & MaximizeHorizontal )
01285 {
01286 if( geom_restore.width() == 0 )
01287 {
01288 plainResize( adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH ));
01289 workspace()->placeSmart( this, clientArea );
01290 }
01291 else
01292 setGeometry( QRect(QPoint( geom_restore.x(), clientArea.top()),
01293 adjustedSize(QSize( geom_restore.width(), clientArea.height()), SizemodeFixedH )));
01294 }
01295 else
01296 setGeometry( QRect(QPoint(x(), clientArea.top()),
01297 adjustedSize(QSize(width(), clientArea.height()), SizemodeFixedH )));
01298 info->setState( NET::MaxVert, NET::Max );
01299 break;
01300 }
01301
01302 case MaximizeHorizontal:
01303 {
01304 if( old_mode & MaximizeVertical )
01305 {
01306 if( geom_restore.height() == 0 )
01307 {
01308 plainResize( adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW ));
01309 workspace()->placeSmart( this, clientArea );
01310 }
01311 else
01312 setGeometry( QRect( QPoint(clientArea.left(), geom_restore.y()),
01313 adjustedSize(QSize(clientArea.width(), geom_restore.height()), SizemodeFixedW )));
01314 }
01315 else
01316 setGeometry( QRect( QPoint(clientArea.left(), y()),
01317 adjustedSize(QSize(clientArea.width(), height()), SizemodeFixedW )));
01318 info->setState( NET::MaxHoriz, NET::Max );
01319 break;
01320 }
01321
01322 case MaximizeRestore:
01323 {
01324 QRect restore = geometry();
01325
01326 if( old_mode & MaximizeVertical )
01327 {
01328 restore.setTop( geom_restore.top());
01329 restore.setBottom( geom_restore.bottom());
01330 }
01331 if( old_mode & MaximizeHorizontal )
01332 {
01333 restore.setLeft( geom_restore.left());
01334 restore.setRight( geom_restore.right());
01335 }
01336 if( !restore.isValid())
01337 {
01338 QSize s = QSize( clientArea.width()*2/3, clientArea.height()*2/3 );
01339 if( geom_restore.width() > 0 )
01340 s.setWidth( geom_restore.width());
01341 if( geom_restore.height() > 0 )
01342 s.setHeight( geom_restore.height());
01343 plainResize( adjustedSize( s ));
01344 workspace()->placeSmart( this, clientArea );
01345 restore = geometry();
01346 if( geom_restore.width() > 0 )
01347 restore.moveLeft( geom_restore.x());
01348 if( geom_restore.height() > 0 )
01349 restore.moveTop( geom_restore.y());
01350 }
01351 setGeometry( restore );
01352 info->setState( 0, NET::Max );
01353 break;
01354 }
01355
01356 case MaximizeFull:
01357 {
01358 QSize adjSize = adjustedSize(clientArea.size(), SizemodeMax );
01359 QRect r = QRect(clientArea.topLeft(), adjSize);
01360 setGeometry( r );
01361 info->setState( NET::Max, NET::Max );
01362 break;
01363 }
01364 default:
01365 break;
01366 }
01367
01368 --block_geometry;
01369 setGeometry( geometry(), ForceGeometrySet );
01370
01371 updateAllowedActions();
01372 if( decoration != NULL )
01373 decoration->maximizeChange();
01374 }
01375
01376 void Client::resetMaximize()
01377 {
01378 if( max_mode == MaximizeRestore )
01379 return;
01380 max_mode = MaximizeRestore;
01381 Notify::raise( Notify::UnMaximize );
01382 info->setState( 0, NET::Max );
01383 updateAllowedActions();
01384 if( decoration != NULL )
01385 decoration->borders( border_left, border_right, border_top, border_bottom );
01386 setGeometry( geometry(), ForceGeometrySet );
01387 if( decoration != NULL )
01388 decoration->maximizeChange();
01389 }
01390
01391 bool Client::isFullScreenable( bool fullscreen_hack ) const
01392 {
01393 if( fullscreen_hack )
01394 return isNormalWindow() || isOverride();
01395 else
01396 return !isSpecialWindow();
01397 }
01398
01399 bool Client::userCanSetFullScreen() const
01400 {
01401 return isNormalWindow() && fullscreen_mode != FullScreenHack
01402 && ( isMaximizable() || isFullScreen());
01403 }
01404
01405 void Client::setFullScreen( bool set, bool user )
01406 {
01407 if( !isFullScreen() && !set )
01408 return;
01409 if( fullscreen_mode == FullScreenHack )
01410 return;
01411 if( user && !userCanSetFullScreen())
01412 return;
01413 setShade( ShadeNone );
01414 bool was_fs = isFullScreen();
01415 if( !was_fs )
01416 geom_fs_restore = geometry();
01417 fullscreen_mode = set ? FullScreenNormal : FullScreenNone;
01418 if( was_fs == isFullScreen())
01419 return;
01420 StackingUpdatesBlocker blocker( workspace());
01421 workspace()->updateClientLayer( this );
01422 info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen );
01423 updateDecoration( false, false );
01424 if( isFullScreen())
01425 setGeometry( workspace()->clientArea( MaximizeFullArea, this ));
01426 else
01427 {
01428 if( maximizeMode() != MaximizeRestore )
01429 changeMaximize( false, false, true );
01430 else if( !geom_fs_restore.isNull())
01431 setGeometry( geom_fs_restore );
01432
01433 else
01434 {
01435 setGeometry( workspace()->clientArea( MaximizeArea, this ));
01436 }
01437 }
01438 }
01439
01440
01441 static QRect* visible_bound = 0;
01442 static GeometryTip* geometryTip = 0;
01443
01444 void Client::drawbound( const QRect& geom )
01445 {
01446 assert( visible_bound == NULL );
01447 visible_bound = new QRect( geom );
01448 doDrawbound( *visible_bound, false );
01449 }
01450
01451 void Client::clearbound()
01452 {
01453 if( visible_bound == NULL )
01454 return;
01455 doDrawbound( *visible_bound, true );
01456 delete visible_bound;
01457 visible_bound = 0;
01458 }
01459
01460 void Client::doDrawbound( const QRect& geom, bool clear )
01461 {
01462 if( decoration != NULL && decoration->drawbound( geom, clear ))
01463 return;
01464 QPainter p ( workspace()->desktopWidget() );
01465 p.setPen( QPen( Qt::white, 5 ) );
01466 p.setRasterOp( Qt::XorROP );
01467 p.drawRect( geom );
01468 }
01469
01470 void Client::positionGeometryTip()
01471 {
01472 assert( isMove() || isResize());
01473
01474 if (options->showGeometryTip())
01475 {
01476 if( !geometryTip )
01477 {
01478 bool save_under = ( isMove() && options->moveMode != Options::Opaque )
01479 || ( isResize() && options->resizeMode != Options::Opaque );
01480 geometryTip = new GeometryTip( &xSizeHint, save_under );
01481 }
01482 QRect wgeom( moveResizeGeom );
01483 wgeom.setWidth( wgeom.width() - ( width() - clientSize().width()));
01484 wgeom.setHeight( wgeom.height() - ( height() - clientSize().height()));
01485 if( isShade())
01486 wgeom.setHeight( 0 );
01487 geometryTip->setGeometry( wgeom );
01488 if( !geometryTip->isVisible())
01489 {
01490 geometryTip->show();
01491 geometryTip->raise();
01492 }
01493 }
01494 }
01495
01496 class EatAllPaintEvents
01497 : public QObject
01498 {
01499 protected:
01500 virtual bool eventFilter( QObject* o, QEvent* e )
01501 { return e->type() == QEvent::Paint && o != geometryTip; }
01502 };
01503
01504 static EatAllPaintEvents* eater = 0;
01505
01506 bool Client::startMoveResize()
01507 {
01508 assert( !moveResizeMode );
01509 assert( QWidget::keyboardGrabber() == NULL );
01510 assert( QWidget::mouseGrabber() == NULL );
01511 if( QApplication::activePopupWidget() != NULL )
01512 return false;
01513 bool has_grab = false;
01514
01515
01516
01517 XSetWindowAttributes attrs;
01518 QRect r = workspace()->clientArea( FullArea, this );
01519 move_resize_grab_window = XCreateWindow( qt_xdisplay(), workspace()->rootWin(), r.x(), r.y(),
01520 r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs );
01521 XMapRaised( qt_xdisplay(), move_resize_grab_window );
01522 if( XGrabPointer( qt_xdisplay(), move_resize_grab_window, False,
01523 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
01524 GrabModeAsync, GrabModeAsync, None, cursor.handle(), qt_x_time ) == Success )
01525 has_grab = true;
01526 if( XGrabKeyboard( qt_xdisplay(), frameId(), False, GrabModeAsync, GrabModeAsync, qt_x_time ) == Success )
01527 has_grab = true;
01528 if( !has_grab )
01529 {
01530 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
01531 move_resize_grab_window = None;
01532 return false;
01533 }
01534 if ( maximizeMode() != MaximizeRestore )
01535 resetMaximize();
01536 moveResizeMode = true;
01537 workspace()->setClientIsMoving(this);
01538 initialMoveResizeGeom = moveResizeGeom = geometry();
01539 checkUnrestrictedMoveResize();
01540 if ( ( isMove() && options->moveMode != Options::Opaque )
01541 || ( isResize() && options->resizeMode != Options::Opaque ) )
01542 {
01543 grabXServer();
01544 kapp->sendPostedEvents();
01545
01546
01547
01548
01549
01550 eater = new EatAllPaintEvents;
01551 kapp->installEventFilter( eater );
01552 }
01553 Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
01554 return true;
01555 }
01556
01557 void Client::finishMoveResize( bool cancel )
01558 {
01559 leaveMoveResize();
01560 if( cancel )
01561 setGeometry( initialMoveResizeGeom );
01562 else
01563 setGeometry( moveResizeGeom );
01564
01565 Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
01566 }
01567
01568 void Client::leaveMoveResize()
01569 {
01570 clearbound();
01571 if (geometryTip)
01572 {
01573 geometryTip->hide();
01574 delete geometryTip;
01575 geometryTip = NULL;
01576 }
01577 if ( ( isMove() && options->moveMode != Options::Opaque )
01578 || ( isResize() && options->resizeMode != Options::Opaque ) )
01579 ungrabXServer();
01580 XUngrabKeyboard( qt_xdisplay(), qt_x_time );
01581 XUngrabPointer( qt_xdisplay(), qt_x_time );
01582 XDestroyWindow( qt_xdisplay(), move_resize_grab_window );
01583 move_resize_grab_window = None;
01584 workspace()->setClientIsMoving(0);
01585 if( move_faked_activity )
01586 workspace()->unfakeActivity( this );
01587 move_faked_activity = false;
01588 moveResizeMode = false;
01589 delete eater;
01590 eater = 0;
01591 }
01592
01593
01594
01595
01596
01597 void Client::checkUnrestrictedMoveResize()
01598 {
01599 if( unrestrictedMoveResize )
01600 return;
01601 QRect desktopArea = workspace()->clientArea( WorkArea, moveResizeGeom.center(), desktop());
01602 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
01603
01604
01605 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
01606 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
01607
01608 titlebar_marge = initialMoveResizeGeom.height();
01609 top_marge = border_bottom;
01610 bottom_marge = border_top;
01611 if( isResize())
01612 {
01613 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
01614 unrestrictedMoveResize = true;
01615 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
01616 unrestrictedMoveResize = true;
01617 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
01618 unrestrictedMoveResize = true;
01619 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
01620 unrestrictedMoveResize = true;
01621 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
01622 unrestrictedMoveResize = true;
01623 }
01624 if( isMove())
01625 {
01626 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
01627 unrestrictedMoveResize = true;
01628
01629 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
01630 unrestrictedMoveResize = true;
01631 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
01632 unrestrictedMoveResize = true;
01633 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
01634 unrestrictedMoveResize = true;
01635 }
01636 }
01637
01638 void Client::handleMoveResize( int x, int y, int x_root, int y_root )
01639 {
01640 if(( mode == PositionCenter && !isMovable())
01641 || ( mode != PositionCenter && ( isShade() || !isResizable())))
01642 return;
01643
01644 if ( !moveResizeMode )
01645 {
01646 QPoint p( QPoint( x, y ) - moveOffset );
01647 if (p.manhattanLength() >= 6)
01648 {
01649 if( !startMoveResize())
01650 {
01651 buttonDown = false;
01652 setCursor( mode );
01653 return;
01654 }
01655 }
01656 else
01657 return;
01658 }
01659
01660
01661 if ( mode != PositionCenter && shade_mode != ShadeNone )
01662 setShade( ShadeNone );
01663
01664 QPoint globalPos( x_root, y_root );
01665
01666
01667 QPoint topleft = globalPos - moveOffset;
01668 QPoint bottomright = globalPos + invertedMoveOffset;
01669 QRect previousMoveResizeGeom = moveResizeGeom;
01670
01671
01672
01673
01674
01675 QRect desktopArea = workspace()->clientArea( WorkArea, globalPos, desktop());
01676 int left_marge, right_marge, top_marge, bottom_marge, titlebar_marge;
01677 if( unrestrictedMoveResize )
01678 left_marge = right_marge = top_marge = bottom_marge = titlebar_marge = 5;
01679 else
01680 {
01681
01682 left_marge = KMIN( 100 + border_right, moveResizeGeom.width());
01683 right_marge = KMIN( 100 + border_left, moveResizeGeom.width());
01684
01685 titlebar_marge = initialMoveResizeGeom.height();
01686 top_marge = border_bottom;
01687 bottom_marge = border_top;
01688 }
01689
01690 bool update = false;
01691 if( isResize())
01692 {
01693
01694 QRect orig = initialMoveResizeGeom;
01695 Sizemode sizemode = SizemodeAny;
01696 switch ( mode )
01697 {
01698 case PositionTopLeft:
01699 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
01700 break;
01701 case PositionBottomRight:
01702 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
01703 break;
01704 case PositionBottomLeft:
01705 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
01706 break;
01707 case PositionTopRight:
01708 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
01709 break;
01710 case PositionTop:
01711 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), orig.bottomRight() ) ;
01712 sizemode = SizemodeFixedH;
01713 break;
01714 case PositionBottom:
01715 moveResizeGeom = QRect( orig.topLeft(), QPoint( orig.right(), bottomright.y() ) ) ;
01716 sizemode = SizemodeFixedH;
01717 break;
01718 case PositionLeft:
01719 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), orig.bottomRight() ) ;
01720 sizemode = SizemodeFixedW;
01721 break;
01722 case PositionRight:
01723 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), orig.bottom() ) ) ;
01724 sizemode = SizemodeFixedW;
01725 break;
01726 case PositionCenter:
01727 default:
01728 assert( false );
01729 break;
01730 }
01731
01732
01733 if( moveResizeGeom.bottom() < desktopArea.top() + top_marge )
01734 moveResizeGeom.setBottom( desktopArea.top() + top_marge );
01735 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
01736 moveResizeGeom.setTop( desktopArea.bottom() - bottom_marge );
01737 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
01738 moveResizeGeom.setRight( desktopArea.left() + left_marge );
01739 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
01740 moveResizeGeom.setLeft(desktopArea.right() - right_marge );
01741 if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() )
01742 moveResizeGeom.setTop( desktopArea.top());
01743
01744 QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
01745
01746 topleft = QPoint( moveResizeGeom.right() - size.width() + 1, moveResizeGeom.bottom() - size.height() + 1 );
01747 bottomright = QPoint( moveResizeGeom.left() + size.width() - 1, moveResizeGeom.top() + size.height() - 1 );
01748 orig = moveResizeGeom;
01749 switch ( mode )
01750 {
01751 case PositionTopLeft:
01752 moveResizeGeom = QRect( topleft, orig.bottomRight() ) ;
01753 break;
01754 case PositionBottomRight:
01755 moveResizeGeom = QRect( orig.topLeft(), bottomright ) ;
01756 break;
01757 case PositionBottomLeft:
01758 moveResizeGeom = QRect( QPoint( topleft.x(), orig.y() ), QPoint( orig.right(), bottomright.y()) ) ;
01759 break;
01760 case PositionTopRight:
01761 moveResizeGeom = QRect( QPoint( orig.x(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
01762 break;
01763
01764
01765
01766 case PositionTop:
01767 moveResizeGeom = QRect( QPoint( orig.left(), topleft.y() ), QPoint( bottomright.x(), orig.bottom()) ) ;
01768 break;
01769 case PositionBottom:
01770 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
01771 break;
01772 case PositionLeft:
01773 moveResizeGeom = QRect( QPoint( topleft.x(), orig.top() ), QPoint( orig.right(), bottomright.y()));
01774 break;
01775 case PositionRight:
01776 moveResizeGeom = QRect( orig.topLeft(), QPoint( bottomright.x(), bottomright.y() ) ) ;
01777 break;
01778 case PositionCenter:
01779 default:
01780 assert( false );
01781 break;
01782 }
01783 if( moveResizeGeom.size() != previousMoveResizeGeom.size())
01784 update = true;
01785 }
01786 else if( isMove())
01787 {
01788 assert( mode == PositionCenter );
01789
01790 moveResizeGeom.moveTopLeft( topleft );
01791 moveResizeGeom.moveTopLeft( workspace()->adjustClientPosition( this, moveResizeGeom.topLeft() ) );
01792
01793 if( moveResizeGeom.bottom() < desktopArea.top() + titlebar_marge - 1 )
01794 moveResizeGeom.moveBottom( desktopArea.top() + titlebar_marge - 1 );
01795
01796 if( moveResizeGeom.top() > desktopArea.bottom() - bottom_marge )
01797 moveResizeGeom.moveTop( desktopArea.bottom() - bottom_marge );
01798 if( moveResizeGeom.right() < desktopArea.left() + left_marge )
01799 moveResizeGeom.moveRight( desktopArea.left() + left_marge );
01800 if( moveResizeGeom.left() > desktopArea.right() - right_marge )
01801 moveResizeGeom.moveLeft(desktopArea.right() - right_marge );
01802 if( moveResizeGeom.topLeft() != previousMoveResizeGeom.topLeft())
01803 update = true;
01804 }
01805 else
01806 assert( false );
01807
01808 if( update )
01809 {
01810 if(( isResize() ? options->resizeMode : options->moveMode ) == Options::Opaque )
01811 {
01812 setGeometry( moveResizeGeom );
01813 positionGeometryTip();
01814 }
01815 else if(( isResize() ? options->resizeMode : options->moveMode ) == Options::Transparent )
01816 {
01817 clearbound();
01818 positionGeometryTip();
01819 drawbound( moveResizeGeom );
01820 }
01821 }
01822 if ( isMove() )
01823 workspace()->clientMoved(globalPos, qt_x_time);
01824 }
01825
01826
01827 }