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