1 /*
   2  *
   3  * Compiz application switcher plugin
   4  *
   5  * staticswitcher.cpp
   6  *
   7  * Copyright : (C) 2008 by Danny Baumann
   8  * E-mail    : maniac@compiz-fusion.org
   9  *
  10  * Based on switcher.c:
  11  * Copyright : (C) 2007 David Reveman
  12  * E-mail    : davidr@novell.com
  13  *
  14  * This program is free software; you can redistribute it and/or
  15  * modify it under the terms of the GNU General Public License
  16  * as published by the Free Software Foundation; either version 2
  17  * of the License, or (at your option) any later version.
  18  *
  19  * This program is distributed in the hope that it will be useful,
  20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22  * GNU General Public License for more details.
  23  *
  24  */
  25 
  26 #include "staticswitcher.h"
  27 
  28 COMPIZ_PLUGIN_20090315 (staticswitcher, StaticSwitchPluginVTable)
  29 
  30 const unsigned short PREVIEWSIZE = 150;
  31 const unsigned short BORDER = 10;
  32 
  33 void
  34 StaticSwitchScreen::updatePopupWindow ()
  35 {
  36     int    newXCount, newYCount;
  37     int    winWidth, winHeight;
  38     float  aspect;
  39     int    count = windows.size ();
  40     double dCount = count;
  41     int    w = PREVIEWSIZE, h = PREVIEWSIZE, b = BORDER;
  42     int    x, y;
  43     XSizeHints   xsh;
  44 
  45     /* maximum window size is 2/3 of the current output */
  46     winWidth  = ::screen->currentOutputDev ().width () * 2 / 3;
  47     winHeight = ::screen->currentOutputDev ().height () * 2 / 3;
  48 
  49     if (count <= 4)
  50     {
  51 	/* don't put 4 or less windows in multiple rows */
  52 	newXCount = count;
  53 	newYCount = 1;
  54     }
  55     else
  56     {
  57 	aspect = (float) winWidth / winHeight;
  58 	/* round is available in C99 only, so use a replacement for that */
  59 	newYCount = floor (sqrt (dCount / aspect) + 0.5f);
  60 	newXCount = ceil (dCount / newYCount);
  61     }
  62 
  63     while ((w + b) * newXCount > winWidth ||
  64 	   (h + b) * newYCount > winHeight)
  65     {
  66 	/* shrink by 10% until all windows fit */
  67 	w = w * 9 / 10;
  68 	h = h * 9 / 10;
  69 	b = b * 9 / 10;
  70     }
  71 
  72     winWidth = MIN (count, newXCount);
  73     winHeight = (count + newXCount - 1) / newXCount;
  74 
  75     winWidth = winWidth * w + (winWidth + 1) * b;
  76     winHeight = winHeight * h + (winHeight + 1) * b;
  77     xCount = MIN (newXCount, count);
  78 
  79     previewWidth = w;
  80     previewHeight = h;
  81     previewBorder = b;
  82 
  83     x = ::screen->currentOutputDev ().region ()->extents.x1 +
  84 	::screen->currentOutputDev ().width () / 2;
  85     y = ::screen->currentOutputDev ().region ()->extents.y1 +
  86 	::screen->currentOutputDev ().height () / 2;
  87 
  88     xsh.flags       = PSize | PPosition | PWinGravity;
  89     xsh.x           = x;
  90     xsh.y           = y;
  91     xsh.width       = winWidth;
  92     xsh.height      = winHeight;
  93     xsh.win_gravity = StaticGravity;
  94 
  95     XSetWMNormalHints (::screen->dpy (), popupWindow, &xsh);
  96 
  97     CompWindow *popup = screen->findWindow (popupWindow);
  98 
  99     XWindowChanges xwc;
 100     unsigned int valueMask = 0;
 101 
 102     valueMask |= (CWX | CWY | CWWidth | CWHeight);
 103 
 104     xwc.x = x - winWidth / 2;
 105     xwc.y = y - winHeight / 2;
 106     xwc.width = winWidth;
 107     xwc.height = winHeight;
 108 
 109     if (popup)
 110 	popup->configureXWindow (valueMask, &xwc);
 111     else
 112 	XConfigureWindow (::screen->dpy (), popupWindow,
 113 			   valueMask, &xwc);
 114 }
 115 
 116 void
 117 StaticSwitchScreen::updateWindowList ()
 118 {
 119     pos  = 0;
 120     move = 0;
 121 
 122     selectedWindow = windows.front ();
 123 
 124     if (popupWindow)
 125 	updatePopupWindow ();
 126 }
 127 
 128 void
 129 StaticSwitchScreen::createWindowList ()
 130 {
 131     windows.clear ();
 132 
 133     foreach (CompWindow *w, ::screen->windows ())
 134     {
 135 	SWITCH_WINDOW (w);
 136 
 137 	if (sw->isSwitchWin ())
 138 	{
 139 	    windows.push_back (w);
 140 
 141 	    sw->cWindow->damageRectSetEnabled (sw, true);
 142 	}
 143     }
 144 
 145     windows.sort (BaseSwitchScreen::compareWindows);
 146 
 147     updateWindowList ();
 148 }
 149 
 150 bool
 151 StaticSwitchWindow::damageRect (bool initial, const CompRect &rect)
 152 {
 153     return BaseSwitchWindow::damageRect (initial, rect);
 154 }
 155 
 156 BaseSwitchWindow::IconMode
 157 StaticSwitchWindow::getIconMode ()
 158 {
 159     if (sScreen->optionGetIconOnly ())
 160 	return ShowIconOnly;
 161     if (!sScreen->optionGetIcon ())
 162 	return HideIcon;
 163 
 164     return ShowIcon;
 165 }
 166 
 167 bool
 168 StaticSwitchScreen::getPaintRectangle (CompWindow *w,
 169 				       CompRect   &rect,
 170 				       int        *opacity)
 171 {
 172     int mode;
 173 
 174     mode = optionGetHighlightRectHidden ();
 175 
 176     if (w->isViewable () || w->shaded ())
 177     {
 178     	rect = w->borderRect ();
 179 	return true;
 180     }
 181     else if (mode == HighlightRectHiddenTaskbarEntry &&
 182     	     (w->iconGeometry ().x1 () != 0 ||
 183 	      w->iconGeometry ().y1 () != 0 ||
 184 	      w->iconGeometry ().x2 () != 0 ||
 185 	      w->iconGeometry ().y2 () != 0))
 186     {
 187     	rect = w->iconGeometry ();
 188 	return true;
 189     }
 190     else if (mode == HighlightRectHiddenOriginalWindowPosition)
 191     {
 192     	rect = w->serverBorderRect ();
 193 
 194 	if (opacity)
 195 	    *opacity /= 4;
 196 
 197 	return true;
 198     }
 199 
 200     return false;
 201 }
 202 
 203 void
 204 StaticSwitchScreen::doWindowDamage (CompWindow *w)
 205 {
 206     if (w->isViewable () || w->shaded ())
 207     {
 208     	CompositeWindow::get (w)->addDamage ();
 209     }
 210     else
 211     {
 212 	CompRect box;
 213 	if (getPaintRectangle (w, box, NULL))
 214 	{
 215 	    CompRect boxExtended (box.x () - 2,
 216 	    			  box.y () - 2,
 217 	    			  box.width () + 4,
 218 	    			  box.height () + 4);
 219 
 220 	    cScreen->damageRegion (CompRegion (boxExtended));
 221 	}
 222     }
 223 }
 224 
 225 void
 226 StaticSwitchScreen::handleSelectionChange (bool toNext, int nextIdx)
 227 {
 228     move = nextIdx;
 229     moreAdjust = true;
 230 }
 231 
 232 void
 233 StaticSwitchScreen::createPopup ()
 234 {
 235     if (!popupWindow)
 236     {
 237 	Display		     *dpy = ::screen->dpy ();
 238 	XWMHints	     xwmh;
 239 	XClassHint           xch;
 240 	Atom		     state[4];
 241 	int		     nState = 0;
 242 	XSetWindowAttributes attr;
 243 	Visual		     *visual;
 244 
 245 	visual = findArgbVisual (dpy, ::screen->screenNum ());
 246 	if (!visual)
 247 	    return;
 248 
 249 	xwmh.flags = InputHint;
 250 	xwmh.input = 0;
 251 
 252 	xch.res_name  = (char *)"compiz";
 253 	xch.res_class = (char *)"switcher-window";
 254 
 255 	attr.background_pixel = 0;
 256 	attr.border_pixel     = 0;
 257 	attr.colormap	      = XCreateColormap (dpy, ::screen->root (), visual,
 258 						 AllocNone);
 259 	attr.override_redirect = 1;
 260 
 261 	popupWindow =
 262 	    XCreateWindow (dpy, ::screen->root (),
 263 	    		   -1, -1, 1, 1, 0,
 264 			   32, InputOutput, visual,
 265 			   CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect, &attr);
 266 
 267 	XSetWMProperties (dpy, popupWindow, NULL, NULL,
 268 			  programArgv, programArgc,
 269 			  NULL, &xwmh, &xch);
 270 
 271 	state[nState++] = Atoms::winStateAbove;
 272 	state[nState++] = Atoms::winStateSticky;
 273 	state[nState++] = Atoms::winStateSkipTaskbar;
 274 	state[nState++] = Atoms::winStateSkipPager;
 275 
 276 	XChangeProperty (dpy, popupWindow,
 277 			 Atoms::winState,
 278 			 XA_ATOM, 32, PropModeReplace,
 279 			 (unsigned char *) state, nState);
 280 
 281 	XChangeProperty (dpy, popupWindow,
 282 			 Atoms::winType,
 283 			 XA_ATOM, 32, PropModeReplace,
 284 			 (unsigned char *) &Atoms::winTypeUtil, 1);
 285 
 286 	::screen->setWindowProp (popupWindow, Atoms::winDesktop, 0xffffffff);
 287 
 288 	setSelectedWindowHint (false);
 289 
 290 	updatePopupWindow ();
 291     }
 292 }
 293 
 294 bool
 295 StaticSwitchScreen::showPopup ()
 296 {
 297     /* Always checks for an existing popup */
 298     createPopup ();
 299 
 300     XMapWindow (::screen->dpy (), popupWindow);
 301 
 302     cScreen->damageScreen ();
 303 
 304     popupDelayTimer.stop ();
 305 
 306     return false;
 307 }
 308 
 309 Cursor
 310 StaticSwitchScreen::getCursor (bool mouseSelectOn)
 311 {
 312     if (mouseSelectOn)
 313 	return ::screen->normalCursor ();
 314 
 315     return ::screen->invisibleCursor ();
 316 }
 317 
 318 void
 319 StaticSwitchScreen::initiate (SwitchWindowSelection selection,
 320 			      bool                  shouldShowPopup)
 321 {
 322     bool noSwitchWindows;
 323     bool newMouseSelect;
 324 
 325     if (::screen->otherGrabExist ("switcher", "scale", "cube", 0))
 326 	return;
 327 
 328     this->selection      = selection;
 329     selectedWindow       = NULL;
 330 
 331     noSwitchWindows = true;
 332     foreach (CompWindow *w, ::screen->windows ())
 333     {
 334 	if (StaticSwitchWindow::get (w)->isSwitchWin ())
 335 	{
 336 	    noSwitchWindows = false;
 337 	    break;
 338 	}
 339     }
 340     if (noSwitchWindows)
 341 	return;
 342 
 343     newMouseSelect = optionGetMouseSelect () &&
 344     	             selection != Panels && shouldShowPopup;
 345 
 346     if (!grabIndex)
 347 	grabIndex = ::screen->pushGrab (getCursor (newMouseSelect), "switcher");
 348     else if (newMouseSelect != mouseSelect)
 349 	::screen->updateGrab (grabIndex, getCursor (newMouseSelect));
 350 
 351     mouseSelect = newMouseSelect;
 352 
 353     if (grabIndex)
 354     {
 355 	if (!switching)
 356 	{
 357 	    lastActiveNum = ::screen->activeNum ();
 358 
 359 	    createWindowList ();
 360 
 361 	    if (shouldShowPopup)
 362 	    {
 363 		unsigned int delay;
 364 
 365 		delay = optionGetPopupDelay () * 1000;
 366 		if (delay)
 367 		{
 368 		    if (popupDelayTimer.active ())
 369 			popupDelayTimer.stop ();
 370 
 371 		    popupDelayTimer.start
 372 			(boost::bind (&StaticSwitchScreen::showPopup, this),
 373 			 delay, delay * 1.2);
 374 		}
 375 		else
 376 		{
 377 		    showPopup ();
 378 		}
 379 
 380 		setSelectedWindowHint (optionGetFocusOnSwitch ());
 381 	    }
 382 
 383 	    lastActiveWindow = screen->activeWindow ();
 384 	    activateEvent (true);
 385 	}
 386 
 387 	cScreen->damageScreen ();
 388 
 389 	switching  = true;
 390 	moreAdjust = true;
 391 
 392 	::screen->handleEventSetEnabled (this, true);
 393 	cScreen->preparePaintSetEnabled (this, true);
 394 	cScreen->donePaintSetEnabled (this, true);
 395 	gScreen->glPaintOutputSetEnabled (this, true);
 396 
 397 	foreach (CompWindow *w, ::screen->windows ())
 398 	{
 399 	    SWITCH_WINDOW (w);
 400 
 401 	    sw->gWindow->glPaintSetEnabled (sw, true);
 402 	}
 403     }
 404 }
 405 
 406 static bool
 407 switchTerminate (CompAction         *action,
 408 	         CompAction::State  state,
 409 	         CompOption::Vector &options)
 410 {
 411     Window     xid;
 412 
 413     xid = (Window) CompOption::getIntOptionNamed (options, "root");
 414 
 415     if (action)
 416 	action->setState (action->state () &
 417 			  (unsigned)~(CompAction::StateTermKey |
 418 			  	      CompAction::StateTermButton));
 419 
 420     if (xid && xid != ::screen->root ())
 421 	return false;
 422 
 423     SWITCH_SCREEN (screen);
 424 
 425     if (ss->grabIndex)
 426     {
 427 	if (ss->popupDelayTimer.active ())
 428 	    ss->popupDelayTimer.stop ();
 429 
 430 	if (ss->popupWindow)
 431 	    XUnmapWindow (::screen->dpy (), ss->popupWindow);
 432 
 433 	ss->switching = false;
 434 
 435 	if (state & CompAction::StateCancel)
 436 	    ss->selectedWindow = NULL;
 437 
 438 	if (state && ss->selectedWindow && !ss->selectedWindow->destroyed ())
 439 	    ::screen->sendWindowActivationRequest (ss->selectedWindow->id ());
 440 
 441 	::screen->removeGrab (ss->grabIndex, 0);
 442 	ss->grabIndex = NULL;
 443 
 444 	if (!ss->popupWindow)
 445 	    ::screen->handleEventSetEnabled (ss, false);
 446 
 447 	ss->selectedWindow = NULL;
 448 
 449 	if (screen->activeWindow () != ss->lastActiveWindow)
 450 	{
 451 	    CompWindow *w = screen->findWindow (ss->lastActiveWindow);
 452 
 453 	    if (w)
 454 		w->moveInputFocusTo ();
 455 	}
 456 
 457 	ss->setSelectedWindowHint (false);
 458 
 459 	ss->lastActiveNum = 0;
 460 
 461 	ss->cScreen->damageScreen ();
 462     }
 463 
 464     return false;
 465 }
 466 
 467 static bool
 468 switchInitiateCommon (CompAction            *action,
 469 		      CompAction::State     state,
 470 		      CompOption::Vector    &options,
 471 		      SwitchWindowSelection selection,
 472 		      bool                  shouldShowPopup,
 473 		      bool                  nextWindow)
 474 {
 475     Window     xid;
 476 
 477     xid = (Window) CompOption::getIntOptionNamed (options, "root");
 478 
 479     if (xid != ::screen->root ())
 480 	return false;
 481 
 482     SWITCH_SCREEN (::screen);
 483 
 484     if (!ss->switching)
 485     {
 486 	if (selection == Group)
 487 	{
 488 	    CompWindow *w;
 489 	    Window     xid;
 490 
 491 	    xid = (Window) CompOption::getIntOptionNamed (options, "window");
 492 	    w = ::screen->findWindow (xid);
 493 	    if (w)
 494 		ss->clientLeader = (w->clientLeader ()) ?
 495 				   w->clientLeader () : xid;
 496 	    else
 497 		ss->clientLeader = None;
 498 	}
 499 
 500 	ss->initiate (selection, shouldShowPopup);
 501 
 502 	if (state & CompAction::StateInitKey)
 503 	    action->setState (action->state () | CompAction::StateTermKey);
 504 
 505 	if (state & CompAction::StateInitEdge)
 506 	    action->setState (action->state () | CompAction::StateTermEdge);
 507 	else if (state & CompAction::StateInitButton)
 508 	    action->setState (action->state () | CompAction::StateTermButton);
 509     }
 510 
 511     ss->switchToWindow (nextWindow, ss->optionGetAutoChangeVp (), ss->optionGetFocusOnSwitch ());
 512 
 513     return false;
 514 }
 515 
 516 void
 517 StaticSwitchScreen::getMinimizedAndMatch (bool &minimizedOption,
 518 					  CompMatch *&matchOption)
 519 {
 520     minimizedOption = optionGetMinimized ();
 521     matchOption = &optionGetWindowMatch ();
 522 }
 523 
 524 bool
 525 StaticSwitchScreen::getMipmap ()
 526 {
 527     return optionGetMipmap ();
 528 }
 529 
 530 void
 531 StaticSwitchScreen::windowRemove (CompWindow *w)
 532 {
 533     if (w)
 534     {
 535 	bool   inList = false;
 536 
 537 	CompWindow *selected;
 538 	CompWindow *old;
 539 
 540 	SWITCH_WINDOW (w);
 541 
 542 	if (!sw->isSwitchWin (true))
 543 	    return;
 544 
 545 	sw->cWindow->damageRectSetEnabled (sw, false);
 546 	sw->gWindow->glPaintSetEnabled (sw, false);
 547 
 548 	old = selected = selectedWindow;
 549 
 550 	CompWindowList::iterator it = windows.begin ();
 551 	while (it != windows.end ())
 552 	{
 553 	    if (*it == w)
 554 	    {
 555 		inList = true;
 556 
 557 		if (w == selected)
 558 		{
 559 		    ++it;
 560 		    if (it == windows.end ())
 561 			selected = windows.front ();
 562 		    else
 563 			selected = *it;
 564 		    --it;
 565 		}
 566 
 567 		CompWindowList::iterator del = it;
 568 		++it;
 569 		windows.erase (del);
 570 	    }
 571 	    else
 572 		++it;
 573 	}
 574 
 575 	if (!inList)
 576 	    return;
 577 
 578 	if (windows.size () == 0)
 579 	{
 580 	    CompOption::Vector o (0);
 581 	    o.push_back (CompOption ("root", CompOption::TypeInt));
 582 	    o[0].value ().set ((int) ::screen->root ());
 583 
 584 	    switchTerminate (NULL, 0, o);
 585 	    return;
 586 	}
 587 
 588 	if (!grabIndex)
 589 	    return;
 590 
 591 	updateWindowList ();
 592 
 593 	int i = 0;
 594 	foreach (CompWindow *w, windows)
 595 	{
 596 	    selectedWindow = w;
 597 	    move = pos = i;
 598 
 599 	    if (selectedWindow == selected)
 600 		break;
 601 	    i++;
 602 	}
 603 
 604 	if (popupWindow)
 605 	{
 606 	    CompWindow *popup;
 607 
 608 	    popup = ::screen->findWindow (popupWindow);
 609 	    if (popup)
 610 		CompositeWindow::get (popup)->addDamage ();
 611 
 612 	    setSelectedWindowHint (optionGetFocusOnSwitch ());
 613 	}
 614 
 615 	if (old != selectedWindow)
 616 	{
 617 	    CompositeWindow::get (selectedWindow)->addDamage ();
 618 	    CompositeWindow::get (w)->addDamage ();
 619 
 620 	    if (old && !old->destroyed ())
 621 		CompositeWindow::get (old)->addDamage ();
 622 
 623 	    moreAdjust = true;
 624 	}
 625     }
 626 }
 627 
 628 int
 629 StaticSwitchScreen::getRowXOffset (int y)
 630 {
 631     int retval = 0;
 632     int count = windows.size ();
 633 
 634     if (count - (y * (int)xCount) >= (int)xCount)
 635 	return 0;
 636 
 637     switch (optionGetRowAlign ()) {
 638     case RowAlignLeft:
 639 	break;
 640     case RowAlignCentered:
 641 	retval = (xCount - count + (y * (int)xCount)) *
 642 	         (previewWidth + previewBorder) / 2;
 643 	break;
 644     case RowAlignRight:
 645 	retval = (xCount - count + (y * (int)xCount)) *
 646 	         (previewWidth + previewBorder);
 647 	break;
 648     }
 649 
 650     return retval;
 651 }
 652 
 653 void
 654 StaticSwitchScreen::getWindowPosition (unsigned int index,
 655 				       int          *x,
 656 				       int          *y)
 657 {
 658     int row, column;
 659 
 660     if (index >= windows.size ())
 661 	return;
 662 
 663     column = (int)index % xCount;
 664     row    = (int)index / xCount;
 665 
 666     *x = column * previewWidth + (column + 1) * previewBorder;
 667     *x += getRowXOffset (row);
 668 
 669     *y = row * previewHeight + (row + 1) * previewBorder;
 670 }
 671 
 672 CompWindow *
 673 StaticSwitchScreen::findWindowAt (int x,
 674 				  int y)
 675 {
 676     CompWindow *popup;
 677 
 678     popup = ::screen->findWindow (popupWindow);
 679     if (popup)
 680     {
 681 	unsigned int i = 0;
 682 	foreach (CompWindow *w, windows)
 683 	{
 684 	    int x1, x2, y1, y2;
 685 
 686 	    getWindowPosition (i, &x1, &y1);
 687 
 688 	    x1 += popup->geometry ().x ();
 689 	    y1 += popup->geometry ().y ();
 690 
 691 	    x2 = x1 + previewWidth;
 692 	    y2 = y1 + previewHeight;
 693 
 694 	    if (x >= x1 && x < x2 && y >= y1 && y < y2)
 695 		return w;
 696 
 697 	    i++;
 698 	}
 699     }
 700 
 701     return NULL;
 702 }
 703 
 704 void
 705 StaticSwitchScreen::handleEvent (XEvent *event)
 706 {
 707     BaseSwitchScreen::handleEvent (event);
 708 
 709     switch (event->type)
 710     {
 711     case ButtonPress:
 712 	if (grabIndex && mouseSelect)
 713 	{
 714 	    CompWindow *selected;
 715 
 716 	    selected = findWindowAt (event->xbutton.x_root,
 717 	    			     event->xbutton.y_root);
 718 	    if (selected)
 719 	    {
 720 	    	selectedWindow = selected;
 721 
 722 	    	CompOption::Vector o (0);
 723 	    	o.push_back (CompOption ("root", CompOption::TypeInt));
 724 	    	o[0].value ().set ((int) ::screen->root ());
 725 
 726 	    	switchTerminate (NULL, CompAction::StateTermButton, o);
 727 	    }
 728 	}
 729 	break;
 730     default:
 731 	break;
 732     }
 733 }
 734 
 735 bool
 736 StaticSwitchScreen::adjustVelocity ()
 737 {
 738     float dx, adjust, amount;
 739     int   count = windows.size ();
 740 
 741     dx = move - pos;
 742     if (abs (dx) > abs (dx + count))
 743 	dx += count;
 744     if (abs (dx) > abs (dx - count))
 745 	dx -= count;
 746 
 747     adjust = dx * 0.15f;
 748     amount = fabs (dx) * 1.5f;
 749     if (amount < 0.2f)
 750 	amount = 0.2f;
 751     else if (amount > 2.0f)
 752 	amount = 2.0f;
 753 
 754     mVelocity = (amount * mVelocity + adjust) / (amount + 1.0f);
 755 
 756     if (fabs (dx) < 0.001f && fabs (mVelocity) < 0.001f)
 757     {
 758 	mVelocity = 0.0f;
 759 	return false;
 760     }
 761 
 762     return true;
 763 }
 764 
 765 void
 766 StaticSwitchScreen::preparePaint (int msSinceLastPaint)
 767 {
 768     if (moreAdjust)
 769     {
 770 	int   steps;
 771 	float amount, chunk;
 772 	int   count = windows.size ();
 773 
 774 	amount = msSinceLastPaint * 0.05f * optionGetSpeed ();
 775 	steps  = amount / (0.5f * optionGetTimestep ());
 776 	if (!steps) steps = 1;
 777 	chunk  = amount / (float) steps;
 778 
 779 	while (steps--)
 780 	{
 781 	    moreAdjust = adjustVelocity ();
 782 	    if (!moreAdjust)
 783 	    {
 784 		pos = move;
 785 		break;
 786 	    }
 787 
 788 	    pos += mVelocity * chunk;
 789 	    pos = fmod (pos, count);
 790 	    if (pos < 0.0)
 791 		pos += count;
 792 	}
 793     }
 794 
 795     cScreen->preparePaint (msSinceLastPaint);
 796 }
 797 
 798 void
 799 StaticSwitchScreen::paintRect (const GLMatrix &transform,
 800                                CompRect       &box,
 801 			       int offset,
 802 			       unsigned short *color,
 803 			       unsigned short opacity)
 804 {
 805     GLushort colorData[4] = {
 806 	color[0],
 807 	color[1],
 808 	color[2],
 809 	static_cast <GLushort> (color[3] * opacity / 100)
 810     };
 811 
 812     GLfloat vertexData[12] = {
 813 	static_cast <GLfloat> (box.x1 () + offset), static_cast <GLfloat> (box.y1 () + offset), 0,
 814 	static_cast <GLfloat> (box.x2 () - offset), static_cast <GLfloat> (box.y1 () + offset), 0,
 815 	static_cast <GLfloat> (box.x2 () - offset), static_cast <GLfloat> (box.y2 () - offset), 0,
 816 	static_cast <GLfloat> (box.x1 () + offset), static_cast <GLfloat> (box.y2 () - offset), 0
 817     };
 818 
 819     GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
 820     streamingBuffer->begin (GL_LINE_LOOP);
 821 
 822     streamingBuffer->addColors (1, colorData);
 823     streamingBuffer->addVertices (4, vertexData);
 824 
 825     streamingBuffer->end ();
 826     streamingBuffer->render (transform);
 827 }
 828 
 829 bool
 830 StaticSwitchScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
 831 				   const GLMatrix            &transform,
 832 				   const CompRegion          &region,
 833 				   CompOutput                *output,
 834 				   unsigned int              mask)
 835 {
 836     bool status;
 837 
 838     if (grabIndex)
 839     {
 840 	int        mode;
 841 	CompWindow *switcher, *zoomed;
 842 	Window	   zoomedAbove = None;
 843 
 844 	if (!popupDelayTimer.active ())
 845 	    mode = optionGetHighlightMode ();
 846 	else
 847 	    mode = HighlightModeNone;
 848 
 849 	if (mode == HighlightModeBringSelectedToFront)
 850 	{
 851 	    CompWindow *frontWindow = ::screen->clientList ().back ();
 852 
 853 	    zoomed = selectedWindow;
 854 	    if (zoomed && zoomed != frontWindow)
 855 	    {
 856 		CompWindow *w;
 857 
 858 		for (w = zoomed->prev; w && w->id () <= 1; w = w->prev)
 859 		    ;
 860 		zoomedAbove = (w) ? w->id () : None;
 861 
 862 		::screen->unhookWindow (zoomed);
 863 		::screen->insertWindow (zoomed, frontWindow->id ());
 864 	    }
 865 	    else
 866 	    {
 867 		zoomed = NULL;
 868 	    }
 869 	}
 870 	else
 871 	{
 872 	    zoomed = NULL;
 873 	}
 874 
 875 	ignoreSwitcher = true;
 876 
 877 	status = gScreen->glPaintOutput (sAttrib, transform, region, output,
 878 					 mask);
 879 
 880 	if (zoomed)
 881 	{
 882 	    ::screen->unhookWindow (zoomed);
 883 	    ::screen->insertWindow (zoomed, zoomedAbove);
 884 	}
 885 
 886 	ignoreSwitcher = false;
 887 
 888 	switcher = ::screen->findWindow (popupWindow);
 889 
 890 	if (switcher || mode == HighlightModeShowRectangle)
 891 	{
 892 	    GLMatrix   sTransform (transform);
 893 
 894 	    sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
 895 
 896 	    if (mode == HighlightModeShowRectangle)
 897 	    {
 898 		CompWindow *w;
 899 
 900 		w = selectedWindow;
 901 
 902 		if (w)
 903 		{
 904 		    CompRect box;
 905 		    int      opacity = 100;
 906 
 907 		    if (getPaintRectangle (w, box, &opacity))
 908 		    {
 909 			unsigned short *color;
 910 			GLushort        colorData[4];
 911 			GLfloat         vertexData[12];
 912 			GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
 913 
 914 			glEnable (GL_BLEND);
 915 
 916 			/* fill rectangle */
 917 			colorData[0] = optionGetHighlightColorRed ();
 918 			colorData[1] = optionGetHighlightColorGreen ();
 919 			colorData[2] = optionGetHighlightColorBlue ();
 920 			colorData[3] = optionGetHighlightColorAlpha ();
 921 			colorData[3] = colorData[3] * opacity / 100;
 922 
 923 			vertexData[0]  = box.x1 ();
 924 			vertexData[1]  = box.y2 ();
 925 			vertexData[2]  = 0.0f;
 926 			vertexData[3]  = box.x1 ();
 927 			vertexData[4]  = box.y1 ();
 928 			vertexData[5]  = 0.0f;
 929 			vertexData[6]  = box.x2 ();
 930 			vertexData[7]  = box.y2 ();
 931 			vertexData[8]  = 0.0f;
 932 			vertexData[9]  = box.x2 ();
 933 			vertexData[10] = box.y1 ();
 934 			vertexData[11] = 0.0f;
 935 
 936 			streamingBuffer->begin (GL_TRIANGLE_STRIP);
 937 			streamingBuffer->addColors (1, colorData);
 938 			streamingBuffer->addVertices (4, vertexData);
 939 			streamingBuffer->end ();
 940 			streamingBuffer->render (sTransform);
 941 
 942 			/* draw outline */
 943 			glLineWidth (1.0);
 944 
 945 			color = optionGetHighlightBorderColor ();
 946 			paintRect (sTransform, box, 0, color, opacity);
 947 			paintRect (sTransform, box, 2, color, opacity);
 948 			color = optionGetHighlightBorderInlayColor ();
 949 			paintRect (sTransform, box, 1, color, opacity);
 950 
 951 			glDisable (GL_BLEND);
 952 		    }
 953 		}
 954 	    }
 955 
 956 	    if (switcher)
 957 	    {
 958 	    	SWITCH_WINDOW (switcher);
 959 
 960 		if (!switcher->destroyed () &&
 961 		    switcher->isViewable () &&
 962 		    sw->cWindow->damaged ())
 963 		{
 964 		    sw->gWindow->glPaint (sw->gWindow->paintAttrib (),
 965 					  sTransform, infiniteRegion, 0);
 966 		}
 967 	    }
 968 	}
 969     }
 970     else
 971     {
 972 	status = gScreen->glPaintOutput (sAttrib, transform, region, output,
 973 					 mask);
 974     }
 975 
 976     return status;
 977 }
 978 
 979 void
 980 StaticSwitchScreen::donePaint ()
 981 {
 982     if (grabIndex && moreAdjust)
 983     {
 984 	CompWindow *w;
 985 
 986 	w = ::screen->findWindow (popupWindow);
 987 	if (w)
 988 	    CompositeWindow::get (w)->addDamage ();
 989     }
 990     else if (!grabIndex && !moreAdjust)
 991     {
 992 	activateEvent (false);
 993 
 994 	cScreen->preparePaintSetEnabled (this, false);
 995 	cScreen->donePaintSetEnabled (this, false);
 996 	gScreen->glPaintOutputSetEnabled (this, false);
 997 
 998 	foreach (CompWindow *w, ::screen->windows ())
 999 	{
1000 	    SWITCH_WINDOW (w);
1001 	    sw->cWindow->damageRectSetEnabled (sw, false);
1002 	    sw->gWindow->glPaintSetEnabled (sw, false);
1003 	}
1004     }
1005 
1006     cScreen->donePaint ();
1007 }
1008 
1009 void
1010 StaticSwitchScreen::paintSelectionRect (const GLMatrix &transform,
1011                                         int             x,
1012 					int          y,
1013 					float        dx,
1014 					float        dy,
1015 					unsigned int opacity)
1016 {
1017     GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
1018     GLushort        colorData[4];
1019     GLfloat         vertexData[18];
1020     GLMatrix        sTransform (transform);
1021     float op;
1022     int   w, h;
1023     int   count = windows.size ();
1024 
1025     w = previewWidth + previewBorder;
1026     h = previewHeight + previewBorder;
1027 
1028     glEnable (GL_BLEND);
1029 
1030     if (dx > xCount - 1)
1031 	op = 1.0 - MIN (1.0, dx - (xCount - 1));
1032     else if (dx + (dy * xCount) > count - 1)
1033 	op = 1.0 - MIN (1.0, dx - (count - 1 - (dy * xCount)));
1034     else if (dx < 0.0)
1035 	op = 1.0 + MAX (-1.0, dx);
1036     else
1037 	op = 1.0;
1038 
1039     for (unsigned int i = 0; i < 4; i++)
1040 	colorData[i] = (float)fgColor[i] * opacity * op / 0xffff;
1041 
1042     sTransform.translate (x + previewBorder / 2 + (dx * w),
1043 		  y + previewBorder / 2 + (dy * h), 0.0f);
1044 
1045     streamingBuffer->begin (GL_TRIANGLE_STRIP);
1046 
1047     vertexData[0]  = -1;
1048     vertexData[1]  = -1;
1049     vertexData[2]  = 0;
1050     vertexData[3]  = -1;
1051     vertexData[4]  = 1;
1052     vertexData[5]  = 0;
1053     vertexData[6]  = w + 1;
1054     vertexData[7]  = -1;
1055     vertexData[8]  = 0;
1056     vertexData[9]  = w + 1;
1057     vertexData[10] = 1;
1058     vertexData[11] = 0;
1059 
1060     streamingBuffer->addColors (1, colorData);
1061     streamingBuffer->addVertices (4, vertexData);
1062 
1063     streamingBuffer->end ();
1064     streamingBuffer->render (sTransform);
1065 
1066 
1067     streamingBuffer->begin (GL_TRIANGLE_STRIP);
1068 
1069     vertexData[0]  = -1;
1070     vertexData[1]  = h - 1;
1071     vertexData[2]  = 0;
1072     vertexData[3]  = -1;
1073     vertexData[4]  = h + 1;
1074     vertexData[5]  = 0;
1075     vertexData[6]  = w + 1;
1076     vertexData[7]  = h - 1;
1077     vertexData[8]  = 0;
1078     vertexData[9]  = w + 1;
1079     vertexData[10] = h + 1;
1080     vertexData[11] = 0;
1081 
1082     streamingBuffer->addColors (1, colorData);
1083     streamingBuffer->addVertices (4, vertexData);
1084 
1085     streamingBuffer->end ();
1086     streamingBuffer->render (sTransform);
1087 
1088 
1089     streamingBuffer->begin (GL_TRIANGLE_STRIP);
1090 
1091     vertexData[0]  = -1;
1092     vertexData[1]  = 1;
1093     vertexData[2]  = 0;
1094     vertexData[3]  = -1;
1095     vertexData[4]  = h - 1;
1096     vertexData[5]  = 0;
1097     vertexData[6]  = 1;
1098     vertexData[7]  = 1;
1099     vertexData[8]  = 0;
1100     vertexData[9]  = 1;
1101     vertexData[10] = h - 1;
1102     vertexData[11] = 0;
1103 
1104     streamingBuffer->addColors (1, colorData);
1105     streamingBuffer->addVertices (4, vertexData);
1106 
1107     streamingBuffer->end ();
1108     streamingBuffer->render (sTransform);
1109 
1110 
1111     streamingBuffer->begin (GL_TRIANGLE_STRIP);
1112 
1113     vertexData[0]  = w - 1;
1114     vertexData[1]  = 1;
1115     vertexData[2]  = 0;
1116     vertexData[3]  = w - 1;
1117     vertexData[4]  = h - 1;
1118     vertexData[5]  = 0;
1119     vertexData[6]  = w + 1;
1120     vertexData[7]  = 1;
1121     vertexData[8]  = 0;
1122     vertexData[9]  = w + 1;
1123     vertexData[10] = h - 1;
1124     vertexData[11] = 0;
1125 
1126     streamingBuffer->addColors (1, colorData);
1127     streamingBuffer->addVertices (4, vertexData);
1128 
1129     streamingBuffer->end ();
1130     streamingBuffer->render (sTransform);
1131 
1132     glDisable (GL_BLEND);
1133 }
1134 
1135 bool
1136 StaticSwitchWindow::isSwitchWin (bool removing)
1137 {
1138     bool baseIsSwitchWin = BaseSwitchWindow::isSwitchWin (removing);
1139 
1140     if (baseIsSwitchWin && sScreen->selection == Group)
1141     {
1142 	if (sScreen->clientLeader != window->clientLeader () &&
1143 	    sScreen->clientLeader != window->id ())
1144 	    return false;
1145     }
1146 
1147     return baseIsSwitchWin;
1148 }
1149 
1150 void
1151 StaticSwitchWindow::updateIconTexturedWindow (GLWindowPaintAttrib  &sAttrib,
1152 					      int                  &wx,
1153 					      int                  &wy,
1154 					      int                  x,
1155 					      int                  y,
1156 					      GLTexture            *icon)
1157 {
1158     float xScale, yScale;
1159 
1160     xScale = (float) ICON_SIZE / icon->width ();
1161     yScale = (float) ICON_SIZE / icon->height ();
1162 
1163     if (xScale < yScale)
1164 	yScale = xScale;
1165     else
1166 	xScale = yScale;
1167 
1168     sAttrib.xScale = (float) sScreen->previewWidth * xScale / PREVIEWSIZE;
1169     sAttrib.yScale = (float) sScreen->previewWidth * yScale / PREVIEWSIZE;
1170 
1171     wx = x + sScreen->previewWidth - (sAttrib.xScale * icon->width ());
1172     wy = y + sScreen->previewHeight - (sAttrib.yScale * icon->height ());
1173 }
1174 
1175 void
1176 StaticSwitchWindow::updateIconNontexturedWindow (GLWindowPaintAttrib  &sAttrib,
1177 						 int                  &wx,
1178 						 int                  &wy,
1179 						 float                &width,
1180 						 float                &height,
1181 						 int                  x,
1182 						 int                  y,
1183 						 GLTexture            *icon)
1184 {
1185     sAttrib.xScale = width / icon->width ();
1186     sAttrib.yScale = height / icon->height ();
1187 
1188     if (sAttrib.xScale < sAttrib.yScale)
1189 	sAttrib.yScale = sAttrib.xScale;
1190     else
1191 	sAttrib.xScale = sAttrib.yScale;
1192 
1193     width  = icon->width ()  * sAttrib.xScale;
1194     height = icon->height () * sAttrib.yScale;
1195 
1196     wx = x + (sScreen->previewWidth / 2) - (width / 2);
1197     wy = y + (sScreen->previewHeight / 2) - (height / 2);
1198 }
1199 
1200 void
1201 StaticSwitchWindow::updateIconPos (int   &wx,
1202 				   int   &wy,
1203 				   int   x,
1204 				   int   y,
1205 				   float width,
1206 				   float height)
1207 {
1208     wx = x + (sScreen->previewWidth / 2) - (width / 2);
1209     wy = y + (sScreen->previewHeight / 2) - (height / 2);
1210 }
1211 
1212 void
1213 StaticSwitchWindow::paintThumb (const GLWindowPaintAttrib &attrib,
1214 			  const GLMatrix            &transform,
1215 		          unsigned int              mask,
1216 			  int                       x,
1217 			  int                       y)
1218 {
1219     BaseSwitchWindow::paintThumb (attrib,
1220     				  transform,
1221     				  mask,
1222     				  x,
1223     				  y,
1224 				  sScreen->previewWidth,
1225 				  sScreen->previewHeight,
1226 				  sScreen->previewWidth * 3 / 4,
1227 				  sScreen->previewHeight * 3 / 4);
1228 }
1229 
1230 bool
1231 StaticSwitchWindow::glPaint (const GLWindowPaintAttrib &attrib,
1232 			     const GLMatrix            &transform,
1233 			     const CompRegion          &region,
1234 			     unsigned int              mask)
1235 {
1236     bool       status;
1237 
1238     /* We are painting the switcher popup window:
1239      * Paint the popup window first and then paint
1240      * the relevant thumbnails */
1241     if (window->id () == sScreen->popupWindow)
1242     {
1243 	int            x, y, offX;
1244 	float          px, py, pos;
1245 	int            count = sScreen->windows.size ();
1246 
1247 	const CompWindow::Geometry &g = window->geometry ();
1248 
1249 	if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK ||
1250 	    sScreen->ignoreSwitcher)
1251 	    return false;
1252 
1253 	status = gWindow->glPaint (attrib, transform, region, mask);
1254 
1255 	if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK) && region.isEmpty ())
1256 	    return true;
1257 
1258 	glEnable (GL_SCISSOR_TEST);
1259 	glScissor (g.x (), 0, g.width (), ::screen->height ());
1260 
1261 	unsigned int i = 0;
1262 	foreach (CompWindow *w, sScreen->windows)
1263 	{
1264 	    sScreen->getWindowPosition (i, &x, &y);
1265 	    StaticSwitchWindow::get (w)->paintThumb (
1266 	       gWindow->lastPaintAttrib (), transform,
1267 	       mask, x + g.x (), y + g.y ());
1268 	    i++;
1269 	}
1270 
1271 	pos = fmod (sScreen->pos, count);
1272 	px  = fmod (pos, sScreen->xCount);
1273 	py  = floor (pos / sScreen->xCount);
1274 
1275 	offX = sScreen->getRowXOffset (py);
1276 
1277 	if (pos > count - 1)
1278 	{
1279 	    px = fmod (pos - count, sScreen->xCount);
1280 	    sScreen->paintSelectionRect (transform, g.x (), g.y (), px, 0.0,
1281 	    				 gWindow->lastPaintAttrib ().opacity);
1282 
1283 	    px = fmod (pos, sScreen->xCount);
1284 	    sScreen->paintSelectionRect (transform, g.x () + offX, g.y (),
1285 	    				 px, py,
1286 	    				 gWindow->lastPaintAttrib ().opacity);
1287 	}
1288 	if (px > sScreen->xCount - 1)
1289 	{
1290 	    sScreen->paintSelectionRect (transform, g.x (), g.y (), px, py,
1291 	    				 gWindow->lastPaintAttrib ().opacity);
1292 
1293 	    py = fmod (py + 1, ceil ((double) count / sScreen->xCount));
1294 	    offX = sScreen->getRowXOffset (py);
1295 
1296 	    sScreen->paintSelectionRect (transform, g.x () + offX, g.y (),
1297 	    				 px - sScreen->xCount, py,
1298 	    				 gWindow->lastPaintAttrib ().opacity);
1299 	}
1300 	else
1301 	{
1302 	    sScreen->paintSelectionRect (transform, g.x () + offX, g.y (),
1303 	    				 px, py,
1304 	    				 gWindow->lastPaintAttrib ().opacity);
1305 	}
1306 	glDisable (GL_SCISSOR_TEST);
1307     }
1308     /* Adjust opacity/brightness/saturation of windows that are
1309      * not selected
1310      */
1311     else if (sScreen->switching && !sScreen->popupDelayTimer.active () &&
1312 	     (window != sScreen->selectedWindow))
1313     {
1314 	GLWindowPaintAttrib sAttrib (attrib);
1315 	GLuint              value;
1316 
1317 	value = (GLuint) sScreen->optionGetSaturation ();
1318 	if (value != 100)
1319 	    sAttrib.saturation = sAttrib.saturation * value / 100;
1320 
1321 	value = (GLuint) sScreen->optionGetBrightness ();
1322 	if (value != 100)
1323 	    sAttrib.brightness = sAttrib.brightness * value / 100;
1324 
1325 	if (window->wmType () & (unsigned)~(CompWindowTypeDockMask |
1326 					    CompWindowTypeDesktopMask))
1327 	{
1328 	    value = (GLuint) sScreen->optionGetOpacity ();
1329 	    if (value != 100)
1330 		sAttrib.opacity = sAttrib.opacity * value / 100;
1331 	}
1332 
1333 	status = gWindow->glPaint (sAttrib, transform, region, mask);
1334     }
1335     /* Fallback case for selected window */
1336     else
1337     {
1338 	status = gWindow->glPaint (attrib, transform, region, mask);
1339     }
1340 
1341     return status;
1342 }
1343 
1344 StaticSwitchScreen::StaticSwitchScreen (CompScreen *screen) :
1345     BaseSwitchScreen (screen),
1346     PluginClassHandler<StaticSwitchScreen,CompScreen> (screen),
1347     clientLeader (None),
1348     previewWidth (0),
1349     previewHeight (0),
1350     previewBorder (0),
1351     xCount (0),
1352     switching (false),
1353     mVelocity (0.0),
1354     pos (0),
1355     move (0),
1356     mouseSelect (false)
1357 {
1358 #define SWITCHBIND(a,b,c) boost::bind (switchInitiateCommon, _1, _2, _3, a, b, c)
1359 
1360     optionSetNextButtonInitiate (SWITCHBIND (CurrentViewport, true, true));
1361     optionSetNextButtonTerminate (switchTerminate);
1362     optionSetNextKeyInitiate (SWITCHBIND (CurrentViewport, true, true));
1363     optionSetNextKeyTerminate (switchTerminate);
1364     optionSetPrevButtonInitiate (SWITCHBIND (CurrentViewport, true, false));
1365     optionSetPrevButtonTerminate (switchTerminate);
1366     optionSetPrevKeyInitiate (SWITCHBIND (CurrentViewport, true, false));
1367     optionSetPrevKeyTerminate (switchTerminate);
1368 
1369     optionSetNextAllButtonInitiate (SWITCHBIND (AllViewports, true, true));
1370     optionSetNextAllButtonTerminate (switchTerminate);
1371     optionSetNextAllKeyInitiate (SWITCHBIND (AllViewports, true, true));
1372     optionSetNextAllKeyTerminate (switchTerminate);
1373     optionSetPrevAllButtonInitiate (SWITCHBIND (AllViewports, true, false));
1374     optionSetPrevAllButtonTerminate (switchTerminate);
1375     optionSetPrevAllKeyInitiate (SWITCHBIND (AllViewports, true, false));
1376     optionSetPrevAllKeyTerminate (switchTerminate);
1377 
1378     optionSetNextGroupButtonInitiate (SWITCHBIND (Group, true, true));
1379     optionSetNextGroupButtonTerminate (switchTerminate);
1380     optionSetNextGroupKeyInitiate (SWITCHBIND (Group, true, true));
1381     optionSetNextGroupKeyTerminate (switchTerminate);
1382     optionSetPrevGroupButtonInitiate (SWITCHBIND (Group, true, false));
1383     optionSetPrevGroupButtonTerminate (switchTerminate);
1384     optionSetPrevGroupKeyInitiate (SWITCHBIND (Group, true, false));
1385     optionSetPrevGroupKeyTerminate (switchTerminate);
1386 
1387     optionSetNextNoPopupButtonInitiate (SWITCHBIND (CurrentViewport, false, true));
1388     optionSetNextNoPopupButtonTerminate (switchTerminate);
1389     optionSetNextNoPopupKeyInitiate (SWITCHBIND (CurrentViewport, false, true));
1390     optionSetNextNoPopupKeyTerminate (switchTerminate);
1391     optionSetPrevNoPopupButtonInitiate (SWITCHBIND (CurrentViewport, false, false));
1392     optionSetPrevNoPopupButtonTerminate (switchTerminate);
1393     optionSetPrevNoPopupKeyInitiate (SWITCHBIND (CurrentViewport, false, false));
1394     optionSetPrevNoPopupKeyTerminate (switchTerminate);
1395 
1396     optionSetNextPanelButtonInitiate (SWITCHBIND (Panels, false, true));
1397     optionSetNextPanelButtonTerminate (switchTerminate);
1398     optionSetNextPanelKeyInitiate (SWITCHBIND (Panels, false, true));
1399     optionSetNextPanelKeyTerminate (switchTerminate);
1400     optionSetPrevPanelButtonInitiate (SWITCHBIND (Panels, false, false));
1401     optionSetPrevPanelButtonTerminate (switchTerminate);
1402     optionSetPrevPanelKeyInitiate (SWITCHBIND (Panels, false, false));
1403     optionSetPrevPanelKeyTerminate (switchTerminate);
1404 
1405 #undef SWITCHBIND
1406 
1407     ScreenInterface::setHandler (screen, false);
1408     CompositeScreenInterface::setHandler (cScreen, false);
1409     GLScreenInterface::setHandler (gScreen, false);
CID 12588 - UNINIT_CTOR
Non-static class member "lastActiveWindow" is not initialized in this constructor nor in any functions that it calls.
1410 }
1411 
1412 
1413 StaticSwitchScreen::~StaticSwitchScreen ()
1414 {
1415     if (popupDelayTimer.active ())
1416 	popupDelayTimer.stop ();
1417 
1418     if (popupWindow)
1419 	XDestroyWindow (::screen->dpy (), popupWindow);
1420 }
1421 
1422 StaticSwitchWindow::StaticSwitchWindow (CompWindow *window) :
1423     BaseSwitchWindow (dynamic_cast<BaseSwitchScreen *>
1424     		      (StaticSwitchScreen::get (screen)), window),
1425     PluginClassHandler<StaticSwitchWindow,CompWindow> (window),
1426     sScreen (StaticSwitchScreen::get (screen))
1427 {
1428     GLWindowInterface::setHandler (gWindow, false);
1429     CompositeWindowInterface::setHandler (cWindow, false);
1430 
1431     if (sScreen->popupWindow && sScreen->popupWindow == window->id ())
1432 	gWindow->glPaintSetEnabled (this, true);
1433 }
1434 
1435 bool
1436 StaticSwitchPluginVTable::init ()
1437 {
1438     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1439         !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1440         !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) ||
1441         !CompPlugin::checkPluginABI ("compiztoolbox", COMPIZ_COMPIZTOOLBOX_ABI))
1442 	 return false;
1443 
1444     return true;
1445 }