-
Notifications
You must be signed in to change notification settings - Fork 266
/
replace-class.lisp
89 lines (82 loc) · 4.09 KB
/
replace-class.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(in-package :dynamic-mixins-swm)
(defgeneric replace-class-in-mixin (object new-class old-class &rest initargs)
(:method ((object standard-object) n o &rest rest)
(declare (ignore o))
(apply #'change-class object n rest)))
(defmethod replace-class-in-mixin ((object mixin-object)
(new-class class)
(old-class class)
&rest rest)
(apply #'replace-class-in-mixin
object (class-name new-class) (class-name old-class) rest))
(defmethod replace-class-in-mixin ((object mixin-object)
(new-class class)
(old-class symbol)
&rest rest)
(apply #'replace-class-in-mixin object (class-name new-class) old-class rest))
(defmethod replace-class-in-mixin ((object mixin-object)
(new-class symbol)
(old-class class)
&rest rest)
(apply #'replace-class-in-mixin object new-class (class-name old-class) rest))
(defmethod replace-class-in-mixin ((object mixin-object)
(new-class symbol)
(old-class symbol)
&rest initargs)
(cond ((eql new-class old-class)
object)
(t
;; First we disable all non-compatible minor modes.
(loop for mode in (stumpwm::list-minor-modes object)
unless (let* ((scope (stumpwm:minor-mode-scope mode))
(st (stumpwm::scope-type scope)))
(or (eql new-class st)
(stumpwm::superclassp new-class st)))
do (stumpwm::autodisable-minor-mode mode object))
(if (typep object 'mixin-object)
(flet ((mix-it (mix-list)
(apply #'change-class
object (ensure-mixin mix-list) initargs)
(stumpwm::sync-minor-modes object)
object))
(let* ((tag nil)
(old-class-obj (find-class old-class))
(fn (lambda (e)
(when (or (eql e old-class) (eql e old-class-obj))
(setf tag t)
t)))
(mix-list
(make-mix-list
:list (remove-duplicates
(mapcar #'%find-class
(subst-if new-class
fn
(mixin-classes
(class-of object))))))))
(if tag
(mix-it mix-list)
(restart-case
(error "~A is not an explicitly mixed class in ~A"
old-class object)
(continue ()
object)
(mix-in-new-class ()
(ensure-mix object new-class))))))
(apply #'change-class object new-class initargs)))))
(defgeneric replace-class (object new-class &rest initargs))
(defmethod replace-class :around (object new &rest rest)
(restart-case (progn
(handler-bind ((error
(lambda (c)
(let ((r1 (find-restart 'continue c))
(r2 (find-restart 'stumpwm::continue c)))
(cond (r1 (invoke-restart r1))
(r2 (invoke-restart r2)))))))
(call-next-method))
(unless (typep object new)
(error "Failed to change class ~A ~A" object new)))
(force-change ()
:report (lambda (s)
(format s "Change class to ~A, removing all mixins" new))
(apply #'change-class object new rest)))
object)