Skip to content

Commit

Permalink
switch to es6 module syntax, and make Workspace and Window into funct…
Browse files Browse the repository at this point in the history
…ion collections (instead of classes)
  • Loading branch information
chee committed Dec 10, 2016
1 parent 6d76179 commit 3082655
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 109 deletions.
116 changes: 60 additions & 56 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
const util = require('util')
import {dirname} from 'path'
import {exec} from 'child_process'
import events from 'events'
import x11 from 'x11'
import EWMH from 'ewmh'

const path = require('path')
const exec = require('child_process').exec
const events = require('events')
const x11 = require('x11')
const EWMH = require('ewmh')
import {stringToKeys} from './util'
import keys from './lib/keys'
import * as Workspace from './workspace'
import * as Window from './window'
import listen from './srv'

const keys = require('./lib/keys')
const {stringToKeys, or} = require('./util')
const Workspace = require('./workspace')
const Window = require('./window')

const eventEmitter = new events.EventEmitter
const commandQueue = new events.EventEmitter

const name = 'wm'
const configuration = require('rc')(name)

// todo:
const keybindings = (() => {
const keybindings = []
for (const binding in configuration.keybindings) {
Expand All @@ -29,14 +29,14 @@ const keybindings = (() => {
const ASYNC = 1
const NOPE = 0

process.env.PATH = `${path.dirname(process.argv[1])}/bin:${process.env.PATH}`
process.env.PATH = `${dirname(process.argv[1])}/bin:${process.env.PATH}`

let attributes
let child
let start
let X
let workspaces
let currentWorkspace
let currentWindow = null
let workspace = null
let screen
let root
let ewmh
Expand Down Expand Up @@ -65,8 +65,12 @@ function grabButtons(X) {
}

// todo: make this size configurable
function makeWorkspaces(screen, size) {
return Array.from(Array(size), () => new Workspace(screen))
function makeWorkspaces(size) {
const workspaces = []
for (let id = 0; id < size; id++) {
workspaces.push(Workspace.create(id))
}
return workspaces
}

function createClient() {
Expand All @@ -76,20 +80,22 @@ function createClient() {
X = global.X = display.client
ewmh = new EWMH(X, root)

ewmh.on('CurrentDesktop', desktop => exec(`notify-send "workspace switch ${desktop}"`))
ewmh.on('Desktop', desktop => exec(`notify-send "workspace switch ${desktop}"`))

grabKeys(X, keybindings)
grabButtons(X)

workspaces = makeWorkspaces(screen, 5)
currentWorkspace = workspaces[0]
workspaces = makeWorkspaces(5)
workspace = workspaces[0]

ewmh.set_number_of_desktops(5, error => {
if (error) exec(`notify-send "${error}"`)
ewmh.set_current_desktop(0)
})
}).on('event', event => {
child = event.child
// todo: put all these event handlers in functions
// todo: it will fix the duplicate decls and be neater
// todo: perhaps emit each of these events from another emitter
switch(event.name) {
case 'KeyPress':
keybindings.forEach(binding => {
Expand All @@ -101,10 +107,10 @@ function createClient() {
case 'ButtonPress':
child = event.child
X.RaiseWindow(child)
currentWindow = new Window(child)
currentWindow.focus()
if (!currentWorkspace.contains(child)) {
currentWorkspace.addWindow(child)
workspace.currentWindow = Window.create(child)
Window.focus(workspace.currentWindow)
if (!Workspace.contains(workspace, workspace.currentWindow)) {
Workspace.addWindow(workspace, workspace.currentWindow)
}
X.GetGeometry(child, (error, attr) => {
start = event
Expand All @@ -130,7 +136,7 @@ function createClient() {
start = null
break
case 'MapRequest':
X.GetWindowAttributes(event.window, (error, attributes) => {
X.GetWindowAttributes(event.wid, (error, attributes) => {
if (error) return console.error(error)
if (attributes[8]) {
return X.MapWindow(event.wid)
Expand All @@ -140,17 +146,14 @@ function createClient() {
event.wid,
{eventMask: x11.eventMask.EnterWindow}
)
currentWorkspace.addWindow(event.wid)
let window = Window.create(event.wid)
Workspace.addWindow(workspace, window)
break
case 'FocusIn':
case 'EnterNotify':
child = event.wid
currentWindow = new Window(child)
currentWindow.focus()
if (!currentWorkspace.contains(child)) {
workspaces.forEach(workspace => workspace.removeWindow(currentWindow.id))
currentWorkspace.addWindow(child)
}
workspace.currentWindow = Window.create(child)
Window.focus(workspace.currentWindow)
break
case 'ConfigureRequest':
child = event.wid
Expand All @@ -171,16 +174,16 @@ function createClient() {
}

// commands
eventEmitter.on('cmd', cmd => {
commandQueue.on('cmd', cmd => {
let match = cmd.match(/workspace\s+(\w+)\s+(\d+)/)

if (match) {
switch (match[1]) {
case 'switch':
// todo: make this start showing the new windows before hiding the old ones
workspaces.forEach(workspace => workspace.hide())
currentWorkspace = workspaces[match[2] - 1]
currentWorkspace.show()
workspaces.forEach(workspace => Workspace.hide(workspace))
workspace = workspaces[match[2] - 1]
Workspace.show(workspace, root)
ewmh.set_current_desktop(match[2] - 1)
break
}
Expand All @@ -191,48 +194,49 @@ eventEmitter.on('cmd', cmd => {
if (match) {
switch (match[1]) {
case 'destroy':
currentWindow.kill()
// workspace.currentWindow?
break
case 'move':
workspaces.forEach(workspace => workspace.removeWindow(currentWindow.id))
workspaces[match[2] - 1].addWindow(currentWindow.id)
currentWindow.hide()
currentWorkspace.show()
// todo: remove only from current workspace?
workspaces.forEach(workspace => Workspace.removeWindow(workspace, workspace.currentWindow))
Workspace.addWindow(workspaces[match[2] - 1], currentWindow)
Window.hide(currentWindow)
workspace.currentWindow = null
Workspace.show(workspace)
break
case 'tile':
switch (match[2]) {
case 'left':
X.ResizeWindow(currentWindow.id, screen.pixel_width / 2, screen.pixel_height)
X.MoveWindow(currentWindow.id, 0, 0)
X.ResizeWindow(workspace.currentWindow.id, screen.pixel_width / 2, screen.pixel_height)
X.MoveWindow(workspace.currentWindow.id, 0, 0)
break
case 'right':
X.ResizeWindow(currentWindow.id, screen.pixel_width / 2, screen.pixel_height)
X.MoveWindow(currentWindow.id, screen.pixel_width / 2, 0)
X.ResizeWindow(workspace.currentWindow.id, screen.pixel_width / 2, screen.pixel_height)
X.MoveWindow(workspace.currentWindow.id, screen.pixel_width / 2, 0)
break
case 'full':
X.ResizeWindow(currentWindow.id, screen.pixel_width, screen.pixel_height)
X.MoveWindow(currentWindow.id, 0, 0)
X.ResizeWindow(workspace.currentWindow.id, screen.pixel_width, screen.pixel_height)
X.MoveWindow(workspace.currentWindow.id, 0, 0)
}
}
}
// todo: make this just reload instead of killing the client
match = cmd.match(/^reload$/)
if (match) {
workspaces.forEach(workspace => workspace.hide())
currentWorkspace = workspaces[0]
currentWorkspace.show()
workspaces.forEach(workspace => Workspace.hide(workspace))
const home = workspace = workspaces[0]
Workspace.show(home)
ewmh.set_current_desktop(0)
workspaces.forEach(workspace => {
workspace.windows.forEach(window => {
workspace.removeWindow(window.id)
currentWorkspace.addWindow(window.id)
Workspace.removeWindow(workspace, window)
Workspace.addWindow(home,window)
})
})
X.KillClient()
createClient()
eventEmitter.emit('die')
require('./srv')(eventEmitter)
}
})

require('./srv')(eventEmitter)
listen(commandQueue)
createClient()
2 changes: 1 addition & 1 deletion srv.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const fs = require('fs')
const net = require('net')

var path = '/tmp/wm'
var path = process.env.XEPHYR ? '/tmp/wm.xephyr' : '/tmp/wm'

module.exports = eventEmitter => {
fs.unlink(path, () => {
Expand Down
44 changes: 21 additions & 23 deletions window.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
module.exports = class {
constructor(id, parent, screen) {
this.id = id
this.parent = parent
this.screen = screen
}
const create = id => ({
id,
workspace: null,
shown: false,
focused: false
})

show() {
global.X.MapWindow(this.id)
}

hide() {
global.X.UnmapWindow(this.id)
}

focus() {
global.X.SetInputFocus(this.id)
}
const show = window => {
global.X.MapWindow(window.id)
window.shown = true
}

kill() {
global.X.DestroyWindow(this.id)
}
const hide = window => {
global.X.UnmapWindow(window.id)
window.shown = false
}

exec(callback) {
callback(this)
}
const focus = window => {
global.X.SetInputFocus(window.id)
// todo: how does this get unset
// is it even the job of the window to maintain this?
window.focused = true
}

export {create, show, hide, focus}
65 changes: 36 additions & 29 deletions workspace.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
const Window = require('./window')
import * as Window from './window'

module.exports = class {
constructor(screen) {
this.screen = screen
this.root = screen.root
this.focused = null
this.windows = []
}
const create = id => ({
id,
windows: [],
currentWindow: null
})

addWindow(id) {
const window = new Window(id)
this.windows.push(window)
window.show()
// todo: maybe this should always take only ever a window
const addWindow = (workspace, window) => {
if (!window) return
if (typeof window == 'number') {
window = Window.create(window)
}
workspace.windows.push(window)
Window.show(window)
}

removeWindow(id) {
this.windows = this.windows.filter(window => window.id != id)
}
const removeWindow = (workspace, window) => {
if (!window) return
const {id} = window
workspace.windows = workspace.windows.filter(window => window.id != id)
}

show() {
if (this.focused) {
this.focused.focus()
} else {
global.X.SetInputFocus(this.root)
}
this.windows.forEach(window => window.show())
}
// todo: should root be a global?
// todo: should root be a *window*?
// todo: this root argument definitely doesn't belong here
const show = (workspace, root) => {
workspace.currentWindow
? Window.focus(workspace.currentWindow)
: global.X.SetInputFocus(root)
workspace.windows.forEach(Window.show)
}

hide() {
this.windows.forEach(window => window.hide())
}
const hide = workspace => {
workspace.windows.forEach(Window.hide)
}

contains(id) {
return this.windows.some(window => window.id == id)
}
const contains = (workspace, window) => {
const {id} = window
return workspace.windows.some(window => window.id == id)
}

export {create, addWindow, removeWindow, show, hide, contains}

0 comments on commit 3082655

Please sign in to comment.