1 /*
   2  *
   3  * Compiz scale plugin addon plugin
   4  *
   5  * scaleaddon.cpp
   6  *
   7  * Copyright : (C) 2007 by Danny Baumann
   8  * E-mail    : maniac@opencompositing.org
   9  *
  10  * Organic scale mode taken from Beryl's scale.c, written by
  11  * Copyright : (C) 2006 Diogo Ferreira
  12  * E-mail    : diogo@underdev.org
  13  *
  14  * Ported to Compiz 0.9 by:
  15  * Copyright : (C) 2009 by Sam Spilsbury
  16  * E-mail    : smspillaz@gmail.com
  17  *
  18  * This program is free software; you can redistribute it and/or
  19  * modify it under the terms of the GNU General Public License
  20  * as published by the Free Software Foundation; either version 2
  21  * of the License, or (at your option) any later version.
  22  *
  23  * This program is distributed in the hope that it will be useful,
  24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26  * GNU General Public License for more details.
  27  *
  28  *
  29  */
  30 
  31 #include "scaleaddon.h"
  32 #include <iostream>
  33 
  34 COMPIZ_PLUGIN_20090315 (scaleaddon, ScaleAddonPluginVTable);
  35 
  36 bool textAvailable;
  37 
  38 void
  39 ScaleAddonWindow::renderTitle ()
  40 {
  41     CompText::Attrib attrib;
  42     float            scale;
  43     int              titleOpt;
  44 
  45     ADDON_SCREEN (screen);
  46 
  47     if (!textAvailable)
  48 	return;
  49 
  50     text.clear ();
  51 
  52     if (!sWindow->hasSlot ())
  53 	return;
  54 
  55     titleOpt = as->optionGetWindowTitle ();
  56 
  57     if (titleOpt == ScaleaddonOptions::WindowTitleNoDisplay)
  58 	return;
  59 
  60     if (titleOpt == ScaleaddonOptions::WindowTitleHighlightedWindowOnly &&
  61 	as->highlightedWindow != window->id ())
  62     {
  63 	return;
  64     }
  65 
  66     scale = sWindow->getSlot ().scale;
  67     attrib.maxWidth = window->width () * scale;
  68     attrib.maxHeight = window->height () * scale;
  69 
  70     attrib.family = "Sans";
  71     attrib.size = as->optionGetTitleSize ();
  72     attrib.color[0] = as->optionGetFontColorRed ();
  73     attrib.color[1] = as->optionGetFontColorGreen ();
  74     attrib.color[2] = as->optionGetFontColorBlue ();
  75     attrib.color[3] = as->optionGetFontColorAlpha ();
  76 
  77     attrib.flags = CompText::WithBackground | CompText::Ellipsized;
  78     if (as->optionGetTitleBold ())
  79 	attrib.flags |= CompText::StyleBold;
  80 
  81     attrib.bgHMargin = as->optionGetBorderSize ();
  82     attrib.bgVMargin = as->optionGetBorderSize ();
  83     attrib.bgColor[0] = as->optionGetBackColorRed ();
  84     attrib.bgColor[1] = as->optionGetBackColorGreen ();
  85     attrib.bgColor[2] = as->optionGetBackColorBlue ();
  86     attrib.bgColor[3] = as->optionGetBackColorAlpha ();
  87 
  88     text.renderWindowTitle (window->id (),
  89 			    as->sScreen->getType () == ScaleTypeAll,
  90 			    attrib);
  91 }
  92 
  93 void
  94 ScaleAddonWindow::drawTitle (const GLMatrix &transform)
  95 {
  96     float         x, y, width, height;
  97     ScalePosition pos = sWindow->getCurrentPosition ();
  98     CompRect      geom = window->borderRect ();
  99 
 100     width  = text.getWidth ();
 101     height = text.getHeight ();
 102 
 103     x = pos.x () + window->x () + geom.width () * pos.scale / 2 - width / 2;
 104     y = pos.y () + window->y () + geom.height () * pos.scale / 2 - height / 2;
 105 
 106     text.draw (transform, floor (x), floor (y), 1.0f);
 107 }
 108 
 109 void
 110 ScaleAddonWindow::drawHighlight (const GLMatrix &transform)
 111 {
 112     GLint         oldBlendSrc, oldBlendDst;
 113     GLushort colorData[4];
 114     GLfloat  vertexData[12];
 115     GLVertexBuffer *streamingBuffer = GLVertexBuffer::streamingBuffer ();
 116     float         x, y, width, height;
 117     ScalePosition pos = sWindow->getCurrentPosition ();
 118     CompRect      geom = window->borderRect ();
 119 
 120     ADDON_SCREEN (screen);
 121 
 122 #ifdef USE_GLES
 123     GLint oldBlendSrcAlpha, oldBlendDstAlpha;
 124 #endif
 125 
 126     if (rescaled)
 127 	return;
 128 
 129     x      = pos.x () + window->x () - (window->border ().left * pos.scale);
 130     y      = pos.y () + window->y () - (window->border ().top * pos.scale);
 131     width  = geom.width () * pos.scale;
 132     height = geom.height () * pos.scale;
 133 
 134     /* we use a poor replacement for roundf()
 135      * (available in C99 only) here */
 136     x = floor (x + 0.5f);
 137     y = floor (y + 0.5f);
 138 
 139 #ifdef USE_GLES
 140     glGetIntegerv (GL_BLEND_SRC_RGB, &oldBlendSrc);
 141     glGetIntegerv (GL_BLEND_DST_RGB, &oldBlendDst);
 142     glGetIntegerv (GL_BLEND_SRC_ALPHA, &oldBlendSrcAlpha);
 143     glGetIntegerv (GL_BLEND_DST_ALPHA, &oldBlendDstAlpha);
 144 #else
 145     GLboolean wasBlend = glIsEnabled (GL_BLEND);
 146     glGetIntegerv (GL_BLEND_SRC, &oldBlendSrc);
 147     glGetIntegerv (GL_BLEND_DST, &oldBlendDst);
 148 
 149     if (!wasBlend)
 150 	glEnable (GL_BLEND);
 151 
 152 #endif
 153 
 154     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 155 
 156     streamingBuffer->begin (GL_TRIANGLE_STRIP);
 157 
 158     colorData[0] = as->optionGetHighlightColorRed ();
 159     colorData[1] = as->optionGetHighlightColorGreen ();
 160     colorData[2] = as->optionGetHighlightColorBlue ();
 161     colorData[3] = as->optionGetHighlightColorAlpha ();
 162 
 163     streamingBuffer->addColors (1, colorData);
 164 
 165     vertexData[0]  = x;
 166     vertexData[1]  = y;
 167     vertexData[2]  = 0.0f;
 168     vertexData[3]  = x;
 169     vertexData[4]  = y + height;
 170     vertexData[5]  = 0.0f;
 171     vertexData[6]  = x + width;
 172     vertexData[7]  = y;
 173     vertexData[8]  = 0.0f;
 174     vertexData[9]  = x + width;
 175     vertexData[10] = y + height;
 176     vertexData[11] = 0.0f;
 177 
 178     streamingBuffer->addVertices (4, vertexData);
 179 
 180     streamingBuffer->end ();
 181     streamingBuffer->render (transform);
 182 
 183 #ifdef USE_GLES
 184     glBlendFuncSeparate (oldBlendSrc, oldBlendDst,
 185                          oldBlendSrcAlpha, oldBlendDstAlpha);
 186 #else
 187     if (!wasBlend)
 188 	glDisable (GL_BLEND);
 189     glBlendFunc (oldBlendSrc, oldBlendDst);
 190 #endif
 191 }
 192 
 193 void
 194 ScaleAddonScreen::checkWindowHighlight ()
 195 {
 196     if (highlightedWindow != lastHighlightedWindow)
 197     {
 198 	CompWindow *w;
 199 
 200 	w = screen->findWindow (highlightedWindow);
 201 	if (w)
 202 	{
 203 	    ADDON_WINDOW (w);
 204 	    aw->renderTitle ();
 205 	    aw->cWindow->addDamage ();
 206 	}
 207 
 208 	w = screen->findWindow (lastHighlightedWindow);
 209 	if (w)
 210 	{
 211 	    ADDON_WINDOW (w);
 212 	    aw->renderTitle ();
 213 	    aw->cWindow->addDamage (w);
 214 	}
 215 
 216 	lastHighlightedWindow = highlightedWindow;
 217     }
 218 }
 219 
 220 bool
 221 ScaleAddonScreen::closeWindow (CompAction         *action,
 222 			       CompAction::State  state,
 223 			       CompOption::Vector options)
 224 {
 225     CompWindow *w;
 226 
 227     if (!sScreen->hasGrab ())
 228 	return false;
 229 
 230     w = screen->findWindow (highlightedWindow);
 231     if (w)
 232 	w->close (screen->getCurrentTime ());
 233 
 234     return true;
 235 }
 236 
 237 bool
 238 ScaleAddonScreen::pullWindow (CompAction         *action,
 239 			      CompAction::State  state,
 240 			      CompOption::Vector options)
 241 {
 242     CompWindow *w;
 243 
Condition "!this->sScreen->hasGrab()", taking false branch
 244     if (!sScreen->hasGrab ())
 245 	return false;
 246 
 247     w = screen->findWindow (highlightedWindow);
Condition "w", taking true branch
 248     if (w)
 249     {
 250 	int       x, y, xOffset, yOffset;
 251 	CompPoint vp;
 252 
 253 	vp = w->defaultViewport ();
 254 
 255 	xOffset = (screen->vp ().x () - vp.x ()) * screen->width ();
 256 	yOffset = (screen->vp ().y () - vp.y ()) * screen->height ();
 257 
 258 	x = w->x () + xOffset;
 259 	y = w->y () + yOffset;
 260 
Condition "this->optionGetConstrainPullToScreen()", taking false branch
 261 	if (optionGetConstrainPullToScreen ())
 262 	{
 263 	    CompRect workArea, extents;
 264 
 265 	    workArea = screen->outputDevs ()[w->outputDevice ()].workArea ();
 266 	    extents  = w->borderRect ();
 267 
 268 	    extents.setX (extents.x () + xOffset);
 269 	    extents.setY (extents.y () + yOffset);
 270 
 271 	    if (extents.x1 () < workArea.x1 ())
 272 	        x += workArea.x1 () - extents.x1 ();
 273 	    else if (extents.x2 () > workArea.x2 ())
 274 	        x += workArea.x2 () - extents.x2 ();
 275 
 276 	    if (extents.y1 () < workArea.y1 ())
 277 	        y += workArea.y1 () - extents.y1 ();
 278 	    else if (extents.y2 () > workArea.y2 ())
 279 	        y += workArea.y2 () - extents.y2 ();
End of if statement
 280 	}
 281 
Condition "x != w->x()", taking true branch
 282 	if (x != w->x () || y != w->y ())
 283 	{
 284 	    ScalePosition pos, oldPos;
 285 	    ADDON_WINDOW (w);
 286 
 287 	    oldPos = aw->sWindow->getCurrentPosition ();
 288 
 289 	    w->moveToViewportPosition (x, y, true);
 290 
 291 	    /* Select this window when ending scale */
 292 	    aw->sWindow->scaleSelectWindow ();
 293 
 294 	    /* stop scaled window dissapearing */
 295 	    pos.setX (oldPos.x () - xOffset);
 296 	    pos.setY (oldPos.y () - yOffset);
 297 
Condition "this->optionGetExitAfterPull()", taking true branch
 298 	    if (optionGetExitAfterPull ())
 299 	    {
 300 		CompAction         *action;
 301 		CompOption::Vector o;
 302 		CompOption         *opt;
 303 
 304 		o.push_back (CompOption ("root", CompOption::TypeInt));
 305 		o[0].value ().set ((int) screen->root ());
 306 
CID 12472 - NULL_RETURNS
Function "CompOption::findOption(CompOption::Vector &, CompString, unsigned int *)" returns null (checked 81 out of 84 times).
Assigning: "opt" = null return value from "CompOption::findOption(CompOption::Vector &, CompString, unsigned int *)".
 307 		opt = CompOption::findOption (sScreen->getOptions (),
 308 					      "initiate_key", 0);
CID 12472 - NULL_RETURNS
Dereferencing a pointer that might be null "opt" when calling "CompOption::value()".
 309 		action = &opt->value ().action ();
 310 
 311 		if (action->terminate ())
 312 		    action->terminate () (action, 0, o);
 313 	    }
 314 	    else
 315 	    {
 316 		ScaleSlot slot = aw->sWindow->getSlot ();
 317 
 318 		/* provide a simple animation */
 319 		aw->cWindow->addDamage ();
 320 
 321 		pos.setX (oldPos.x () -  slot.width () / 20);
 322 		pos.setY (oldPos.y () - slot.height () / 20);
 323 		pos.scale = oldPos.scale * 1.1f;
 324 
 325 		aw->sWindow->setCurrentPosition (pos);
 326 
 327 		aw->cWindow->addDamage ();
 328 	    }
 329 	}
 330     }
 331 
 332     return true;
 333 }
 334 
 335 bool
 336 ScaleAddonScreen::zoomWindow (CompAction         *action,
 337 			      CompAction::State  state,
 338 			      CompOption::Vector options)
 339 {
 340     CompWindow *w;
 341 
 342     if (!sScreen->hasGrab ())
 343 	return false;
 344 
 345     w = screen->findWindow (highlightedWindow);
 346     if (w)
 347     {
 348 	CompRect output;
 349 	int      head;
 350 
 351 	ADDON_WINDOW (w);
 352 
 353 	if (!aw->sWindow->hasSlot ())
 354 	    return false;
 355 
 356 	head   = screen->outputDeviceForPoint (aw->sWindow->getSlot ().pos ());
 357 	output = screen->outputDevs ()[head];
 358 
 359 	/* damage old rect */
 360 	aw->cWindow->addDamage ();
 361 
 362 	if (!aw->rescaled)
 363 	{
 364 	    ScaleSlot slot = aw->sWindow->getSlot ();
 365 	    int       x1, x2, y1, y2;
 366 	    CompRect  geom = w->borderRect ();
 367 
 368 	    aw->oldAbove = w->next;
 369 	    w->raise ();
 370 
 371 	    /* backup old values */
 372 	    aw->origSlot = slot;
 373 	    aw->rescaled = true;
 374 
 375 	    x1 = output.centerX () - geom.width () / 2 + w->border ().left;
 376 	    y1 = output.centerY () - geom.height () / 2 + w->border ().top;
 377 	    x2 = slot.x () + geom.width ();
 378 	    y2 = slot.y () + geom.height ();
 379 
 380 	    slot.scale = 1.0f;
 381 	    slot.setGeometry (x1, y1, x2 - x1, y2 - y1);
 382 
 383 	    aw->sWindow->setSlot (slot);
 384 	}
 385 	else
 386 	{
 387 	    if (aw->oldAbove)
 388 	        w->restackBelow (aw->oldAbove);
 389 
 390 	    aw->rescaled = false;
 391 	    aw->sWindow->setSlot (aw->origSlot);
 392 	}
 393 
 394 	/* slot size may have changed, so
 395 	 * update window title */
 396 	aw->renderTitle ();
 397 
 398 	aw->cWindow->addDamage ();
 399     }
 400 
 401     return true;
 402 }
 403 
 404 void
 405 ScaleAddonScreen::handleEvent (XEvent *event)
 406 {
 407     screen->handleEvent (event);
 408 
 409     switch (event->type)
 410     {
 411     case PropertyNotify:
 412 	if (event->xproperty.atom == XA_WM_NAME && sScreen->hasGrab ())
 413 	{
 414 	    CompWindow *w;
 415 
 416 	    w = screen->findWindow (event->xproperty.window);
 417 	    if (w)
 418 	    {
 419 		ADDON_WINDOW (w);
 420 		aw->renderTitle ();
 421 		aw->cWindow->addDamage ();
 422 	    }
 423 	}
 424 	break;
 425     case MotionNotify:
 426 	if (sScreen->hasGrab ())
 427 	{
 428 	    highlightedWindow = sScreen->getHoveredWindow ();
 429 	    checkWindowHighlight ();
 430 	}
 431 	break;
 432     default:
 433 	break;
 434     }
 435 }
 436 
 437 void
 438 ScaleAddonWindow::scalePaintDecoration (const GLWindowPaintAttrib &attrib,
 439 				        const GLMatrix		  &transform,
 440 					const CompRegion          &region,
 441 					unsigned int		  mask)
 442 {
 443     ScaleScreen::State state;
 444 
 445     ADDON_SCREEN (screen);
 446 
 447     state = as->sScreen->getState ();
 448     sWindow->scalePaintDecoration (attrib, transform, region, mask);
 449 
 450     if (state == ScaleScreen::Wait || state == ScaleScreen::Out)
 451     {
 452 	if (as->optionGetWindowHighlight ())
 453 	{
 454 	    if (window->id () == as->highlightedWindow)
 455 		drawHighlight (transform);
 456 	}
 457 
 458 	if (textAvailable)
 459 	    drawTitle (transform);
 460     }
 461 }
 462 
 463 void
 464 ScaleAddonWindow::scaleSelectWindow ()
 465 {
 466     ADDON_SCREEN (screen);
 467 
 468     as->highlightedWindow = window->id ();
 469     as->checkWindowHighlight ();
 470 
 471     sWindow->scaleSelectWindow ();
 472 }
 473 
 474 void
 475 ScaleAddonScreen::donePaint ()
 476 {
 477     ScaleScreen::State state = sScreen->getState ();
 478 
 479     if (state != ScaleScreen::Idle && lastState == ScaleScreen::Idle)
 480     {
 481 	foreach (CompWindow *w, screen->windows ())
 482 	    ScaleAddonWindow::get (w)->renderTitle ();
 483     }
 484     else if (state == ScaleScreen::Idle && lastState != ScaleScreen::Idle)
 485     {
 486 	foreach (CompWindow *w, screen->windows ())
 487 	    ScaleAddonWindow::get (w)->text.clear ();
 488     }
 489 
 490     if (state == ScaleScreen::Out && lastState != ScaleScreen::Out)
 491     {
 492 	lastHighlightedWindow = None;
 493 	checkWindowHighlight ();
 494     }
 495 
 496     lastState = state;
 497 
 498     cScreen->donePaint ();
 499 }
 500 
 501 void
 502 ScaleAddonScreen::handleCompizEvent (const char         *pluginName,
 503 				     const char         *eventName,
 504 				     CompOption::Vector &options)
 505 {
 506     screen->handleCompizEvent (pluginName, eventName, options);
 507 
 508     if ((strcmp (pluginName, "scale") == 0) &&
 509 	(strcmp (eventName, "activate") == 0))
 510     {
 511 	bool activated =
 512 	    CompOption::getBoolOptionNamed (options, "active", false);
 513 
 514 	if (activated)
 515 	{
 516 	    screen->addAction (&optionGetCloseKey ());
 517 	    screen->addAction (&optionGetZoomKey ());
 518 	    screen->addAction (&optionGetPullKey ());
 519 	    screen->addAction (&optionGetCloseButton ());
 520 	    screen->addAction (&optionGetZoomButton ());
 521 	    screen->addAction (&optionGetPullButton ());
 522 
 523 	    /* TODO: or better
 524 	       ad->highlightedWindow     = sd->selectedWindow;
 525 	       here? do we want to show up the highlight without
 526 	       mouse move initially? */
 527 
 528 	    highlightedWindow     = None;
 529 	    lastHighlightedWindow = None;
 530 	    checkWindowHighlight ();
 531 	}
 532 	else
 533 	{
 534 	    foreach (CompWindow *w, screen->windows ())
 535 	    {
 536 		ADDON_WINDOW (w);
 537 		aw->rescaled = false;
 538 	    }
 539 
 540 	    screen->removeAction (&optionGetCloseKey ());
 541 	    screen->removeAction (&optionGetZoomKey ());
 542 	    screen->removeAction (&optionGetPullKey ());
 543 	    screen->removeAction (&optionGetCloseButton ());
 544 	    screen->removeAction (&optionGetZoomButton ());
 545 	    screen->removeAction (&optionGetPullButton ());
 546 	}
 547     }
 548 }
 549 
 550 /**
 551  * experimental organic layout method
 552  * inspired by smallwindows (smallwindows.sf.net) by Jens Egeblad
 553  * FIXME: broken.
 554  * */
 555 #if 0
 556 static const double ORGANIC_STEP = 0.05f;
 557 static int
 558 organicCompareWindows (const void *elem1,
 559 		       const void *elem2)
 560 {
 561     CompWindow *w1 = *((CompWindow **) elem1);
 562     CompWindow *w2 = *((CompWindow **) elem2);
 563 
 564     return (WIN_X (w1) + WIN_Y (w1)) - (WIN_X (w2) + WIN_Y (w2));
 565 }
 566 
 567 static double
 568 layoutOrganicCalculateOverlap (CompScreen *s,
 569 			       int        win,
 570 			       int        x,
 571 			       int        y)
 572 {
 573     int    x1, y1, x2, y2;
 574     int    overlapX, overlapY;
 575     int    xMin, xMax, yMin, yMax;
 576     double result = -0.01;
 577 
 578     SCALE_SCREEN ();
 579     ADDON_SCREEN ();
 580 
 581     x1 = x;
 582     y1 = y;
 583     x2 = x1 + WIN_W (ss->windows[win]) * as->scale;
 584     y2 = y1 + WIN_H (ss->windows[win]) * as->scale;
 585 
 586     for (int i = 0; i < ss->nWindows; i++)
 587     {
 588 	if (i == win)
 589 	    continue;
 590 
 591 	overlapX = overlapY = 0;
 592 	xMax = MAX (ss->slots[i].x1, x1);
 593 	xMin = MIN (ss->slots[i].x1 + WIN_W (ss->windows[i]) * as->scale, x2);
 594 	if (xMax <= xMin)
 595 	    overlapX = xMin - xMax;
 596 
 597 	yMax = MAX (ss->slots[i].y1, y1);
 598 	yMin = MIN (ss->slots[i].y1 + WIN_H (ss->windows[i]) * as->scale, y2);
 599 
 600 	if (yMax <= yMin)
 601 	    overlapY = yMin - yMax;
 602 
 603 	result += (double)overlapX * overlapY;
 604     }
 605 
 606     return result;
 607 }
 608 
 609 static double
 610 layoutOrganicFindBestHorizontalPosition (CompScreen *s,
 611 					 int        win,
 612 					 int        *bestX,
 613 					 int        areaWidth)
 614 {
 615     int    i, y1, y2, w;
 616     double bestOverlap = 1e31, overlap;
 617 
 618     SCALE_SCREEN ();
 619     ADDON_SCREEN ();
 620 
 621     y1 = ss->slots[win].y1;
 622     y2 = ss->slots[win].y1 + WIN_H (ss->windows[win]) * as->scale;
 623 
 624     w = WIN_W (ss->windows[win]) * as->scale;
 625     *bestX = ss->slots[win].x1;
 626 
 627     for (i = 0; i < ss->nWindows; i++)
 628     {
 629 	CompWindow *lw = ss->windows[i];
 630 	if (i == win)
 631 	    continue;
 632 
 633 	if (ss->slots[i].y1 < y2 &&
 634 	    ss->slots[i].y1 + WIN_H (lw) * as->scale > y1)
 635 	{
 636 	    if (ss->slots[i].x1 - w >= 0)
 637 	    {
 638 		double overlap;
 639 		
 640 		overlap = layoutOrganicCalculateOverlap (s, win,
 641 		 					 ss->slots[i].x1 - w,
 642 							 y1);
 643 
 644 		if (overlap < bestOverlap)
 645 		{
 646 		    *bestX = ss->slots[i].x1 - w;
 647 		    bestOverlap = overlap;
 648 		}
 649 	    }
 650 	    if (WIN_W (lw) * as->scale + ss->slots[i].x1 + w < areaWidth)
 651 	    {
 652 		double overlap;
 653 		
 654 		overlap = layoutOrganicCalculateOverlap (s, win,
 655 		 					 ss->slots[i].x1 +
 656 		 					 WIN_W (lw) * as->scale,
 657 		 					 y1);
 658 
 659 		if (overlap < bestOverlap)
 660 		{
 661 		    *bestX = ss->slots[i].x1 + WIN_W (lw) * as->scale;
 662 		    bestOverlap = overlap;
 663 		}
 664 	    }
 665 	}
 666     }
 667 
 668     overlap = layoutOrganicCalculateOverlap (s, win, 0, y1);
 669     if (overlap < bestOverlap)
 670     {
 671 	*bestX = 0;
 672 	bestOverlap = overlap;
 673     }
 674 
 675     overlap = layoutOrganicCalculateOverlap (s, win, areaWidth - w, y1);
 676     if (overlap < bestOverlap)
 677     {
 678 	*bestX = areaWidth - w;
 679 	bestOverlap = overlap;
 680     }
 681 
 682     return bestOverlap;
 683 }
 684 
 685 static double
 686 layoutOrganicFindBestVerticalPosition (CompScreen *s,
 687 				       int        win,
 688 				       int        *bestY,
 689 				       int        areaHeight)
 690 {
 691     int    i, x1, x2, h;
 692     double bestOverlap = 1e31, overlap;
 693 
 694     SCALE_SCREEN ();
 695     ADDON_SCREEN ();
 696 
 697     x1 = ss->slots[win].x1;
 698     x2 = ss->slots[win].x1 + WIN_W (ss->windows[win]) * as->scale;
 699     h = WIN_H (ss->windows[win]) * as->scale;
 700     *bestY = ss->slots[win].y1;
 701 
 702     for (i = 0; i < ss->nWindows; i++)
 703     {
 704 	CompWindow *w = ss->windows[i];
 705 
 706 	if (i == win)
 707 	    continue;
 708 
 709 	if (ss->slots[i].x1 < x2 &&
 710 	    ss->slots[i].x1 + WIN_W (w) * as->scale > x1)
 711 	{
 712 	    if (ss->slots[i].y1 - h >= 0 && ss->slots[i].y1 < areaHeight)
 713 	    {
 714 		double overlap;
 715 		overlap = layoutOrganicCalculateOverlap (s, win, x1,
 716 	 						 ss->slots[i].y1 - h);
 717 		if (overlap < bestOverlap)
 718 		{
 719 		    *bestY = ss->slots[i].y1 - h;
 720 		    bestOverlap = overlap;
 721 		}
 722 	    }
 723 	    if (WIN_H (w) * as->scale + ss->slots[i].y1 > 0 &&
 724 		WIN_H (w) * as->scale + h + ss->slots[i].y1 < areaHeight)
 725 	    {
 726 		double overlap;
 727 		
 728 		overlap = layoutOrganicCalculateOverlap (s, win, x1,
 729 		 					 WIN_H (w) * as->scale +
 730 							 ss->slots[i].y1);
 731 
 732 		if (overlap < bestOverlap)
 733 		{
 734 		    *bestY = ss->slots[i].y1 + WIN_H(w) * as->scale;
 735 		    bestOverlap = overlap;
 736 		}
 737 	    }
 738 	}
 739     }
 740 
 741     overlap = layoutOrganicCalculateOverlap (s, win, x1, 0);
 742     if (overlap < bestOverlap)
 743     {
 744 	*bestY = 0;
 745 	bestOverlap = overlap;
 746     }
 747 
 748     overlap = layoutOrganicCalculateOverlap (s, win, x1, areaHeight - h);
 749     if (overlap < bestOverlap)
 750     {
 751 	*bestY = areaHeight - h;
 752 	bestOverlap = overlap;
 753     }
 754 
 755     return bestOverlap;
 756 }
 757 
 758 static bool
 759 layoutOrganicLocalSearch (CompScreen *s,
 760 			  int        areaWidth,
 761 			  int        areaHeight)
 762 {
 763     bool   improvement;
 764     int    i;
 765     double totalOverlap;
 766 
 767     SCALE_SCREEN ();
 768 
 769     do
 770     {
 771 	improvement = false;
 772 	for (i = 0; i < ss->nWindows; i++)
 773 	{
 774 	    bool improved;
 775 
 776 	    do
 777 	    {
 778 		int    newX, newY;
 779 		double oldOverlap, overlapH, overlapV;
 780 
 781 		improved = false;
 782 		oldOverlap = layoutOrganicCalculateOverlap (s, i,
 783  							    ss->slots[i].x1,
 784 							    ss->slots[i].y1);
 785 
 786 		overlapH = layoutOrganicFindBestHorizontalPosition (s, i,
 787 								    &newX,
 788 								    areaWidth);
 789 		overlapV = layoutOrganicFindBestVerticalPosition (s, i,
 790 								  &newY,
 791 								  areaHeight);
 792 
 793 		if (overlapH < oldOverlap - 0.1 ||
 794 		    overlapV < oldOverlap - 0.1)
 795 		{
 796 		    improved = true;
 797 		    improvement = true;
 798 		    if (overlapV > overlapH)
 799 			ss->slots[i].x1 = newX;
 800 		    else
 801 			ss->slots[i].y1 = newY;
 802 		}
 803     	    }
 804 	    while (improved);
 805 	}
 806     }
 807     while (improvement);
 808 
 809     totalOverlap = 0.0;
 810     for (i = 0; i < ss->nWindows; i++)
 811     {
 812 	totalOverlap += layoutOrganicCalculateOverlap (s, i,
 813 						       ss->slots[i].x1,
 814 						       ss->slots[i].y1);
 815     }
 816 
 817     return (totalOverlap > 0.1);
 818 }
 819 
 820 static void
 821 layoutOrganicRemoveOverlap (CompScreen *s,
 822 			    int        areaWidth,
 823 			    int        areaHeight)
 824 {
 825     int        i, spacing;
 826     CompWindow *w;
 827 
 828     SCALE_SCREEN ();
 829     ADDON_SCREEN ();
 830 
 831     spacing = ss->opt[SCALE_SCREEN_OPTION_SPACING].value.i;
 832 
 833     while (layoutOrganicLocalSearch (s, areaWidth, areaHeight))
 834     {
 835 	for (i = 0; i < ss->nWindows; i++)
 836 	{
 837 	    int centerX, centerY;
 838 	    int newX, newY, newWidth, newHeight;
 839 
 840 	    w = ss->windows[i];
 841 
 842 	    centerX = ss->slots[i].x1 + WIN_W (w) / 2;
 843 	    centerY = ss->slots[i].y1 + WIN_H (w) / 2;
 844 
 845 	    newWidth = (int)((1.0 - ORGANIC_STEP) *
 846 			     (double)WIN_W (w)) - spacing / 2;
 847 	    newHeight = (int)((1.0 - ORGANIC_STEP) *
 848 			      (double)WIN_H (w)) - spacing / 2;
 849 	    newX = centerX - (newWidth / 2);
 850 	    newY = centerY - (newHeight / 2);
 851 
 852 	    ss->slots[i].x1 = newX;
 853 	    ss->slots[i].y1 = newY;
 854 	    ss->slots[i].x2 = newX + WIN_W (w);
 855 	    ss->slots[i].y2 = newY + WIN_H (w);
 856 	}
 857 	as->scale -= ORGANIC_STEP;
 858     }
 859 }
 860 
 861 static bool
 862 layoutOrganicThumbs (CompScreen *s)
 863 {
 864     CompWindow *w;
 865     int        i, moMode;
 866     XRectangle workArea;
 867 
 868     SCALE_SCREEN ();
 869     ADDON_SCREEN ();
 870 
 871     moMode = ss->opt[SCALE_SCREEN_OPTION_MULTIOUTPUT_MODE].value.i;
 872 
 873     switch (moMode) {
 874     case SCALE_MOMODE_ALL:
 875 	workArea = s->workArea;
 876 	break;
 877     case SCALE_MOMODE_CURRENT:
 878     default:
 879 	workArea = s->outputDev[s->currentOutputDev].workArea;
 880 	break;
 881     }
 882 
 883     as->scale = 1.0f;
 884 
 885     qsort (ss->windows, ss->nWindows, sizeof(CompWindow *),
 886 	   organicCompareWindows);
 887 
 888     for (i = 0; i < ss->nWindows; i++)
 889     {
 890 	w = ss->windows[i];
 891 	SCALE_WINDOW (w);
 892 
 893 	sWindow->slot = &ss->slots[i];
 894 	ss->slots[i].x1 = WIN_X (w) - workArea.x;
 895 	ss->slots[i].y1 = WIN_Y (w) - workArea.y;
 896 	ss->slots[i].x2 = WIN_X (w) + WIN_W (w) - workArea.x;
 897 	ss->slots[i].y2 = WIN_Y (w) + WIN_H (w) - workArea.y;
 898 
 899 	if (ss->slots[i].x1 < 0)
 900 	{
 901 	    ss->slots[i].x2 += abs (ss->slots[i].x1);
 902 	    ss->slots[i].x1 = 0;
 903 	}
 904 	if (ss->slots[i].x2 > workArea.width - workArea.x)
 905 	{
 906 	    ss->slots[i].x1 -= abs (ss->slots[i].x2 - workArea.width);
 907 	    ss->slots[i].x2 = workArea.width - workArea.x;
 908 	}
 909 
 910 	if (ss->slots[i].y1 < 0)
 911 	{
 912 	    ss->slots[i].y2 += abs (ss->slots[i].y1);
 913 	    ss->slots[i].y1 = 0;
 914 	}
 915 	if (ss->slots[i].y2 > workArea.height - workArea.y)
 916 	{
 917 	    ss->slots[i].y1 -= abs (ss->slots[i].y2 -
 918 				    workArea.height - workArea.y);
 919 	    ss->slots[i].y2 = workArea.height - workArea.y;
 920 	}
 921     }
 922 
 923     ss->nSlots = ss->nWindows;
 924 
 925     layoutOrganicRemoveOverlap (s, workArea.width - workArea.x,
 926 				workArea.height - workArea.y);
 927     for (i = 0; i < ss->nWindows; i++)
 928     {
 929 	w = ss->windows[i];
 930 	SCALE_WINDOW (w);
 931 
 932 	if (ss->type == ScaleTypeGroup)
 933 	    raiseWindow (ss->windows[i]);
 934 
 935 	ss->slots[i].x1 += w->input.left + workArea.x;
 936 	ss->slots[i].x2 += w->input.left + workArea.x;
 937 	ss->slots[i].y1 += w->input.top + workArea.y;
 938 	ss->slots[i].y2 += w->input.top + workArea.y;
 939 	sWindow->adjust = true;
 940     }
 941 
 942     return true;
 943 }
 944 
 945 #endif
 946 
 947 /*
 948  * Inspired by KWin - the KDE Window Manager
 949  * presentwindows.cpp
 950  * Copyright (C) 2007 Rivo Laks <rivolaks@hot.ee>
 951  * Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
 952  * 
 953  */
 954 
 955 bool
 956 ScaleAddonScreen::isOverlappingAny (ScaleWindow *w,
 957 				    std::map <ScaleWindow *, CompRegion> targets,
 958 				    const CompRegion &border)
 959 {
 960     if (border.intersects (targets[w]))
 961 	return true;
 962     // Is there a better way to do this?
 963     std::map <ScaleWindow *, CompRegion>::const_iterator i;
 964     for (i = targets.begin (); i != targets.end (); ++i)
 965     {
 966 	if (w == (*i).first)
 967 	    continue;
 968 	if (targets[w].intersects ((*i).second))
 969 	    return true;
 970     }
 971     return false;
 972 }
 973 
 974 bool
 975 ScaleAddonScreen::layoutNaturalThumbs ()
 976 {
 977     ScaleScreen::WindowList windows = ScaleScreen::get (screen)->getWindows ();
 978     bool overlapping;
 979     CompRect area = screen->workArea ();
 980     CompRect bounds = area;
 981     std::map <ScaleWindow *, CompRegion> targets;
 982     std::map <ScaleWindow *, int> directions;
 983     int				  direction = 0;
 984     int				  iterCount = 0;
 985 
 986     if (windows.size () == 1)
 987     {
 988 	// Just move the window to its original location to save time
 989 	if (screen->fullscreenOutput ().workArea ().contains (windows.front ()->window->geometry ()))
 990 	{
 991 	    ScaleSlot slot ((CompRect &) windows.front ()->window->geometry ());
 992 	    windows.front ()->setSlot (slot);
 993 	    return true;
 994 	}
 995     }
 996 
 997     foreach (ScaleWindow *w, windows)
 998     {
 999         bounds = CompRegion (bounds).united (w->window->outputRect ()).boundingRect ();
1000         targets[w] = CompRegion (w->window->outputRect ());
1001 	// Reuse the unused "slot" as a preferred direction attribute. This is used when the window
1002 	// is on the edge of the screen to try to use as much screen real estate as possible.
1003 	directions[w] = direction;
1004 	direction++;
1005 	if (direction == 4)
1006 	    direction = 0;
1007     }
1008         
1009     do
1010     {
1011 	overlapping = false;
1012 	foreach (ScaleWindow *w, windows)
1013 	{
1014 	    foreach (ScaleWindow *e, windows)
1015 	    {
1016 		if (e->window->id () != w->window->id () && targets[w].intersects (targets[e]))
1017 		{
1018 		    int moveX = targets[w].boundingRect ().centerX () - targets[e].boundingRect ().centerX ();
1019 		    int moveY = targets[w].boundingRect ().centerY () - targets[e].boundingRect ().centerY ();
1020 		    //int xSection, ySection;
1021 		    // Overlap detected, determine direction to push
1022 		    
1023 		    overlapping = true;
1024 
1025 		    moveX /= optionGetNaturalPrecision ();
1026 		    moveY /= optionGetNaturalPrecision ();
1027 		    
1028 		    /* Force movement */
1029 		    if (moveX == 0)
1030 			moveX = optionGetNaturalPrecision ();
1031 		    if (moveY == 0)
1032 			moveY = optionGetNaturalPrecision ();
1033 		    
1034 		    targets[w] = targets[w].translated (moveX, moveY);
1035 		    targets[e] = targets[e].translated (-moveX, -moveY);
1036 		    
1037 		    /* Try to keep the bounding rect the same aspect as the screen so that more
1038 		     * screen real estate is utilised. We do this by splitting the screen into nine
1039 		     * equal sections, if the window center is in any of the corner sections pull the
1040 		     * window towards the outer corner. If it is in any of the other edge sections
1041 		     * alternate between each corner on that edge. We don't want to determine it
1042 		     * randomly as it will not produce consistant locations when using the filter.
1043 		     * Only move one window so we don't cause large amounts of unnecessary zooming
1044 		     * in some situations. We need to do this even when expanding later just in case
1045 		     * all windows are the same size.
1046 		     * (We are using an old bounding rect for this, hopefully it doesn't matter)
1047 		     * FIXME: Disabled for now
1048 		     *
1049 		    xSection = (targets[w].boundingRect ().x () - bounds.x ()) / (bounds.width () / 3);
1050 		    ySection = (targets[w].boundingRect ().y () - bounds.y ()) / (bounds.height () / 3);
1051 		    moveX = 0;
1052 		    moveY = 0;
1053 		    if (xSection != 1 || ySection != 1) // Remove this if you want the center to pull as well
1054 		    {
1055 			if (xSection == 1)
1056 			    xSection = (directions[w] / 2 ? 2 : 0);
1057 			if (ySection == 1)
1058 			    ySection = (directions[w] % 2 ? 2 : 0);
1059 		    }
1060 		    
1061                     if (xSection == 0 && ySection == 0)
1062 		    {
1063 			moveX = bounds.left () - targets[w].boundingRect ().centerX ();
1064 			moveY = bounds.top () - targets[w].boundingRect ().centerY ();
1065 		    }
1066                     if (xSection == 2 && ySection == 0)
1067 		    {
1068 			moveX = bounds.right () - targets[w].boundingRect ().centerX ();
1069 			moveY = bounds.top () - targets[w].boundingRect ().centerY ();
1070 		    }
1071                     if (xSection == 2 && ySection == 2)
1072 		    {
1073 			moveX = bounds.right () - targets[w].boundingRect ().centerX ();
1074 			moveY = bounds.bottom () - targets[w].boundingRect ().centerY ();
1075 		    }
1076                     if (xSection == 0 && ySection == 2)
1077 		    {
1078 			moveX = bounds.left () - targets[w].boundingRect ().centerX ();
1079 			moveY = bounds.right () - targets[w].boundingRect ().centerY ();
1080 		    }
1081                     if (moveX != 0 || moveY != 0)
1082                         targets[w].translate (moveX, moveY);
1083 		    */
1084 		}
1085 		
1086 		// Update bounding rect
1087 		bounds = CompRegion (bounds).united (targets[w]).boundingRect ();
1088 		bounds = CompRegion (bounds).united (targets[e]).boundingRect ();
1089 	    }
1090 	}
1091     }
1092     while (overlapping);
1093 
1094     // Work out scaling by getting the most top-left and most bottom-right window coords.
1095     // The 20's and 10's are so that the windows don't touch the edge of the screen.
1096     double scale;
1097     if (bounds == area)
1098         scale = 1.0; // Don't add borders to the screen
1099     else if (area.width () / double (bounds.width ()) < area.height () / double (bounds.height ()))
1100         scale = (area.width () - 20) / double (bounds.width ());
1101     else
1102         scale = (area.height () - 20) / double (bounds.height ());
1103     // Make bounding rect fill the screen size for later steps
1104     bounds = CompRect (
1105         bounds.x () - (area.width () - 20 - bounds.width () * scale ) / 2 - 10 / scale,
1106         bounds.y () - (area.height () - 20 - bounds.height () * scale ) / 2 - 10 / scale,
1107         area.width () / scale,
1108         area.height () / scale
1109         );
1110     
1111     // Move all windows back onto the screen and set their scale
1112     foreach (ScaleWindow *w, windows)
1113     {
1114         targets[w] = CompRect (
1115             (targets[w].boundingRect ().x () - bounds.x () ) * scale + area.x (),
1116 	    (targets[w].boundingRect ().y () - bounds.y ()) * scale + area.y (),
1117 	    targets[w].boundingRect ().width () * scale,
1118 	    targets[w].boundingRect ().height () * scale
1119             );
1120 	ScaleSlot slt (targets[w].boundingRect ());
1121 	slt.scale = scale;
1122 	slt.filled = true;
1123 	
1124 	w->setSlot (slt);
1125     }
1126 
1127     // Don't expand onto or over the border
1128     CompRegion borderRegion = CompRegion (area);
1129     CompRegion areaRegion = CompRegion (area);
1130     borderRegion.translate (-200, -200);
1131     borderRegion.shrink (-200, -200); // actually expands the region
1132     areaRegion.translate (10 / scale, 10 / scale);
1133     areaRegion.shrink (10 / scale, 10 / scale);
1134     
1135     borderRegion ^= areaRegion;
1136 
1137     bool moved = false;
1138     do
1139     {
1140 	moved = false;
1141 	foreach (ScaleWindow *w, windows)
1142 	{
1143 	    CompRegion oldRegion;
1144 	    
1145 	    // This may cause some slight distortion if the windows are enlarged a large amount
1146 	    int widthDiff = optionGetNaturalPrecision ();
1147 	    int heightDiff = ((w->window->height () / w->window->width ()) * 
1148 	    (targets[w].boundingRect ().width() + widthDiff)) - targets[w].boundingRect ().height ();
1149 	    int xDiff = widthDiff / 2;  // Also move a bit in the direction of the enlarge, allows the
1150 	    int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side.
1151 	    
1152 	    // Attempt enlarging to the top-right
1153 	    oldRegion = targets[w];
1154 	    targets[w] = CompRegion (
1155 				     targets[w].boundingRect ().x () + xDiff,
1156 				     targets[w].boundingRect ().y () - yDiff - heightDiff,
1157 				     targets[w].boundingRect ().width () + widthDiff,
1158 				     targets[w].boundingRect ().height () + heightDiff
1159 					);
1160 	    if (isOverlappingAny (w, targets, borderRegion))
1161 		targets[w] = oldRegion;
1162 	    else
1163 		moved = true;
1164 	    
1165 	    // Attempt enlarging to the bottom-right
1166 	    oldRegion = targets[w];
1167 	    targets[w] = CompRegion(
1168 				    targets[w].boundingRect ().x () + xDiff,
1169 				    targets[w].boundingRect ().y () + yDiff,
1170 				    targets[w].boundingRect ().width () + widthDiff,
1171 				    targets[w].boundingRect ().height () + heightDiff
1172 				    );
1173 	    if (isOverlappingAny (w, targets, borderRegion))
1174 		targets[w] = oldRegion;
1175 	    else
1176 		moved = true;
1177 		
1178 	    // Attempt enlarging to the bottom-left
1179 	    oldRegion = targets[w];
1180 	    targets[w] = CompRegion (
1181 				    targets[w].boundingRect ().x() - xDiff - widthDiff,
1182 				    targets[w].boundingRect ().y() + yDiff,
1183 				    targets[w].boundingRect ().width() + widthDiff,
1184 				    targets[w].boundingRect ().height() + heightDiff
1185 				    );
1186 	    if (isOverlappingAny (w, targets, borderRegion))
1187 		targets[w] = oldRegion;
1188 	    else
1189 		moved = true;
1190 		    
1191 	    // Attempt enlarging to the top-left
1192 	    oldRegion = targets[w];
1193 	    targets[w] = CompRegion (
1194 				    targets[w].boundingRect ().x() - xDiff - widthDiff,
1195 				    targets[w].boundingRect ().y() - yDiff - heightDiff,
1196 				    targets[w].boundingRect ().width() + widthDiff,
1197 				    targets[w].boundingRect ().height() + heightDiff
1198 				    );
1199 	    if (isOverlappingAny (w, targets, borderRegion))
1200 		targets[w] = oldRegion;
1201 	    else
1202 		moved = true;
1203 	}
1204 	
1205 	iterCount++;
1206     }
1207     while (moved && iterCount < 100);
1208 
1209     // The expanding code above can actually enlarge windows over 1.0/2.0 scale, we don't like this
1210     // We can't add this to the loop above as it would cause a never-ending loop so we have to make
1211     // do with the less-than-optimal space usage with using this method.
1212     foreach (ScaleWindow *w, windows)
1213     {
1214 	double scale = targets[w].boundingRect ().width() / double( w->window->width());
1215 	if (scale > 2.0 || (scale > 1.0 && (w->window->width() > 300 || w->window->height() > 300)))
1216 	{
1217 	    scale = (w->window->width () > 300 || w->window->height () > 300) ? 1.0 : 2.0;
1218 	    targets[w] = CompRegion (
1219 				    targets[w].boundingRect ().center().x() - int (w->window->width() * scale) / 2,
1220 				    targets[w].boundingRect ().center().y() - int (w->window->height () * scale) / 2,
1221 				    w->window->width() * scale,
1222 				    w->window->height() * scale
1223 				    );
1224 	}
1225     }
1226 
1227     return true;
1228 
1229 }
1230 
1231 bool
1232 ScaleAddonScreen::layoutSlotsAndAssignWindows ()
1233 {
1234     bool status;
1235 
1236     switch (optionGetLayoutMode ())
1237     {
1238     case LayoutModeNatural:
1239 	status = layoutNaturalThumbs ();
1240 	break;
1241     case LayoutModeNormal:
1242     default:
1243 	status = sScreen->layoutSlotsAndAssignWindows ();
1244 	break;
1245     }
1246 
1247     return status;
1248 }
1249 
1250 void
1251 ScaleAddonScreen::optionChanged (CompOption                 *opt,
1252 				 ScaleaddonOptions::Options num)
1253 {
1254     switch (num)
1255     {
1256 	case ScaleaddonOptions::WindowTitle:
1257 	case ScaleaddonOptions::TitleBold:
1258 	case ScaleaddonOptions::TitleSize:
1259 	case ScaleaddonOptions::BorderSize:
1260 	case ScaleaddonOptions::FontColor:
1261 	case ScaleaddonOptions::BackColor:
1262 	    if (textAvailable)
1263 	    {
1264 		foreach (CompWindow *w, screen->windows ())
1265 		{
1266 		    ADDON_WINDOW (w);
1267 		    aw->renderTitle ();
1268 		}
1269 	    }
1270 	    break;
1271 	default:
1272 	    break;
1273     }
1274 }
1275 
1276 ScaleAddonScreen::ScaleAddonScreen (CompScreen *) :
1277     PluginClassHandler <ScaleAddonScreen, CompScreen> (screen),
1278     cScreen (CompositeScreen::get (screen)),
1279     sScreen (ScaleScreen::get (screen)),
1280     highlightedWindow (0),
1281     lastHighlightedWindow (0),
1282     lastState (ScaleScreen::Idle),
1283     scale (1.0f)
1284 {
1285     CompAction::CallBack cb;
1286     ChangeNotify         notify;
1287 
1288     ScreenInterface::setHandler (screen, true);
1289     CompositeScreenInterface::setHandler (cScreen, true);
1290     ScaleScreenInterface::setHandler (sScreen, true);
1291 
1292     cb = boost::bind (&ScaleAddonScreen::closeWindow, this, _1, _2, _3);
1293     optionSetCloseKeyInitiate (cb);
1294     optionSetCloseButtonInitiate (cb);
1295 
1296     cb = boost::bind (&ScaleAddonScreen::zoomWindow, this, _1, _2, _3);
1297     optionSetZoomKeyInitiate (cb);
1298     optionSetZoomButtonInitiate (cb);
1299 
1300     cb = boost::bind (&ScaleAddonScreen::pullWindow, this, _1, _2, _3);
1301     optionSetPullKeyInitiate (cb);
1302     optionSetPullButtonInitiate (cb);
1303 
1304     notify = boost::bind (&ScaleAddonScreen::optionChanged, this, _1, _2);
1305     optionSetWindowTitleNotify (notify);
1306     optionSetTitleBoldNotify (notify);
1307     optionSetTitleSizeNotify (notify);
1308     optionSetBorderSizeNotify (notify);
1309     optionSetFontColorNotify (notify);
1310     optionSetBackColorNotify (notify);
1311 }
1312 
1313 ScaleAddonWindow::ScaleAddonWindow (CompWindow *window) :
1314     PluginClassHandler <ScaleAddonWindow, CompWindow> (window),
1315     window (window),
1316     sWindow (ScaleWindow::get (window)),
1317     cWindow (CompositeWindow::get (window)),
1318     rescaled (false),
1319     oldAbove (NULL)
1320 {
1321     ScaleWindowInterface::setHandler (sWindow);
1322 }
1323 
1324 bool
1325 ScaleAddonPluginVTable::init ()
1326 {
1327     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1328 	!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1329 	!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI) ||
1330 	!CompPlugin::checkPluginABI ("scale", COMPIZ_SCALE_ABI))
1331 	return false;
1332 
1333     if (!CompPlugin::checkPluginABI ("text", COMPIZ_TEXT_ABI))
1334     {
1335 	compLogMessage ("scaleaddon", CompLogLevelInfo,
1336 			"Text Plugin not loaded, no text will be drawn.");
1337 	textAvailable = false;
1338     }
1339     else
1340 	textAvailable = true;
1341 
1342     return true;
1343 }