├── LICENSE ├── README.md ├── tinywm-session ├── tinywm.desktop └── tinywm.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Collin Glass 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyWM 2 | 3 | Port of TinyWM in Go. 4 | 5 | ## Usage 6 | 7 | Make sure libx11-dev is installed 8 | 9 | ``` 10 | $ sudo apt-get install libx11-dev 11 | ``` 12 | 13 | Add the ```.desktop``` file to the xsessions directory. This will add a new selection to the list of window managers at the login screen. 14 | 15 | ``` 16 | $ sudo cp tinywm.desktop /usr/share/xsessions/ 17 | ``` 18 | 19 | This file runs /usr/bin/tinywm-session. Create that file now. 20 | 21 | ``` 22 | $ sudo cp tinywm-session /usr/bin/ 23 | $ sudo chmod a+x /usr/bin/tinywm-session 24 | ``` 25 | 26 | tinwm-session preloads a terminal and then runs the go binary. Build the binary and move it to /usr/bin/. 27 | 28 | ``` 29 | $ go build 30 | $ sudo mv tinywm /usr/bin/ 31 | $ sudo chmod a+x /usr/bin/tinywm 32 | ``` 33 | 34 | Log out. You should now see tinywm as an option in the list. Choose it a log in. You should have a bare WM with a terminal emulator running. 35 | 36 | ## Development 37 | 38 | Issues and PR's are welcome! :) Feel free to hit me on twitter @collinglass. 39 | -------------------------------------------------------------------------------- /tinywm-session: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | xsetroot -solid "#000000" 3 | xrdb -load $HOME/.Xdefaults 4 | x-terminal-emulator 5 | x-terminal-emulator 6 | exec /usr/bin/tinywm -------------------------------------------------------------------------------- /tinywm.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=TinyWM 4 | Comment=A tiny window manager 5 | Exec=tinywm-session 6 | Terminal=False 7 | TryExec=tinywm 8 | Type=Application 9 | 10 | [Window Manager] 11 | SessionManaged=true -------------------------------------------------------------------------------- /tinywm.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #cgo LDFLAGS: -lX11 5 | #include 6 | 7 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 8 | */ 9 | import "C" 10 | import ( 11 | "bytes" 12 | "encoding/binary" 13 | "unsafe" 14 | ) 15 | 16 | func unionToInt(cbytes [192]byte) (result int) { 17 | buf := bytes.NewBuffer(cbytes[:]) 18 | var ptr uint64 19 | if err := binary.Read(buf, binary.LittleEndian, &ptr); err == nil { 20 | uptr := uintptr(ptr) 21 | return *(*int)(unsafe.Pointer(uptr)) 22 | } 23 | return 0 24 | } 25 | 26 | func unionToXKeyEvent(cbytes [192]byte) (result *C.XKeyEvent) { 27 | buf := bytes.NewBuffer(cbytes[:]) 28 | var ptr uint64 29 | if err := binary.Read(buf, binary.LittleEndian, &ptr); err == nil { 30 | uptr := uintptr(ptr) 31 | return (*C.XKeyEvent)(unsafe.Pointer(uptr)) 32 | } 33 | return nil 34 | } 35 | 36 | func unionToXButtonEvent(cbytes [192]byte) (result *C.XButtonEvent) { 37 | buf := bytes.NewBuffer(cbytes[:]) 38 | var ptr uint64 39 | if err := binary.Read(buf, binary.LittleEndian, &ptr); err == nil { 40 | uptr := uintptr(ptr) 41 | return (*C.XButtonEvent)(unsafe.Pointer(uptr)) 42 | } 43 | return nil 44 | } 45 | 46 | func main() { 47 | var dpy *C.Display 48 | var attr C.XWindowAttributes 49 | var start C.XButtonEvent 50 | var ev C.XEvent 51 | var ch *C.char 52 | 53 | if dpy != C.XOpenDisplay(ch) { 54 | return 55 | } 56 | 57 | C.XGrabKey( 58 | dpy, 59 | C.int(C.XKeysymToKeycode(dpy, C.XStringToKeysym(C.CString("F1")))), 60 | C.Mod1Mask, 61 | C.XDefaultRootWindow(dpy), 62 | 1, 63 | C.GrabModeAsync, 64 | C.GrabModeAsync, 65 | ) 66 | 67 | C.XGrabButton( 68 | dpy, 69 | 1, 70 | C.Mod1Mask, 71 | C.XDefaultRootWindow(dpy), 72 | 1, 73 | C.ButtonPressMask|C.ButtonReleaseMask|C.PointerMotionMask, 74 | C.GrabModeAsync, 75 | C.GrabModeAsync, 76 | C.None, 77 | C.None, 78 | ) 79 | 80 | C.XGrabButton( 81 | dpy, 82 | 3, 83 | C.Mod1Mask, 84 | C.XDefaultRootWindow(dpy), 85 | 1, 86 | C.ButtonPressMask|C.ButtonReleaseMask|C.PointerMotionMask, 87 | C.GrabModeAsync, 88 | C.GrabModeAsync, 89 | C.None, 90 | C.None, 91 | ) 92 | 93 | start.subwindow = C.None 94 | 95 | for { 96 | C.XNextEvent(dpy, &ev) 97 | if unionToInt(ev) == C.KeyPress && unionToXKeyEvent(ev).subwindow != C.None { 98 | C.XRaiseWindow(dpy, unionToXKeyEvent(ev).subwindow) 99 | } else if unionToInt(ev) == C.ButtonPress && unionToXButtonEvent(ev).subwindow != C.None { 100 | C.XGetWindowAttributes(dpy, unionToXButtonEvent(ev).subwindow, &attr) 101 | start = *unionToXButtonEvent(ev) 102 | } else if unionToInt(ev) == C.MotionNotify && start.subwindow != C.None { 103 | xdiff := unionToXButtonEvent(ev).x_root - start.x_root 104 | ydiff := unionToXButtonEvent(ev).y_root - start.y_root 105 | 106 | var toDiffX C.int 107 | var toDiffY C.int 108 | 109 | if start.button == 1 { 110 | toDiffX = xdiff 111 | toDiffY = ydiff 112 | } 113 | 114 | var toWidth C.int 115 | var toHeight C.int 116 | 117 | if start.button == 3 { 118 | toWidth = xdiff 119 | toHeight = ydiff 120 | } 121 | 122 | C.XMoveResizeWindow( 123 | dpy, 124 | start.subwindow, 125 | attr.x+toDiffX, 126 | attr.y+toDiffY, 127 | max(1, attr.width+toWidth), 128 | max(1, attr.height+toHeight)) 129 | } else if unionToInt(ev) == C.ButtonRelease { 130 | start.subwindow = C.None 131 | } 132 | } 133 | } 134 | 135 | func max(a, b C.int) C.uint { 136 | if a > b { 137 | return C.uint(a) 138 | } 139 | 140 | return C.uint(b) 141 | } 142 | --------------------------------------------------------------------------------