about summary refs log tree commit diff stats
path: root/draw.c
Commit message (Expand)AuthorAgeFilesLines
* applied Jukka's sizeof K&R compliance patch, applied Manuels' last-line print...arg@mig292006-11-261-2/+2
* added a similiar patch to Daves solution to indicate if there are clients wit...arg@mig292006-11-221-8/+24
* returning to old bar colorization behavior, like sander proposed for consiste...arg@mig292006-11-211-1/+1
* applied Gottox patchesarg@mig292006-11-211-5/+2
* code polishing, removed unnecessary newlinesAnselm R. Garbe2006-10-061-13/+1
* removed the stack position stuffAnselm R. Garbe2006-10-051-3/+1
* applied dave's highlight patch for big fontsAnselm R. Garbe2006-09-291-1/+1
* added symbols for different modesAnselm R. Garbe2006-09-291-1/+3
* added slight error check to getcolorarg@mmvi2006-09-261-1/+2
* applied Jukkas patcharg@mmvi2006-09-251-2/+2
* removed all dotile checksarg@mmvi2006-09-221-1/+1
* removed a bunch of lines through making function signatures more consistent w...Anselm R. Garbe2006-09-121-16/+8
* removed crappy variablesAnselm R. Garbe2006-08-281-2/+0
* applied sanders somepatches.patchAnselm R. Garbe2006-08-281-4/+5
* trying a different configurationAnselm R. Garbe2006-08-251-3/+6
* removed small 1px gap, somehow without it things feel betterAnselm R. Garbe2006-08-251-1/+1
* oopsAnselm R. Garbe2006-08-251-1/+1
* fixed typoAnselm R. Garbe2006-08-251-1/+1
* s/TILED/TILE/gAnselm R. Garbe2006-08-251-1/+1
* removed a bunch of lines, made mode symbols configurableAnselm R. Garbe2006-08-251-7/+2
* changed symbols for float/tiled mode, added mouse-driven mode toggle to butto...Anselm R. Garbe2006-08-251-1/+1
* small fix to separate client title from right-most tagAnselm R. Garbe2006-08-251-2/+2
* new color stuff/new rendering stuffAnselm R. Garbe2006-08-251-30/+19
* back to 3 colorsAnselm R. Garbe2006-08-251-24/+23
* fixedAnselm R. Garbe2006-08-241-6/+6
* 3->4 colorsAnselm R. Garbe2006-08-241-13/+7
* found less intrusive wayAnselm R. Garbe2006-08-241-6/+12
* changing tag indicator through underlineAnselm R. Garbe2006-08-241-26/+16
* updated man pageAnselm R. Garbe2006-08-231-49/+47
* implemented right tag drawing in the status bar and titlebarsAnselm R. Garbe2006-08-231-10/+21
* tags appear in the left againAnselm R. Garbe2006-08-231-5/+5
* titlebars contain tags in the right nowAnselm R. Garbe2006-08-221-6/+5
* fixed string cuttingAnselm R.Garbe2006-08-141-6/+6
* fixed string cutting in draw.cAnselm R.Garbe2006-08-141-2/+10
* implemented viewextend and added M-S-C-n shortcuts for extending the current ...Anselm R.Garbe2006-08-111-2/+2
* implement multi-tag selection through button3 click on the specific tagAnselm R.Garbe2006-08-111-2/+2
* simplified drawtextAnselm R.Garbe2006-08-111-21/+14
* applied sumik's multihead patchAnselm R.Garbe2006-08-101-1/+1
* readded border color, this sucks leastAnselm R.Garbe2006-08-101-14/+22
* drawing border with fg colorAnselm R.Garbe2006-08-101-1/+14
* removed unnecessary border colorAnselm R.Garbe2006-08-101-21/+0
* changed signature of drawtextarg@10ksloc.org2006-08-071-12/+10
* status box should have a border in my eyesarg@10ksloc.org2006-08-071-1/+1
* removed TLast tag enum, now tags is simple defined as char *[] array, the res...arg@10ksloc.org2006-08-031-2/+2
* changed Client->tags and Rule->tags to be Bool (I'll also try to remove the T...arg@10ksloc.org2006-08-031-4/+4
* made fullscreen apps working fine in floating mode (there is no sane way to m...arg@10ksloc.org2006-08-021-1/+0
* committed a patch which fixes the hints of Jukkaarg@10ksloc.org2006-08-011-1/+1
* made status bar drawing more robust, implemented togglemax and togglemode, wo...arg@10ksloc.org2006-07-201-7/+6
* cleaned up codearg@10ksloc.org2006-07-201-2/+4
* added heretag command which allows to tag a client of a foreign tag with curr...Anselm R. Garbe2006-07-181-1/+1
, srcNoTc: int # length of 'dest', 'src' without the # transitive closure destInfo: set[RootInfo] info: TLineInfo W = object # WriteTrackContext owner: PSym returnsNew: AssignToResult # assignments to 'result' assignments: seq[Assignment] # list of all assignments in this proc proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) = case n.kind of nkSym: if n.sym.kind in {skParam, skVar, skTemp, skLet, skResult, skForVar}: if n.sym.kind in {skResult, skParam}: incl(info, rootIsResultOrParam) result.add(cast[ptr TSym](n.sym)) of nkHiddenDeref, nkDerefExpr: incl(info, rootIsHeapAccess) allRoots(n.sons[0], result, info) of nkDotExpr, nkBracketExpr, nkCheckedFieldExpr, nkHiddenAddr, nkObjUpConv, nkObjDownConv: allRoots(n.sons[0], result, info) of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch, nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast: allRoots(n.lastSon, result, info) of nkCallKinds: if getMagic(n) == mSlice: allRoots(n.sons[1], result, info) else: # we do significantly better here by using the available escape # information: if n.sons[0].typ.isNil: return var typ = n.sons[0].typ if typ != nil: typ = skipTypes(typ, abstractInst) if typ.kind != tyProc: typ = nil else: assert(sonsLen(typ) == sonsLen(typ.n)) for i in 1 ..< n.len: let it = n.sons[i] if typ != nil and i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) let paramType = typ.n.sons[i] if paramType.typ.isCompileTimeOnly: continue if sfEscapes in paramType.sym.flags or paramType.typ.kind == tyVar: allRoots(it, result, info) else: allRoots(it, result, info) else: for i in 0..<n.safeLen: allRoots(n.sons[i], result, info) proc addAsgn(a: var Assignment; dest, src: PNode; destInfo: set[RootInfo]) = a.dest = @[] a.src = @[] a.destInfo = destInfo allRoots(dest, a.dest, a.destInfo) if dest.kind == nkSym: incl(a.destInfo, rootIsSym) if src != nil: var dummy: set[RootInfo] allRoots(src, a.src, dummy) a.destNoTc = a.dest.len a.srcNoTc = a.src.len a.info = dest.info #echo "ADDING ", dest.info, " ", a.destInfo proc srcHasSym(a: Assignment; x: ptr TSym): bool = for i in 0 ..< a.srcNoTc: if a.src[i] == x: return true proc returnsNewExpr*(n: PNode): NewLocation = case n.kind of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nkFloatLit..nkFloat64Lit, nkNilLit: result = newLit of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkOfBranch, nkElifBranch, nkElse, nkExceptBranch, nkFinally, nkCast: result = returnsNewExpr(n.lastSon) of nkCurly, nkBracket, nkPar, nkTupleConstr, nkObjConstr, nkClosure, nkIfExpr, nkIfStmt, nkWhenStmt, nkCaseStmt, nkTryStmt: result = newLit for i in ord(n.kind == nkObjConstr) ..< n.len: let x = returnsNewExpr(n.sons[i]) case x of newNone: return newNone of newLit: discard of newCall: result = newCall of nkCallKinds: if n.sons[0].typ != nil and tfReturnsNew in n.sons[0].typ.flags: result = newCall else: result = newNone proc deps(w: var W; dest, src: PNode; destInfo: set[RootInfo]) = # let x = (localA, localB) # compute 'returnsNew' property: let retNew = if src.isNil: newNone else: returnsNewExpr(src) if dest.kind == nkSym and dest.sym.kind == skResult: if retNew != newNone: if w.returnsNew != asgnOther: w.returnsNew = asgnNew else: w.returnsNew = asgnOther # mark the dependency, but # rule out obviously innocent assignments like 'somebool = true' if dest.kind == nkSym and retNew == newLit: discard else: let L = w.assignments.len w.assignments.setLen(L+1) addAsgn(w.assignments[L], dest, src, destInfo) proc depsArgs(w: var W; n: PNode) = if n.sons[0].typ.isNil: return var typ = skipTypes(n.sons[0].typ, abstractInst) if typ.kind != tyProc: return # echo n.info, " ", n, " ", w.owner.name.s, " ", typeToString(typ) assert(sonsLen(typ) == sonsLen(typ.n)) for i in 1 ..< n.len: let it = n.sons[i] if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) let paramType = typ.n.sons[i] if paramType.typ.isCompileTimeOnly: continue var destInfo: set[RootInfo] = {} if sfWrittenTo in paramType.sym.flags or paramType.typ.kind == tyVar: # p(f(x, y), X, g(h, z)) destInfo.incl markAsWrittenTo if sfEscapes in paramType.sym.flags: destInfo.incl markAsEscaping if destInfo != {}: deps(w, it, nil, destInfo) proc deps(w: var W; n: PNode) = case n.kind of nkLetSection, nkVarSection: for child in n: let last = lastSon(child) if last.kind == nkEmpty: continue if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}: if child.len-2 != last.len: return for i in 0 .. child.len-3: deps(w, child.sons[i], last.sons[i], {}) else: for i in 0 .. child.len-3: deps(w, child.sons[i], last, {}) of nkAsgn, nkFastAsgn: deps(w, n.sons[0], n.sons[1], {}) else: for i in 0 ..< n.safeLen: deps(w, n.sons[i]) if n.kind in nkCallKinds: if getMagic(n) in {mNew, mNewFinalize, mNewSeq}: # may not look like an assignment, but it is: deps(w, n.sons[1], newNodeIT(nkObjConstr, n.info, n.sons[1].typ), {}) else: depsArgs(w, n) proc possibleAliases(w: var W; result: var seq[ptr TSym]) = # this is an expensive fixpoint iteration. We could speed up this analysis # by a smarter data-structure but we wait until profiling shows us it's # expensive. Usually 'w.assignments' is small enough. var alreadySeen = initIntSet() template addNoDup(x) = if not alreadySeen.containsOrIncl(x.id): result.add x for x in result: alreadySeen.incl x.id var todo = 0 while todo < result.len: let x = result[todo] inc todo for i in 0..<len(w.assignments): let a = addr(w.assignments[i]) #if a.srcHasSym(x): # # y = f(..., x, ...) # for i in 0 ..< a.destNoTc: addNoDup a.dest[i] if a.destNoTc > 0 and a.dest[0] == x and rootIsSym in a.destInfo: # x = f(..., y, ....) for i in 0 ..< a.srcNoTc: addNoDup a.src[i] proc markWriteOrEscape(w: var W; conf: ConfigRef) = ## Both 'writes' and 'escapes' effects ultimately only care ## about *parameters*. ## However, due to aliasing, even locals that might not look as parameters ## have to count as parameters if they can alias a parameter: ## ## .. code-block:: nim ## proc modifies(n: Node) {.writes: [n].} = ## let x = n ## x.data = "abc" ## ## We call a symbol *parameter-like* if it is a parameter or can alias a ## parameter. ## Let ``p``, ``q`` be *parameter-like* and ``x``, ``y`` be general ## expressions. ## ## A write then looks like ``p[] = x``. ## An escape looks like ``p[] = q`` or more generally ## like ``p[] = f(q)`` where ``f`` can forward ``q``. for i in 0..<len(w.assignments): let a = addr(w.assignments[i]) if a.destInfo != {}: possibleAliases(w, a.dest) if {rootIsHeapAccess, markAsWrittenTo} * a.destInfo != {}: for p in a.dest: if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfWrittenTo) if w.owner.kind == skFunc and p.typ.kind != tyVar: localError(conf, a.info, "write access to non-var parameter: " & p.name.s) if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}: var destIsParam = false for p in a.dest: if p.kind in {skResult, skParam} and p.owner == w.owner: destIsParam = true break if destIsParam: possibleAliases(w, a.src) for p in a.src: if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfEscapes) proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) = var w: W w.owner = owner w.assignments = @[] # Phase 1: Collect and preprocess any assignments in the proc body: deps(w, body) # Phase 2: Compute the 'writes' and 'escapes' effects: markWriteOrEscape(w, conf) if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and containsGarbageCollectedRef(owner.typ.sons[0]): incl(owner.typ.flags, tfReturnsNew)