diff --git a/source/clog-gui.lisp b/source/clog-gui.lisp
index db7fab4..d5ccd88 100644
--- a/source/clog-gui.lisp
+++ b/source/clog-gui.lisp
@@ -55,6 +55,7 @@
(window-content generic-function)
(window-focus generic-function)
(window-close generic-function)
+ (window-valid-p function)
(window-maximized-p generic-function)
(window-maximize generic-function)
(window-normalize generic-function)
@@ -130,12 +131,8 @@
;; Implementation - clog-gui - Desktop GUI abstraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
(defclass clog-gui ()
- ((body
- :accessor body
- :documentation "Top level access to browser window")
- (current-win
+ ((current-win
:accessor current-win
:initform nil
:documentation "The current window at front")
@@ -207,7 +204,6 @@
\"clog-gui\". (Private)"
(let ((clog-gui (make-instance 'clog-gui)))
(setf (connection-data-item clog-body "clog-gui") clog-gui)
- (setf (body clog-gui) clog-body)
clog-gui))
;;;;;;;;;;;;;;;;;;;;;;;;
@@ -242,6 +238,7 @@
(body-left-offset 0)
(body-right-offset 0)
(use-clog-debugger nil)
+ (parent-desktop-obj nil)
(w3-css-url "/css/w3.css")
(jquery-ui-css "/css/jquery-ui.css")
(jquery-ui "/js/jquery-ui.js"))
@@ -249,11 +246,16 @@
If W3-CSS-URL has not been loaded before is installed unless is nil.
BODY-LEFT-OFFSET and BODY-RIGHT-OFFSET limit width on maximize. If
use-clog-debugger then a graphical debugger is set for all events.
+parent-desktop-obj is used if this window is a popup or otherwise a
+slave of another clog-gui page.
NOTE: use-clog-debugger should not be set for security issues
on non-secure environments."
- (let ((app (create-clog-gui clog-body)))
- (setf (body-left-offset app) body-left-offset)
- (setf (body-right-offset app) body-right-offset))
+ (if parent-desktop-obj
+ (let ((app (connection-data-item parent-desktop-obj "clog-gui")))
+ (setf (connection-data-item clog-body "clog-gui") app))
+ (let ((app (create-clog-gui clog-body)))
+ (setf (body-left-offset app) body-left-offset)
+ (setf (body-right-offset app) body-right-offset)))
(set-on-full-screen-change (html-document clog-body) 'reorient-all-windows)
(set-on-orientation-change (window clog-body) 'reorient-all-windows)
(set-on-resize (window clog-body) 'reorient-all-windows)
@@ -302,7 +304,7 @@ create-gui-menu-bar."))
(defmethod menu-bar-height ((obj clog-obj))
(let ((app (connection-data-item obj "clog-gui")))
- (if (menu app)
+ (if (and app (menu app))
(height (menu app))
0)))
@@ -326,15 +328,16 @@ create-gui-menu-bar."))
window or nil if not found"))
(defmethod window-to-top-by-title ((obj clog-obj) title)
- (let ((app (connection-data-item obj "clog-gui"))
- (r nil))
- (maphash (lambda (key value)
- (declare (ignore key))
- (when (equalp (window-title value) title)
- (window-focus value)
- (setf r value)))
- (windows app))
- r))
+ (when title
+ (let ((app (connection-data-item obj "clog-gui"))
+ (r nil))
+ (maphash (lambda (key value)
+ (declare (ignore key))
+ (when (and (equalp (window-title value) title)
+ (window-focus value)
+ (setf r value))))
+ (windows app))
+ r)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; window-to-top-by-param ;;
@@ -557,10 +560,12 @@ Only one instance allowed."))
(setf (window-select app) window-select)
(set-on-change window-select (lambda (obj)
(let ((win (gethash (value obj) (windows app))))
- (when win
+ (if (window-valid-p win)
(unless (keep-on-top win)
(setf (hiddenp win) nil)
- (window-focus win))))))
+ (window-focus win))
+ (execute window-select (format nil "remove(~A.selectedIndex)"
+ (script-id window-select)))))))
(when content
(create-option window-select :content content))
window-select))
@@ -897,9 +902,10 @@ window-to-top-by-param or window-by-param."))
(border-class *default-border-class*)
(title-class *default-title-class*)
(html-id nil))
- (let ((app (connection-data-item obj "clog-gui")))
+ (let ((app (connection-data-item obj "clog-gui"))
+ (body (connection-body obj)))
(unless html-id
- (setf html-id (generate-id)))
+ (setf html-id (format nil "~A" (generate-id))))
(when (eql (hash-table-count (windows app)) 0)
;; If previously no open windows reset default position
(setf (last-x app) 0)
@@ -914,10 +920,10 @@ window-to-top-by-param or window-by-param."))
(setf (last-y app) (menu-bar-height obj)))
(setf top (last-y app))
(incf (last-y app) *top-bar-height*)
- (when (> top (- (inner-height (window (body app))) (last-y app)))
+ (when (> top (- (inner-height (window body)) (last-y app)))
(setf (last-y app) (menu-bar-height obj))))
- (let ((win (create-child (body app)
- (format nil
+ (let ((win (create-child body
+ (format nil
"
@@ -959,7 +965,7 @@ window-to-top-by-param or window-by-param."))
(setf (closer win) (attach-as-child win (format nil "~A-closer" html-id)))
(setf (sizer win) (attach-as-child win (format nil "~A-sizer" html-id)))
(setf (content win) (attach-as-child win (format nil "~A-body" html-id)))
- (setf (gethash (format nil "~A" html-id) (windows app)) win)
+ (setf (gethash html-id (windows app)) win)
(set-on-click win (lambda (obj)
(declare (ignore obj))
(unless (> (modal-count app) 0)
@@ -1076,13 +1082,17 @@ window-to-top-by-param or window-by-param."))
(:documentation "Set CLOG-GUI-WINDOW as focused window."))
(defmethod window-focus ((obj clog-gui-window))
- (let ((app (connection-data-item obj "clog-gui")))
- (unless (keep-on-top obj)
- (when (last-z app)
- (setf (z-index obj) (incf (last-z app)))))
- (when (window-select app)
- (setf (selectedp (window-select-item obj)) t))
- (fire-on-window-change obj app))
+ (let ((app (connection-data-item obj "clog-gui"))
+ (pop (connection-data-item obj "clog-popup")))
+ (when app
+ (unless (keep-on-top obj)
+ (when (last-z app)
+ (setf (z-index obj) (incf (last-z app)))))
+ (when (window-select app)
+ (setf (selectedp (window-select-item obj)) t))
+ (when pop
+ (focus pop))
+ (fire-on-window-change obj app)))
obj)
;;;;;;;;;;;;;;;;;;
@@ -1105,6 +1115,24 @@ the browser."))
(fire-on-window-close obj)))
nil)
+;;;;;;;;;;;;;;;;;;;;
+;; window-valid-p ;;
+;;;;;;;;;;;;;;;;;;;;
+
+(defun window-valid-p (obj)
+ "Returns t if is a valid clog-gui-window. An invalid state
+can occur when a popup slave desktop is closed by the OS or the window has
+been previously closed. If the obj exists in the internal hash of windows
+it is removed."
+ (when obj
+ (when (typep obj 'clog-gui-window)
+ (let* ((app (connection-data-item obj "clog-gui"))
+ (win (when app
+ (gethash (html-id obj) (windows app)))))
+ (when win
+ (when (connection-data-item win "clog-gui")
+ obj))))))
+
;;;;;;;;;;;;;;;;;;;;;;;;
;; window-maximized-p ;;
;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1135,15 +1163,19 @@ the browser."))
(setf (last-y obj) (top obj))
(setf (last-height obj) (height obj))
(setf (last-width obj) (width obj)))
- (setf (top obj) (unit :px (menu-bar-height obj)))
+ (cond ((connection-data-item obj "clog-popup")
+ (setf (top obj) (unit :px 0))
+ (setf (height obj) (inner-height (window (connection-body obj)))))
+ (t
+ (setf (top obj) (unit :px (menu-bar-height obj)))
+ (setf (height obj)
+ (- (inner-height (window (connection-body obj))) (menu-bar-height obj)))))
(setf (left obj) (unit :px 0))
(setf (width obj) (unit :vw 100))
(setf (left obj) (unit :px (body-left-offset app)))
(setf (width obj) (- (width obj)
(body-left-offset app)
(body-right-offset app)))
- (setf (height obj)
- (- (inner-height (window (body app))) (menu-bar-height obj)))
(fire-on-window-size-done obj)))))
;;;;;;;;;;;;;;;;;;;;;;
@@ -1247,7 +1279,7 @@ interactions. Use window-end-modal to undo."))
(let ((app (connection-data-item obj "clog-gui")))
(when (and app
(<= (modal-count app) 0))
- (setf (modal-background app) (create-div (body app) :class "w3-overlay"))
+ (setf (modal-background app) (create-div (connection-body obj) :class "w3-overlay"))
(setf (display (modal-background app)) :block))
(incf (modal-count app))
(setf (keep-on-top obj) t)
@@ -1780,8 +1812,8 @@ Calls on-input with t if confirmed or nil if canceled."
(time-out nil)
(left nil) (top nil)
(width 400) (height 500)
-
-
+
+
(size 40) (rows 4)
(client-movement nil)
(html-id nil))
diff --git a/tools/clog-builder-files.lisp b/tools/clog-builder-files.lisp
index 52ca49c..10daccd 100644
--- a/tools/clog-builder-files.lisp
+++ b/tools/clog-builder-files.lisp
@@ -32,15 +32,27 @@
(defun on-open-file-ext (obj &key open-file popup)
(if (and *open-external-with-emacs* open-file)
(swank:ed-in-emacs open-file)
- (open-window (window (connection-body obj))
- (if open-file
- (format nil "/source-editor?open-file=~A"
- open-file)
- "/source-editor?open-file=%20")
- :specs (if (or popup *open-external-in-popup*)
- "width=800,height=600"
- "")
- :name "_blank")))
+ (if *open-external-using-clog-popups*
+ (let ((pop (open-clog-popup obj
+ :specs (if (or popup *open-external-source-in-popup*)
+ "width=640,height=480"
+ "")
+ :name "_blank")))
+ (if pop
+ (let ((app (connection-data-item obj "builder-app-data")))
+ (setf (connection-data-item pop "builder-app-data") app)
+ (clog-gui-initialize pop :parent-desktop-obj obj)
+ (on-open-file pop :open-file open-file :maximized t))
+ (on-open-file obj :open-file open-file)))
+ (open-window (window (connection-body obj))
+ (if open-file
+ (format nil "/source-editor?open-file=~A"
+ open-file)
+ "/source-editor?open-file=%20")
+ :specs (if (or popup *open-external-source-in-popup*)
+ "width=800,height=600"
+ "")
+ :name "_blank"))))
(defun on-open-file (obj &key open-file
(title "New Source Editor")
@@ -299,8 +311,8 @@
(set-on-click m-ntab (lambda (obj)
(when is-dirty
(save obj nil))
- (on-open-file-ext obj :open-file file-name)
- (window-close win)))
+ (window-close win)
+ (on-open-file-ext obj :open-file file-name)))
(set-on-window-can-close win
(lambda (obj)
(cond (is-dirty
diff --git a/tools/clog-builder-settings.lisp b/tools/clog-builder-settings.lisp
index 6f1113e..d2debd0 100644
--- a/tools/clog-builder-settings.lisp
+++ b/tools/clog-builder-settings.lisp
@@ -12,8 +12,10 @@
;; Open panels and files in new browser tabs by default
(defparameter *open-external* nil)
+;; Use clog-popup and extend desktop to popups
+(defparameter *open-external-using-clog-popups* nil)
;; Open files in browser popups instead of tabs if browser allows
-(defparameter *open-external-in-popup* nil)
+(defparameter *open-external-source-in-popup* nil)
;; Open panel editors in browser popus instead of tabs if browser allows
(defparameter *open-external-panels-in-popup* nil)
;; Open panels as popups by default
diff --git a/tools/preferences.lisp.sample b/tools/preferences.lisp.sample
index 5439fed..da0ee73 100644
--- a/tools/preferences.lisp.sample
+++ b/tools/preferences.lisp.sample
@@ -5,10 +5,12 @@
;; Preferences loaded on next call to clog-tools:clog-builder or [Eval All]
+;; Builder Desktop
+
;; Open panels and files in new browser tabs by default
(setf *open-external* nil)
-;; Open files in browser popups instead of tabs if browser allows
-(setf *open-external-in-popup* nil)
+;; Use clog-popup and extend desktop to popups
+(setf *open-external-using-clog-popups* nil)
;; CLOG Panels
@@ -19,6 +21,8 @@
;; CLOG Source Editor
+;; Open files in browser popups instead of tabs if browser allows
+(setf *open-external-source-in-popup* nil)
;; Use console for evals instead of capture
(setf *editor-use-console-for-evals* nil)
;; Use emacs instead of the source-editor when opening external