about summary refs log tree commit diff stats
Commit message (Expand)AuthorAgeFilesLines
* added a note how to achieve status info in the bararg@10ksloc.org2006-07-211-1/+17
* preparing 0.6 which will be available in the evening after sanders patch approx.arg@10ksloc.org2006-07-212-21/+8
* sanitization of several clunky stuff, removed heretag (rarely of use), simpli...arg@10ksloc.org2006-07-214-48/+40
* applied sanders no_sizehints for tiled mode patch (thx!)arg@10ksloc.org2006-07-202-11/+11
* serious mistake in pop() (forgot to set c->prev to NULL on pop)arg@10ksloc.org2006-07-201-0/+1
* using double-linked list in order to get correct prev focus handlingarg@10ksloc.org2006-07-204-21/+45
* added yet another CUTOMIZE tagarg@10ksloc.org2006-07-201-0/+2
* cleaned the CUSTOMIZE flagsarg@10ksloc.org2006-07-203-5/+9
* made status bar drawing more robust, implemented togglemax and togglemode, wo...arg@10ksloc.org2006-07-205-33/+59
* cleaned up codearg@10ksloc.org2006-07-208-85/+78
* Added tag 0.4 for changeset eb3165734f00fe7f7da8aeebaed00e60a57caac9arg@10ksloc.org2006-07-201-0/+1
* prepared 0.4 0.4arg@10ksloc.org2006-07-202-4/+10
* using O3 instead of Os, binary size still < 40kbarg@10ksloc.org2006-07-201-1/+1
* fixed version in man pagearg@10ksloc.org2006-07-201-1/+1
* yet another html patcharg@10ksloc.org2006-07-201-5/+5
* updated htmlarg@10ksloc.org2006-07-201-5/+5
* makefile now sets permissions for executables and man pagesarg@10ksloc.org2006-07-201-0/+6
* removed c->f{x,y,w,h} and c->t{x,y,w,h} in favor for the new rule handling re...arg@10ksloc.org2006-07-204-114/+85
* implemented regexp matching for rulesarg@10ksloc.org2006-07-194-32/+40
* applied Jukka's patch with s/ModKeyMask/MODKEY/garg@10ksloc.org2006-07-194-24/+25
* removed TODO, because dwm is nearly finishedarg@10ksloc.org2006-07-191-1/+0
* reapplied my default keybindingsarg@10ksloc.org2006-07-191-1/+10
* alternate dwm.pngarg@10ksloc.org2006-07-191-0/+0
* Added tag 0.3 for changeset 7e66082e5092fb0bccd18a3695a0bec52c80fdb2arg@10ksloc.org2006-07-191-0/+1
* some changes in the html page 0.3arg@10ksloc.org2006-07-191-2/+2
* prepared 0.3arg@10ksloc.org2006-07-191-10/+1
* fixed the bug mentioned by Sanderarg@10ksloc.org2006-07-191-3/+7
* refactored Sanders code somewhatarg@10ksloc.org2006-07-193-15/+8
* implemented fallback for too many clients in stacked modearg@10ksloc.org2006-07-192-3/+10
* and another fix...arg@10ksloc.org2006-07-191-1/+1
* yet another typo fixarg@10ksloc.org2006-07-191-2/+2
* fixed a typoarg@10ksloc.org2006-07-191-1/+1
* floating clients get random (x,y) offsets nowarg@10ksloc.org2006-07-191-0/+7
* applied Sanders resize patch, fixed lower bugarg@10ksloc.org2006-07-195-19/+43
* changed CFLAGsarg@mmvi2006-07-181-5/+5
* firefox instance is different nowarg@mmvi2006-07-181-1/+1
* changed occurrences of wmii.de into 10kloc.org in dwm.html, because 10kloc.or...Anselm R. Garbe2006-07-181-8/+8
* implemened distinguishing float/managed geometries of clients (works quite well)Anselm R. Garbe2006-07-185-78/+105
* pop on heretagAnselm R. Garbe2006-07-183-8/+16
* added heretag command which allows to tag a client of a foreign tag with curr...Anselm R. Garbe2006-07-186-10/+42
* using EXIT_stuff in exit() nowAnselm R. Garbe2006-07-182-8/+7
* simplified MakefileAnselm R. Garbe2006-07-172-3/+2
* added new stuffAnselm R. Garbe2006-07-171-9/+6
* updated htmlAnselm R. Garbe2006-07-171-9/+9
* patched dwmAnselm R. Garbe2006-07-173-30/+46
* updated READMEAnselm R. Garbe2006-07-171-2/+2
* Added tag 0.2 for changeset 0a6472e2203994bc5738d40a340d26f7ec9d6062Anselm R. Garbe2006-07-171-0/+1
* updated html 0.2Anselm R. Garbe2006-07-171-1/+1
* ordered variables in structs and source files alphabeticallyAnselm R. Garbe2006-07-177-77/+70
* slight change to dwm.1Anselm R. Garbe2006-07-171-1/+2
class="w"> sequtils import sugar import algorithm import css/selector import css/parser import css/values import html/dom import html/tags #TODO case sensitivity type SelectResult = object success: bool pseudo: PseudoElem func selectres(s: bool, p: PseudoElem = PSEUDO_NONE): SelectResult = return SelectResult(success: s, pseudo: p) func psuccess(s: SelectResult): bool = return s.pseudo == PSEUDO_NONE and s.success func attrSelectorMatches(elem: Element, sel: Selector): bool = case sel.rel of ' ': return sel.attr in elem.attributes of '=': return elem.attr(sel.attr) == sel.value of '~': return sel.value in unicode.split(elem.attr(sel.attr)) of '|': let val = elem.attr(sel.attr) return val == sel.value or sel.value.startsWith(val & '-') of '^': return elem.attr(sel.attr).startsWith(sel.value) of '$': return elem.attr(sel.attr).endsWith(sel.value) of '*': return elem.attr(sel.attr).contains(sel.value) else: return false func pseudoSelectorMatches(elem: Element, sel: Selector): bool = case sel.pseudo of "first-child": return elem.parentNode.firstElementChild == elem of "last-child": return elem.parentNode.lastElementChild == elem of "only-child": return elem.parentNode.firstElementChild == elem and elem.parentNode.lastElementChild == elem of "hover": return elem.hover of "root": return elem == elem.ownerDocument.root else: return false func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult = case sel.elem of "before": return selectres(true, PSEUDO_BEFORE) of "after": return selectres(true, PSEUDO_AFTER) else: return selectres(false) func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult func funcSelectorMatches(elem: Element, sel: Selector): SelectResult = case sel.name of "not": for slist in sel.fsels: let res = elem.selectorsMatch(slist) if res.success: return selectres(false) return selectres(true) of "is", "where": for slist in sel.fsels: let res = elem.selectorsMatch(slist) if res.success: return selectres(true) return selectres(false) else: discard func selectorMatches(elem: Element, sel: Selector): SelectResult = case sel.t of TYPE_SELECTOR: return selectres(elem.tagType == sel.tag) of CLASS_SELECTOR: return selectres(sel.class in elem.classList) of ID_SELECTOR: return selectres(sel.id == elem.id) of ATTR_SELECTOR: return selectres(elem.attrSelectorMatches(sel)) of PSEUDO_SELECTOR: return selectres(pseudoSelectorMatches(elem, sel)) of PSELEM_SELECTOR: return pseudoElemSelectorMatches(elem, sel) of UNIVERSAL_SELECTOR: return selectres(true) of FUNC_SELECTOR: return funcSelectorMatches(elem, sel) of COMBINATOR_SELECTOR: #combinator without at least two members makes no sense assert sel.csels.len > 1 let match = elem.selectorsMatch(sel.csels[^1]) if match.success: var i = sel.csels.len - 2 case sel.ct of DESCENDANT_COMBINATOR: var e = elem.parentElement while e != nil and i >= 0: let res = e.selectorsMatch(sel.csels[i]) if res.pseudo != PSEUDO_NONE: return selectres(false) if res.success: dec i e = e.parentElement of CHILD_COMBINATOR: var e = elem.parentElement while e != nil and i >= 0: let res = e.selectorsMatch(sel.csels[i]) if res.pseudo != PSEUDO_NONE: return selectres(false) if not res.success: return selectres(false) dec i e = e.parentElement of NEXT_SIBLING_COMBINATOR: var e = elem.previousElementSibling while e != nil and i >= 0: let res = e.selectorsMatch(sel.csels[i]) if res.pseudo != PSEUDO_NONE: return selectres(false) if not res.success: return selectres(false) dec i e = e.previousElementSibling of SUBSEQ_SIBLING_COMBINATOR: var e = elem.previousElementSibling while e != nil and i >= 0: let res = e.selectorsMatch(sel.csels[i]) if res.pseudo != PSEUDO_NONE: return selectres(false) if res.success: dec i e = e.previousElementSibling return selectres(i == -1, match.pseudo) else: return selectres(false) func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult = for sel in selectors.sels: let res = selectorMatches(elem, sel) if not res.success: return selectres(false) if res.pseudo != PSEUDO_NONE: if result.pseudo != PSEUDO_NONE: return selectres(false) result.pseudo = res.pseudo result.success = true func selectElems(document: Document, sel: Selector): seq[Element] = case sel.t of TYPE_SELECTOR: return document.type_elements[sel.tag] of ID_SELECTOR: return document.id_elements[sel.id] of CLASS_SELECTOR: return document.class_elements[sel.class] of UNIVERSAL_SELECTOR: return document.all_elements of ATTR_SELECTOR: return document.all_elements.filter((elem) => attrSelectorMatches(elem, sel)) of PSEUDO_SELECTOR: return document.all_elements.filter((elem) => pseudoSelectorMatches(elem, sel)) of PSELEM_SELECTOR: return document.all_elements.filter((elem) => pseudoElemSelectorMatches(elem, sel)) of FUNC_SELECTOR: return document.all_elements.filter((elem) => selectorMatches(elem, sel)) of COMBINATOR_SELECTOR: return document.all_elements.filter((elem) => selectorMatches(elem, sel)) func selectElems(document: Document, selectors: SelectorList): seq[Element] = assert(selectors.len > 0) let sellist = optimizeSelectorList(selectors) result = document.selectElems(selectors[0]) var i = 1 while i < sellist.len: result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess) inc i proc querySelector*(document: Document, q: string): seq[Element] = let ss = newStringStream(q) let cvals = parseCSSListOfComponentValues(ss) let selectors = parseSelectors(cvals) for sel in selectors: result.add(document.selectElems(sel)) proc applyProperty(elem: Element, s: CSSSpecifiedValue, pseudo: PseudoElem) = var parent: CSSComputedValues if elem.parentElement != nil: parent = elem.parentElement.cssvalues else: parent = rootProperties() let cval = getComputedValue(s, elem.cssvalues, parent) if cval.t == PROPERTY_MARGIN: let left = CSSSpecifiedValue(t: PROPERTY_MARGIN_LEFT, v: VALUE_LENGTH, length: cval.length, globalValue: s.globalValue) let right = CSSSpecifiedValue(t: PROPERTY_MARGIN_RIGHT, v: VALUE_LENGTH, length: cval.length, globalValue: s.globalValue) let top = CSSSpecifiedValue(t: PROPERTY_MARGIN_TOP, v: VALUE_LENGTH, length: cval.length, globalValue: s.globalValue) let bottom = CSSSpecifiedValue(t: PROPERTY_MARGIN_BOTTOM, v: VALUE_LENGTH, length: cval.length, globalValue: s.globalValue) elem.applyProperty(left, pseudo) elem.applyProperty(right, pseudo) elem.applyProperty(top, pseudo) elem.applyProperty(bottom, pseudo) return case pseudo of PSEUDO_NONE: elem.cssvalues[cval.t] = cval of PSEUDO_BEFORE: if elem.cssvalues_before == nil: elem.cssvalues_before.rootProperties() elem.cssvalues_before[cval.t] = cval of PSEUDO_AFTER: if elem.cssvalues_after == nil: elem.cssvalues_after.rootProperties() elem.cssvalues_after[cval.t] = cval elem.cssapplied = true elem.rendered = false type ParsedRule* = tuple[sels: seq[SelectorList], oblock: CSSSimpleBlock] ParsedStylesheet* = seq[ParsedRule] ApplyResult = object normal: seq[tuple[e:Element,d:CSSSpecifiedValue,p:PseudoElem]] important: seq[tuple[e:Element,d:CSSSpecifiedValue,p:PseudoElem]] proc parseStylesheet*(s: Stream): ParsedStylesheet = for v in parseCSS(s).value: let sels = parseSelectors(v.prelude) if sels.len > 1 or sels[^1].len > 0: result.add((sels: sels, oblock: v.oblock)) func calcRules(elem: Element, rules: ParsedStylesheet): array[low(PseudoElem)..high(PseudoElem), seq[CSSSimpleBlock]] = var tosorts: array[low(PseudoElem)..high(PseudoElem), seq[tuple[s:int,b:CSSSimpleBlock]]] for rule in rules: for sel in rule.sels: let match = elem.selectorsMatch(sel) if match.success: let spec = getSpecificity(sel) tosorts[match.pseudo].add((spec,rule.oblock)) for i in low(PseudoElem)..high(PseudoElem): tosorts[i].sort((x, y) => cmp(x.s,y.s)) result[i] = tosorts[i].map((x) => x.b) proc applyItems*(ares: var ApplyResult, elem: Element, decls: seq[CSSParsedItem], pseudo: PseudoElem) = for item in decls: if item of CSSDeclaration: let decl = CSSDeclaration(item) if decl.important: ares.important.add((elem, getSpecifiedValue(decl), pseudo)) else: ares.normal.add((elem, getSpecifiedValue(decl), pseudo)) proc applyRules*(document: Document, pss: ParsedStylesheet, reset: bool = false): ApplyResult = var stack: seq[Element] document.root.cssvalues.rootProperties() stack.add(document.root) while stack.len > 0: let elem = stack.pop() if not elem.cssapplied: if reset: elem.cssvalues.rootProperties() elem.cssvalues_before = nil elem.cssvalues_after = nil let rules_pseudo = calcRules(elem, pss) for pseudo in low(PseudoElem)..high(PseudoElem): let rules = rules_pseudo[pseudo] for rule in rules: let decls = parseCSSListOfDeclarations(rule.value) result.applyItems(elem, decls, pseudo) var i = elem.children.len - 1 while i >= 0: let child = elem.children[i] stack.add(child) dec i proc applyAuthorRules*(document: Document): ApplyResult = var stack: seq[Element] var embedded_rules: seq[ParsedStylesheet] stack.add(document.head) var rules_head = "" for child in document.head.children: if child.tagType == TAG_STYLE: for ct in child.childNodes: if ct.nodeType == TEXT_NODE: rules_head &= Text(ct).data stack.setLen(0) stack.add(document.root) if rules_head.len > 0: let parsed = newStringStream(rules_head).parseStylesheet() embedded_rules.add(parsed) while stack.len > 0: let elem = stack.pop() var rules_local = "" for child in elem.children: if child.tagType == TAG_STYLE: for ct in child.childNodes: if ct.nodeType == TEXT_NODE: rules_local &= Text(ct).data if rules_local.len > 0: let parsed = newStringStream(rules_local).parseStylesheet() embedded_rules.add(parsed) if not elem.cssapplied: let this_rules = embedded_rules.concat() let rules_pseudo = calcRules(elem, this_rules) for pseudo in low(PseudoElem)..high(PseudoElem): let rules = rules_pseudo[pseudo] for rule in rules: let decls = parseCSSListOfDeclarations(rule.value) result.applyItems(elem, decls, pseudo) let style = elem.attr("style") if style.len > 0: let inline_rules = newStringStream(style).parseCSSListOfDeclarations() result.applyItems(elem, inline_rules, PSEUDO_NONE) var i = elem.children.len - 1 while i >= 0: let child = elem.children[i] stack.add(child) dec i if rules_local.len > 0: discard embedded_rules.pop() proc applyStylesheets*(document: Document, uass: ParsedStylesheet, userss: ParsedStylesheet) = let ua = document.applyRules(uass, true) let user = document.applyRules(userss) let author = document.applyAuthorRules() var elems: seq[Element] for rule in ua.normal: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for rule in user.normal: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for rule in author.normal: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for rule in author.important: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for rule in user.important: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for rule in ua.important: if not rule.e.cssapplied: elems.add(rule.e) rule.e.applyProperty(rule.d, rule.p) for elem in elems: if elem.parentElement != nil: elem.cssvalues.inheritProperties(elem.parentElement.cssvalues) if elem.cssvalues_before != nil: elem.cssvalues_before.inheritProperties(elem.cssvalues) if elem.cssvalues_after != nil: elem.cssvalues_after.inheritProperties(elem.cssvalues) proc refreshStyle*(elem: Element) = elem.cssapplied = false for child in elem.children: child.refreshStyle()