Browse code

Finish resize implementation client and server

Guillaume J. Charmes authored on 2013/05/25 06:44:16
Showing 3 changed files
... ...
@@ -35,19 +35,6 @@ var (
35 35
 func ParseCommands(args ...string) error {
36 36
 	cli := NewDockerCli("0.0.0.0", 4243)
37 37
 
38
-	c := make(chan os.Signal, 1)
39
-	signal.Notify(c, syscall.SIGWINCH)
40
-	go func() {
41
-		for sig := range c {
42
-			if sig == syscall.SIGWINCH {
43
-				_, _, err := cli.call("GET", "/auth", nil)
44
-				if err != nil {
45
-					utils.Debugf("Error resize: %s", err)
46
-				}
47
-			}
48
-		}
49
-	}()
50
-
51 38
 	if len(args) > 0 {
52 39
 		methodName := "Cmd" + strings.ToUpper(args[0][:1]) + strings.ToLower(args[0][1:])
53 40
 		method, exists := reflect.TypeOf(cli).MethodByName(methodName)
... ...
@@ -975,6 +962,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
975 975
 	v.Set("stderr", "1")
976 976
 	v.Set("stdin", "1")
977 977
 
978
+	cli.monitorTtySize(cmd.Arg(0))
978 979
 	if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty); err != nil {
979 980
 		return err
980 981
 	}
... ...
@@ -1162,6 +1150,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1162 1162
 	}
1163 1163
 
1164 1164
 	if config.AttachStdin || config.AttachStdout || config.AttachStderr {
1165
+		cli.monitorTtySize(out.Id)
1165 1166
 		if err := cli.hijack("POST", "/containers/"+out.Id+"/attach?"+v.Encode(), config.Tty); err != nil {
1166 1167
 			return err
1167 1168
 		}
... ...
@@ -1295,6 +1284,33 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool) error {
1295 1295
 
1296 1296
 }
1297 1297
 
1298
+func (cli *DockerCli) resizeTty(id string) {
1299
+	ws, err := term.GetWinsize(os.Stdin.Fd())
1300
+	if err != nil {
1301
+		utils.Debugf("Error getting size: %s", err)
1302
+	}
1303
+	v := url.Values{}
1304
+	v.Set("h", strconv.Itoa(int(ws.Height)))
1305
+	v.Set("w", strconv.Itoa(int(ws.Width)))
1306
+	if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil {
1307
+		utils.Debugf("Error resize: %s", err)
1308
+	}
1309
+}
1310
+
1311
+func (cli *DockerCli) monitorTtySize(id string) {
1312
+	cli.resizeTty(id)
1313
+
1314
+	c := make(chan os.Signal, 1)
1315
+	signal.Notify(c, syscall.SIGWINCH)
1316
+	go func() {
1317
+		for sig := range c {
1318
+			if sig == syscall.SIGWINCH {
1319
+				cli.resizeTty(id)
1320
+			}
1321
+		}
1322
+	}()
1323
+}
1324
+
1298 1325
 func Subcmd(name, signature, description string) *flag.FlagSet {
1299 1326
 	flags := flag.NewFlagSet(name, flag.ContinueOnError)
1300 1327
 	flags.Usage = func() {
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"flag"
6 6
 	"fmt"
7
+	"github.com/dotcloud/docker/term"
7 8
 	"github.com/dotcloud/docker/utils"
8 9
 	"github.com/kr/pty"
9 10
 	"io"
... ...
@@ -755,7 +756,11 @@ func (container *Container) Wait() int {
755 755
 }
756 756
 
757 757
 func (container *Container) Resize(h, w int) error {
758
-	return fmt.Errorf("Resize not yet implemented")
758
+	pty, ok := container.ptyMaster.(*os.File)
759
+	if !ok {
760
+		return fmt.Errorf("ptyMaster does not have Fd() method")
761
+	}
762
+	return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
759 763
 }
760 764
 
761 765
 func (container *Container) ExportRw() (Archive, error) {
... ...
@@ -1,6 +1,7 @@
1 1
 package term
2 2
 
3 3
 import (
4
+	"github.com/dotcloud/docker/utils"
4 5
 	"os"
5 6
 	"os/signal"
6 7
 	"syscall"
... ...
@@ -109,17 +110,35 @@ type State struct {
109 109
 	termios Termios
110 110
 }
111 111
 
112
+type Winsize struct {
113
+	Width  uint16
114
+	Height uint16
115
+	x      uint16
116
+	y      uint16
117
+}
118
+
119
+func GetWinsize(fd uintptr) (*Winsize, error) {
120
+	ws := &Winsize{}
121
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws)))
122
+	return ws, err
123
+}
124
+
125
+func SetWinsize(fd uintptr, ws *Winsize) error {
126
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
127
+	return err
128
+}
129
+
112 130
 // IsTerminal returns true if the given file descriptor is a terminal.
113 131
 func IsTerminal(fd int) bool {
114 132
 	var termios Termios
115
-	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
133
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
116 134
 	return err == 0
117 135
 }
118 136
 
119 137
 // Restore restores the terminal connected to the given file descriptor to a
120 138
 // previous state.
121 139
 func Restore(fd int, state *State) error {
122
-	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
140
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
123 141
 	return err
124 142
 }
125 143