(provide 'workspace-grid)
(require 'sawfish.wm.workspace)

;; ================================================================
;; Workspace Grid

;; Provides an virtual desktop "grid" abstraction, using workspaces.

;; In effect, this emulates viewports with workspaces

;; ================================================================



;; ================================================================
;; Custom Variables

;; Eventually these should be read from gnome2's workspace switcher panel
;; applet.
(defcustom num-workspace-rows 1
  "Number of rows (or columns) in the workspace switcher"
  :group workspace
  :type number
  :range (1 . nil))

(defcustom workspace-switcher-orientation 'horizontal
  "Orientation of panel with workspace switcher"
    :type (choice horizontal vertical)
    :group workspace)



;; ================================================================
;; Commands
(defun view-workspace-down
  "View the workspace below the current workspace"
  (interactive)
  (if (eq workspace-switcher-orientation 'horizontal)
      (view-workspace-next-row 1)
    (view-workspace-next-column 1)))

(defun view-workspace-up
  "View the workspace above the current workspace"
  (interactive)
  (if (eq workspace-switcher-orientation 'horizontal)
      (view-workspace-next-row -1)
    (view-workspace-next-column -1)))

(defun view-workspace-left
  "View the workspace to the left of the current workspace"
  (interactive)
  (if (eq workspace-switcher-orientation 'horizontal)
      (view-workspace-next-column -1)
    (view-workspace-next-row -1)))

(defun view-workspace-right
  "View the workspace to the right of the current workspace"
  (interactive)
  (if (eq workspace-switcher-orientation 'horizontal)
      (view-workspace-next-column 1)
    (view-workspace-next-row 1)))



;; ================================================================
;; Private Procedures

;; The workspace-switcher makes a desktop grid by splitting a sequence of
;; workspaces into rows and columns.

;; With a horizontal panel, workspaces line up as
;;    1 2 3
;;    4 5 6
;; but with a vertical panel, they line up as
;;    1 4
;;    2 5
;;    3 6

;; Since we want users to be able to use "up", "down", "left", "right",
;; etc. commands that work no matter the panel's orientation, we have to
;; translate the commands.

;; The following procedures operate on the workspace grid as if it had a
;; horizontal orientation.  Thus, consecutive "columns" have consecutive
;; workspaces, and each "row" consists of a sequence of such consecutive
;; workspaces.  The translation to "up" "down" etc. coordinates is done by the
;; callers.

(defun num-workspaces ()
  (let ((limits (workspace-limits)))
    (- (cdr limits) (car limits) -1)))

(defun num-workspaces-per-row ()
  (quotient (num-workspaces)
	    num-workspace-rows))

(defun workspace-coordinates (workspace)
  "Returns zero-based (column . row) coordinates of `workspace' in pager."
  (let ((normalized-workspace-index (- workspace (car (workspace-limits))))
	(row-size (num-workspaces-per-row)))
    (cons (modulo normalized-workspace-index row-size)
	  (quotient normalized-workspace-index row-size))))


(defun view-workspace-next-row (distance)
  "Move the current workspace `distance' rows to down"
  (let ((new-workspace-number
	 (+ current-workspace (* distance (num-workspaces-per-row)))))

    (when (and (<= new-workspace-number (cdr (workspace-limits)))
	       (>= new-workspace-number (car (workspace-limits))))
      (select-workspace-from-first new-workspace-number))))


(defun view-workspace-next-column (distance)
  "Move the current workspace `distance' columns to the right"
  (let* ((new-column
	  (+ distance (car (workspace-coordinates current-workspace)))))

    (when (and (>= new-column 0)
	       (< new-column (num-workspaces-per-row)))
      (select-workspace (+ distance current-workspace)))))


