{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, PatternGuards, DeriveDataTypeable, ScopedTypeVariables #-}------------------------------------------------------------------------------- |-- Module : XMonad.Layout.LayoutBuilderP-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com>, 2011 Ilya Portnov <portnov84@rambler.ru>-- License : BSD3-style (see LICENSE)---- Maintainer : Ilya Portnov <portnov84@rambler.ru>-- Stability : unstable-- Portability : unportable---- A layout combinator that sends windows matching given predicate to one rectangle-- and the rest to another.-------------------------------------------------------------------------------moduleXMonad.Layout.LayoutBuilderP(LayoutP(..),layoutP,layoutAll,B.relBox,B.absBox,-- * Overloading ways to select windows-- $selectWinPredicate(..),Proxy(..),)whereimportControl.MonadimportData.Maybe(isJust)importXMonadimportqualifiedXMonad.StackSetasWimportXMonad.Util.WindowPropertiesimportqualifiedXMonad.Layout.LayoutBuilderasB-- $selectWin---- 'Predicate' exists because layouts are required to be serializable, and-- "XMonad.Util.WindowProperties" is not sufficient (for example it does not-- allow using regular expressions).---- compare "XMonad.Util.Invisible"-- | Type class for predicates. This enables us to manage not only Windows,-- but any objects, for which instance Predicate is defined.---- Another instance exists in XMonad.Util.WindowPropertiesRE in xmonad-extrasclassPredicatepwwherealwaysTrue::Proxyw->p-- ^ A predicate that is always True.checkPredicate::p->w->XBool-- ^ Check if given object (window or smth else) matches that predicate-- | Contains no actual data, but is needed to help select the correct instance-- of 'Predicate'dataProxya=Proxy-- | Data type for our layout.dataLayoutPpl1l2a=LayoutP(Maybea)(Maybea)pB.SubBox(MaybeB.SubBox)(l1a)(Maybe(l2a))deriving(Show,Read)-- | Use the specified layout in the described area windows that match given predicate and send the rest of the windows to the next layout in the chain.-- It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout.layoutP::(Reada,Eqa,LayoutClassl1a,LayoutClassl2a,LayoutClassl3a,Predicatepa)=>p->B.SubBox-- ^ The box to place the windows in->MaybeB.SubBox-- ^ Possibly an alternative box that is used when this layout handles all windows that are left->l1a-- ^ The layout to use in the specified area->LayoutPpl2l3a-- ^ Where to send the remaining windows->LayoutPpl1(LayoutPpl2l3)a-- ^ The resulting layoutlayoutPpropboxmboxsubnext=LayoutPNothingNothingpropboxmboxsub(Justnext)-- | Use the specified layout in the described area for all remaining windows.layoutAll::foralll1pa.(Reada,Eqa,LayoutClassl1a,Predicatepa)=>B.SubBox-- ^ The box to place the windows in->l1a-- ^ The layout to use in the specified area->LayoutPpl1Fulla-- ^ The resulting layoutlayoutAllboxsub=leta=alwaysTrue(Proxy::Proxya)inLayoutPNothingNothingaboxNothingsubNothinginstance(LayoutClassl1w,LayoutClassl2w,Predicatepw,Showw,Readw,Eqw,Typeablew,Showp)=>LayoutClass(LayoutPpl1l2)wwhere-- | Update window locations.runLayout(W.Workspace_(LayoutPsubfnextfpropboxmboxsubnext)s)rect=do(subs,nexts,subf',nextf')<-splitStackspropsubfnextfletselBox=ifisJustnextf'thenboxelsemaybeboxidmbox(sublist,sub')<-handlesubsubs$calcAreaselBoxrect(nextlist,next')<-casenextofNothing->return([],Nothing)Justn->do(res,l)<-handlennextsrectreturn(res,Justl)return(sublist++nextlist,Just$LayoutPsubf'nextf'propboxmboxsub'next')wherehandlels'r=do(res,ml)<-runLayout(W.Workspace""ls')rl'<-return$maybelidmlreturn(res,l')-- | Propagate messages.handleMessagelm|Just(IncMasterN_)<-fromMessagem=sendFocuslm|Just(Shrink)<-fromMessagem=sendFocuslm|Just(Expand)<-fromMessagem=sendFocuslm|otherwise=sendBothlm-- | Descriptive name for layout.description(LayoutP_____sub(Justnext))="layoutP "++descriptionsub++" "++descriptionnextdescription(LayoutP_____subNothing)="layoutP "++descriptionsubsendSub::(LayoutClassl1a,LayoutClassl2a,Reada,Showa,Eqa,Typeablea,Predicatepa)=>LayoutPpl1l2a->SomeMessage->X(Maybe(LayoutPpl1l2a))sendSub(LayoutPsubfnextfpropboxmboxsubnext)m=dosub'<-handleMessagesubmreturn$ifisJustsub'thenJust$LayoutPsubfnextfpropboxmbox(maybesubidsub')nextelseNothingsendBoth::(LayoutClassl1a,LayoutClassl2a,Reada,Showa,Eqa,Typeablea,Predicatepa)=>LayoutPpl1l2a->SomeMessage->X(Maybe(LayoutPpl1l2a))sendBothl@(LayoutP______Nothing)m=sendSublmsendBoth(LayoutPsubfnextfpropboxmboxsub(Justnext))m=dosub'<-handleMessagesubmnext'<-handleMessagenextmreturn$ifisJustsub'||isJustnext'thenJust$LayoutPsubfnextfpropboxmbox(maybesubidsub')(Just$maybenextidnext')elseNothingsendNext::(LayoutClassl1a,LayoutClassl2a,Reada,Showa,Eqa,Typeablea,Predicatepa)=>LayoutPpl1l2a->SomeMessage->X(Maybe(LayoutPpl1l2a))sendNext(LayoutP______Nothing)_=returnNothingsendNext(LayoutPsubfnextfpropboxmboxsub(Justnext))m=donext'<-handleMessagenextmreturn$ifisJustnext'thenJust$LayoutPsubfnextfpropboxmboxsubnext'elseNothingsendFocus::(LayoutClassl1a,LayoutClassl2a,Reada,Showa,Eqa,Typeablea,Predicatepa)=>LayoutPpl1l2a->SomeMessage->X(Maybe(LayoutPpl1l2a))sendFocusl@(LayoutPsubf______)m=dofoc<-isFocussubfiffocthensendSublmelsesendNextlmisFocus::(Showa)=>Maybea->XBoolisFocusNothing=returnFalseisFocus(Justw)=doms<-(W.stack.W.workspace.W.current)`fmap`getswindowsetreturn$maybeFalse(\s->showw==(show$W.focuss))ms-- | Split given list of objects (i.e. windows) using predicate.splitBy::(Predicatepw)=>p->[w]->X([w],[w])splitBypropws=foldMstep([],[])wswherestep(good,bad)w=dook<-checkPredicatepropwreturn$ifokthen(w:good,bad)else(good,w:bad)splitStack::(Predicatepw,Eqw)=>Maybe(W.Stackw)->p->Maybew->Maybew->X(Maybe(W.Stackw),Maybe(W.Stackw),Maybew,Maybew)splitStackNothing___=return(Nothing,Nothing,Nothing,Nothing)splitStack(Justs)propsubfnextf=doletws=W.integrates(good,other)<-splitBypropwsletsubf'=focgoodsubfnextf'=focothernextfreturn(differentiate'subf'good,differentiate'nextf'other,subf',nextf')wherefoc[]_=Nothingfoclf=ifW.focuss`elem`lthenJust$W.focusselseifmaybeFalse(`elem`l)fthenfelseJust$headlcalcArea::B.SubBox->Rectangle->RectanglecalcArea(B.SubBoxxposyposwidthheight)rect=Rectangle(rect_xrect+fromIntegralxpos')(rect_yrect+fromIntegralypos')width'height'wherexpos'=calcFalsexpos$rect_widthrectypos'=calcFalseypos$rect_heightrectwidth'=calcTruewidth$rect_widthrect-xpos'height'=calcTrueheight$rect_heightrect-ypos'calcznegvaltot=fromIntegral$min(fromIntegraltot)$max0$casevalofB.Relv->floor$v*fromIntegraltotB.Absv->ifv<0||(zneg&&v==0)then(fromIntegraltot)+velsevdifferentiate'::Eqq=>Maybeq->[q]->Maybe(W.Stackq)differentiate'_[]=Nothingdifferentiate'Nothingw=W.differentiatewdifferentiate'(Justf)w|f`elem`w=Just$W.Stack{W.focus=f,W.up=reverse$takeWhile(/=f)w,W.down=tail$dropWhile(/=f)w}|otherwise=W.differentiatewinstancePredicatePropertyWindowwherealwaysTrue_=ConstTruecheckPredicate=hasProperty