func TestWebView_URI(t *testing.T) {
	setup()
	defer teardown()

	mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {})

	wantURI := server.URL + "/"
	var gotURI string
	webView.Connect("notify::uri", func() {
		glib.IdleAdd(func() bool {
			gotURI = webView.URI()
			if gotURI != "" {
				gtk.MainQuit()
			}
			return false
		})
	})

	glib.IdleAdd(func() bool {
		webView.LoadURI(server.URL)
		return false
	})

	gtk.Main()

	if wantURI != gotURI {
		t.Errorf("want URI %q, got %q", wantURI, gotURI)
	}
}
Beispiel #2
0
// EvaluateJavaScript runs the JavaScript in script in the view's context and
// returns the script's result as a Go value.
func (v *View) EvaluateJavaScript(script string) (result interface{}, err error) {
	resultChan := make(chan interface{}, 1)
	errChan := make(chan error, 1)

	glib.IdleAdd(func() bool {
		v.WebView.RunJavaScript(script, func(result *gojs.Value, err error) {
			glib.IdleAdd(func() bool {
				if err == nil {
					goval, err := result.GoValue()
					if err != nil {
						errChan <- err
						return false
					}
					resultChan <- goval
				} else {
					errChan <- err
				}
				return false
			})
		})
		return false
	})

	select {
	case result = <-resultChan:
		return result, nil
	case err = <-errChan:
		return nil, err
	}
}
func TestWebView_Title(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	wantTitle := "foo"
	var gotTitle string
	webView.Connect("notify::title", func() {
		glib.IdleAdd(func() bool {
			gotTitle = webView.Title()
			if gotTitle != "" {
				gtk.MainQuit()
			}
			return false
		})
	})

	glib.IdleAdd(func() bool {
		webView.LoadHTML("<html><head><title>"+wantTitle+"</title></head><body></body></html>", "")
		return false
	})

	gtk.Main()

	if wantTitle != gotTitle {
		t.Errorf("want title %q, got %q", wantTitle, gotTitle)
	}
}
Beispiel #4
0
// txSenderAndReplyListener triggers btcgui to send btcwallet a JSON
// request to create and send a transaction.  If sending the transaction
// succeeds, the recipients in the send coins notebook tab are cleared.
// If the transaction fails because the wallet is not unlocked, the
// unlock dialog is shown, and after a successful unlock, creating and
// sending the tx is tried a second time.
//
// This is written to be run as a goroutine executing outside of the GTK
// main event loop.
func txSenderAndReplyListener(sendTo map[string]float64) {
	triggers.sendTx <- sendTo

	err := <-triggerReplies.sendTx
	// -13 is the error code for needing an unlocked wallet.
	if jsonErr, ok := err.(*btcjson.Error); ok {
		switch jsonErr.Code {
		case -13:
			// Wallet must be unlocked first.  Show unlock dialog.
			glib.IdleAdd(func() {
				unlockSuccessful := make(chan bool)
				go func() {
					for {
						success, ok := <-unlockSuccessful
						if !ok {
							// A closed channel indicates
							// the dialog was cancelled.
							// Abort sending the transaction.
							return
						}
						if success {
							// Try send again.
							go txSenderAndReplyListener(sendTo)
							return
						}
					}
				}()
				d, err := createUnlockDialog(unlockForTxSend, unlockSuccessful)
				if err != nil {
					// TODO(jrick): log error to file
					log.Printf("[ERR] could not create unlock dialog: %v\n", err)
					return
				}
				d.Run()
				d.Destroy()
			})

		default:
			// Generic case to display an error.
			glib.IdleAdd(func() {
				d := errorDialog("Unable to send transaction",
					fmt.Sprintf("%s\nError code: %d", jsonErr.Message, jsonErr.Code))
				d.Run()
				d.Destroy()
			})
		}
		return
	}

	// Send was successful, so clear recipient widgets.
	glib.IdleAdd(resetRecipients)
}
Beispiel #5
0
func main() {
	gtk.Init(nil)

	win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	if err != nil {
		log.Fatal("Unable to create window:", err)
	}
	win.Connect("destroy", func() {
		gtk.MainQuit()
	})

	win.Add(windowWidget())

	// Native GTK is not thread safe, and thus, gotk3's GTK bindings may not
	// be used from other goroutines.  Instead, glib.IdleAdd() must be used
	// to add a function to run in the GTK main loop when it is in an idle
	// state.
	//
	// Two examples of using glib.IdleAdd() are shown below.  The first runs
	// a user created function, LabelSetTextIdle, and passes it two
	// arguments for a label and the text to set it with.  The second calls
	// (*gtk.Label).SetText directly, passing in only the text as an
	// argument.
	//
	// If the function passed to glib.IdleAdd() returns one argument, and
	// that argument is a bool, this return value will be used in the same
	// manner as a native g_idle_add() call.  If this return value is false,
	// the function will be removed from executing in the GTK main loop's
	// idle state.  If the return value is true, the function will continue
	// to execute when the GTK main loop is in this state.
	go func() {
		for {
			time.Sleep(time.Second)
			s := fmt.Sprintf("Set a label %d time(s)!", nSets)
			_, err := glib.IdleAdd(LabelSetTextIdle, topLabel, s)
			if err != nil {
				log.Fatal("IdleAdd() failed:", err)
			}
			nSets++
			s = fmt.Sprintf("Set a label %d time(s)!", nSets)
			_, err = glib.IdleAdd(bottomLabel.SetText, s)
			if err != nil {
				log.Fatal("IdleAdd() failed:", err)
			}
			nSets++
		}
	}()

	win.ShowAll()
	gtk.Main()
}
Beispiel #6
0
// updateAddresses listens for new wallet addresses, updating the GUI when
// necessary.
func updateAddresses() {
	for {
		addrs := <-updateChans.addrs
		glib.IdleAdd(func() {
			RecvCoins.Store.Clear()
		})
		for i := range addrs {
			addr := addrs[i]
			glib.IdleAdd(func() {
				iter := RecvCoins.Store.Append()
				RecvCoins.Store.Set(iter, []int{1},
					[]interface{}{addr})
			})
		}
	}
}
Beispiel #7
0
// cmdGetAddressesByAccount requests all addresses for an account.
//
// TODO(jrick): support non-default accounts.
// TODO(jrick): stop throwing away errors.
func cmdGetAddressesByAccount(ws *websocket.Conn) {
	n := <-NewJSONID
	msg, err := btcjson.CreateMessageWithId("getaddressesbyaccount", n, "")
	if err != nil {
		updateChans.addrs <- []string{}
	}

	replyHandlers.Lock()
	replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) {
		if r, ok := result.([]interface{}); ok {
			addrs := []string{}
			for _, v := range r {
				addrs = append(addrs, v.(string))
			}
			updateChans.addrs <- addrs
		} else {
			if err.Code == btcjson.ErrWalletInvalidAccountName.Code {
				glib.IdleAdd(func() {
					if dialog, err := createNewWalletDialog(); err != nil {
						dialog.Run()
					}
				})
			}
			updateChans.addrs <- []string{}
		}
	}
	replyHandlers.Unlock()

	if err = websocket.Message.Send(ws, msg); err != nil {
		replyHandlers.Lock()
		delete(replyHandlers.m, n)
		replyHandlers.Unlock()
		updateChans.addrs <- []string{}
	}
}
func TestWebView_LoadURI_load_failed(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	loadFailed := false
	loadFinished := false
	webView.Connect("load-failed", func() {
		loadFailed = true
	})
	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			loadFinished = true
			gtk.MainQuit()
		}
	})

	glib.IdleAdd(func() bool {
		// Load a bad URL to trigger load failure.
		webView.LoadURI("http://127.0.0.1:99999")
		return false
	})

	gtk.Main()

	if !loadFailed {
		t.Error("!loadFailed")
	}
	if !loadFinished {
		t.Error("!loadFinished")
	}
}
func TestWebView_GetSnapshot(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			webView.GetSnapshot(func(img *image.RGBA, err error) {
				if err != nil {
					t.Errorf("GetSnapshot error: %q", err)
				}
				if img.Pix == nil {
					t.Error("!img.Pix")
				}
				if img.Stride == 0 || img.Rect.Max.X == 0 || img.Rect.Max.Y == 0 {
					t.Error("!img.Stride or !img.Rect.Max.X or !img.Rect.Max.Y")
				}
				gtk.MainQuit()
			})
		}
	})

	glib.IdleAdd(func() bool {
		webView.LoadHTML(`<p id=foo>abc</p>`, "")
		return false
	})

	gtk.Main()
}
func TestWebView_RunJavaScript_exception(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	wantErr := errors.New("An exception was raised in JavaScript")
	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			webView.RunJavaScript(`throw new Error("foo")`, func(result *gojs.Value, err error) {
				if result != nil {
					ctx := webView.JavaScriptGlobalContext()
					t.Errorf("want result == nil, got %q", ctx.ToStringOrDie(result))
				}
				if !reflect.DeepEqual(wantErr, err) {
					t.Errorf("want error %q, got %q", wantErr, err)
				}
				gtk.MainQuit()
			})
		}
	})

	glib.IdleAdd(func() bool {
		webView.LoadHTML(`<p></p>`, "")
		return false
	})

	gtk.Main()
}
func TestWebView_RunJavaScript(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	wantResultString := "abc"
	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			webView.RunJavaScript(`document.getElementById("foo").innerHTML`, func(result *gojs.Value, err error) {
				if err != nil {
					t.Errorf("RunJavaScript error: %s", err)
				}
				resultString := webView.JavaScriptGlobalContext().ToStringOrDie(result)
				if wantResultString != resultString {
					t.Errorf("want result string %q, got %q", wantResultString, resultString)
				}
				gtk.MainQuit()
			})
		}
	})

	glib.IdleAdd(func() bool {
		webView.LoadHTML(`<p id=foo>abc</p>`, "")
		return false
	})

	gtk.Main()
}
Beispiel #12
0
func (self *PopupMenu) downloadFile(msgId, url, ext string) {
	go func() {
		glib.IdleAdd(func() {
			NewFileChooserWindow(self.parent, msgId, url, ext).window.ShowAll()
		})
	}()
}
func TestWebView_LoadHTML(t *testing.T) {
	webView := NewWebView()
	defer webView.Destroy()

	loadOk := false
	webView.Connect("load-failed", func() {
		t.Errorf("load failed")
	})
	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			loadOk = true
			gtk.MainQuit()
		}
	})

	glib.IdleAdd(func() bool {
		webView.LoadHTML("<p>hello</p>", "")
		return false
	})

	gtk.Main()

	if !loadOk {
		t.Error("!loadOk")
	}
}
Beispiel #14
0
// NewView creates a new View in the context.
func (c *Context) NewView() *View {
	view := make(chan *View, 1)
	glib.IdleAdd(func() bool {
		webView := webkit2.NewWebView()
		settings := webView.Settings()
		settings.SetEnableWriteConsoleMessagesToStdout(true)
		settings.SetUserAgentWithApplicationDetails("WebLoop", "v1")
		v := &View{WebView: webView}
		loadChangedHandler, _ := webView.Connect("load-changed", func(_ *glib.Object, loadEvent webkit2.LoadEvent) {
			switch loadEvent {
			case webkit2.LoadFinished:
				// If we're here, then the load must not have failed, because
				// otherwise we would've disconnected this handler in the
				// load-failed signal handler.
				v.load <- struct{}{}
			}
		})
		webView.Connect("load-failed", func() {
			v.lastLoadErr = ErrLoadFailed
			webView.HandlerDisconnect(loadChangedHandler)
		})
		view <- v
		return false
	})
	return <-view
}
Beispiel #15
0
// updateConnectionState listens for connection status changes to btcd
// and btcwallet, updating the GUI when necessary.
func updateConnectionState() {
	// Statusbar messages for various connection states.
	btcdd := "Disconnected from btcd"
	btcwc := "Established connection to btcwallet"
	btcwd := "Disconnected from btcwallet.  Attempting reconnect..."

	for {
		select {
		case conn := <-updateChans.btcwalletConnected:
			if conn {
				glib.IdleAdd(func() {
					//MenuBar.Settings.New.SetSensitive(true)
					//MenuBar.Settings.Encrypt.SetSensitive(true)
					MenuBar.Settings.TxFee.SetSensitive(true)
					// Lock/Unlock sensitivity is set by wallet notification.
					RecvCoins.NewAddrBtn.SetSensitive(true)
					StatusElems.Lab.SetText(btcwc)
					StatusElems.Pb.Hide()
				})
			} else {
				glib.IdleAdd(func() {
					//MenuBar.Settings.New.SetSensitive(false)
					//MenuBar.Settings.Encrypt.SetSensitive(false)
					MenuBar.Settings.Lock.SetSensitive(false)
					MenuBar.Settings.Unlock.SetSensitive(false)
					MenuBar.Settings.TxFee.SetSensitive(false)
					SendCoins.SendBtn.SetSensitive(false)
					RecvCoins.NewAddrBtn.SetSensitive(false)
					StatusElems.Lab.SetText(btcwd)
					StatusElems.Pb.Hide()
				})
			}
		case conn := <-updateChans.btcdConnected:
			if conn {
				glib.IdleAdd(func() {
					SendCoins.SendBtn.SetSensitive(true)
				})
			} else {
				glib.IdleAdd(func() {
					SendCoins.SendBtn.SetSensitive(false)
					StatusElems.Lab.SetText(btcdd)
					StatusElems.Pb.Hide()
				})
			}
		}
	}
}
Beispiel #16
0
// URI returns the URI of the current resource in the view.
func (v *View) URI() string {
	uri := make(chan string, 1)
	glib.IdleAdd(func() bool {
		uri <- v.WebView.URI()
		return false
	})
	return <-uri
}
Beispiel #17
0
// Title returns the title of the current resource in the view.
func (v *View) Title() string {
	title := make(chan string, 1)
	glib.IdleAdd(func() bool {
		title <- v.WebView.Title()
		return false
	})
	return <-title
}
Beispiel #18
0
// StartMainApplication creates and opens the main window appWindow.
// It then preceeds to start all necessary goroutine to support the main
// application.  Currently, this starts generating the JSON ID generator
// and attempts to open a connection to btcwallet.
//
// This is written to be called as a goroutine outside of the main GTK
// loop.
func StartMainApplication() {
	// Read CA file to verify a btcwallet TLS connection.
	cafile, err := ioutil.ReadFile(cfg.CAFile)
	if err != nil {
		IdlePreGUIError(fmt.Errorf("Cannot open CA file:\n%v", err))
	}

	glib.IdleAdd(func() {
		w, err := CreateWindow()
		if err != nil {
			PreGUIError(fmt.Errorf("Cannot create application window:\n%v", err))
		}
		w.ShowAll()
	})

	// Write current application version to file.
	if err := version.SaveToDataDir(cfg); err != nil {
		log.Print(err)
	}

	// Begin generating new IDs for JSON calls.
	go JSONIDGenerator(NewJSONID)

	// Listen for updates and update GUI with new info.  Attempt
	// reconnect if connection is lost or cannot be established.
	for {
		replies := make(chan error)
		done := make(chan int)
		go func() {
			ListenAndUpdate(cafile, replies)
			close(done)
		}()
	selectLoop:
		for {
			select {
			case <-done:
				break selectLoop
			case err := <-replies:
				switch err {
				case ErrConnectionRefused:
					updateChans.btcwalletConnected <- false
					time.Sleep(5 * time.Second)
				case ErrConnectionLost:
					updateChans.btcwalletConnected <- false
					time.Sleep(5 * time.Second)
				case nil:
					// connected
					updateChans.btcwalletConnected <- true
					log.Print("Established connection to btcwallet.")
				default:
					// TODO(jrick): present unknown error to user in the
					// GUI somehow.
					log.Printf("Unknown connect error: %v", err)
				}
			}
		}
	}
}
Beispiel #19
0
// Open starts loading the resource at the specified URL.
func (v *View) Open(url string) {
	v.load = make(chan struct{}, 1)
	v.lastLoadErr = nil
	glib.IdleAdd(func() bool {
		if !v.destroyed {
			v.WebView.LoadURI(url)
		}
		return false
	})
}
Beispiel #20
0
// IdlePreGUIError runs PreGUIError within the context of the GTK main
// event loop.  This function does not return.
func IdlePreGUIError(e error) {
	glib.IdleAdd(func() {
		PreGUIError(e)
	})

	// This function should block.  However, simple adding a closure the
	// main event loop does not block.  Use an empty select to prevent the
	// calling goroutine from continuing.
	select {}
}
func (self *VerificationWindow) verifyAndLogin() {
	errChan := make(chan error)
	authTokenChan := make(chan string)
	go func() {
		authToken, err := goline.client.GetAuthTokenAfterVerify()
		errChan <- err
		authTokenChan <- authToken
	}()

	go func() {
		err := <-errChan
		if err != nil {
			glib.IdleAdd(func() { goline.LoggerPanicln("Failed to get authorization token:", err) })
		}

		authToken := <-authTokenChan
		err = goline.client.AuthTokenLogin(authToken)
		if err != nil {
			glib.IdleAdd(func() { goline.LoggerPanicln("Failed to login with authorization token:", err) })
		}

		glib.IdleAdd(func() {
			mainWindow := NewMainWindow()
			mainWindow.window.ShowAll()
			self.window.Hide()
			if goline.Autologin {
				goline.AuthToken = authToken
			} else {
				goline.AuthToken, err = encryptAuthToken(self.parent.GetText(self.parent.pwd), authToken)
				if err != nil {
					goline.LoggerPrintln(err)
					glib.IdleAdd(func() { RunAlertMessage(mainWindow.window, "Failed to encrypt authorization token.") })
				}
			}
			err = goline.SaveSettings()
			if err != nil {
				goline.LoggerPrintln(err)
				glib.IdleAdd(func() { RunAlertMessage(mainWindow.window, "Failed to save authorization token.") })
			}
		})
	}()
}
Beispiel #22
0
// updateLockState updates the application widgets due to a change in
// the currently-open wallet's lock state.
func updateLockState() {
	for {
		locked, ok := <-updateChans.lockState
		if !ok {
			return
		}

		if locked {
			glib.IdleAdd(func() {
				MenuBar.Settings.Lock.SetSensitive(false)
				MenuBar.Settings.Unlock.SetSensitive(true)
			})
		} else {
			glib.IdleAdd(func() {
				MenuBar.Settings.Lock.SetSensitive(true)
				MenuBar.Settings.Unlock.SetSensitive(false)
			})
		}
	}
}
Beispiel #23
0
func (self *PopupMenu) viewFile(msgId, url, ext string) {
	go func() {
		downloadingWindow := NewDownloadingWindow(msgId)
		glib.IdleAdd(downloadingWindow.window.ShowAll)
		defer glib.IdleAdd(downloadingWindow.window.Destroy)
		content, err := downloadContentToTemp(msgId, url, ext)
		if err != nil {
			goline.LoggerPrintln(err)
			glib.IdleAdd(func() { RunAlertMessage(self.parent.window, "Failed to download file: %s", err) })
			return
		}

		cmd := exec.Command("xdg-open", content)
		err = cmd.Start()
		if err != nil {
			goline.LoggerPrintln(err)
			glib.IdleAdd(func() { RunAlertMessage(self.parent.window, "Failed to open file.") })
			return
		}
	}()
}
Beispiel #24
0
// cmdGetNewAddress requests a new wallet address.
//
// TODO(jrick): support non-default accounts
func cmdGetNewAddress(ws *websocket.Conn) {
	var err error
	defer func() {
		if err != nil {

		}
	}()

	n := <-NewJSONID
	msg, err := btcjson.CreateMessageWithId("getnewaddress", n, "")
	if err != nil {
		triggerReplies.newAddr <- err
		return
	}

	replyHandlers.Lock()
	replyHandlers.m[n] = func(result interface{}, err *btcjson.Error) {
		switch {
		case err == nil:
			if addr, ok := result.(string); ok {
				triggerReplies.newAddr <- addr
			}

		case err.Code == btcjson.ErrWalletKeypoolRanOut.Code:
			success := make(chan bool)
			glib.IdleAdd(func() {
				dialog, err := createUnlockDialog(unlockForKeypool, success)
				if err != nil {
					log.Print(err)
					success <- false
					return
				}
				dialog.Run()
			})
			if <-success {
				triggers.newAddr <- 1
			}

		default: // all other non-nil errors
			triggerReplies.newAddr <- errors.New(err.Message)
		}
	}
	replyHandlers.Unlock()

	if err = websocket.Message.Send(ws, msg); err != nil {
		replyHandlers.Lock()
		delete(replyHandlers.m, n)
		replyHandlers.Unlock()
		triggerReplies.newAddr <- err
	}
}
func (self *AutologinWindow) Login() {
	errChan := make(chan error)
	go func() {
		err := goline.client.AuthTokenLogin(goline.AuthToken)
		errChan <- err
	}()
	go func() {
		err := <-errChan
		if err != nil {
			goline.LoggerPrintln(err)
			glib.IdleAdd(func() {
				loginWindow := NewLoginWindow()
				loginWindow.window.ShowAll()
				self.window.Hide()
				RunAlertMessage(loginWindow.window, "Failed to login with authorization token.")
			})
		} else {
			glib.IdleAdd(func() {
				NewMainWindow().window.ShowAll()
				self.window.Hide()
			})
		}
	}()
}
Beispiel #26
0
// XXX spilt this?
func updateProgress() {
	for {
		bcHeight, ok := <-updateChans.bcHeight
		if !ok {
			return
		}

		// TODO(jrick) this can go back when remote height is updated.
		/*
			bcHeightRemote, ok := <-updateChans.bcHeightRemote
			if !ok {
				return
			}

			if bcHeight >= 0 && bcHeightRemote >= 0 {
				percentDone := float64(bcHeight) / float64(bcHeightRemote)
				if percentDone < 1 {
					s := fmt.Sprintf("%d of ~%d blocks", bcHeight,
						bcHeightRemote)
					glib.IdleAdd(StatusElems.Lab.SetText,
						"Updating blockchain...")
					glib.IdleAdd(StatusElems.Pb.SetText, s)
					glib.IdleAdd(StatusElems.Pb.SetFraction, percentDone)
					glib.IdleAdd(StatusElems.Pb.Show)
				} else {
					s := fmt.Sprintf("%d blocks", bcHeight)
					glib.IdleAdd(StatusElems.Lab.SetText, s)
					glib.IdleAdd(StatusElems.Pb.Hide)
				}
			} else if bcHeight >= 0 && bcHeightRemote == -1 {
				s := fmt.Sprintf("%d blocks", bcHeight)
				glib.IdleAdd(StatusElems.Lab.SetText, s)
				glib.IdleAdd(StatusElems.Pb.Hide)
			} else {
				glib.IdleAdd(StatusElems.Lab.SetText,
					"Error getting blockchain height")
				glib.IdleAdd(StatusElems.Pb.Hide)
			}
		*/

		s := fmt.Sprintf("%d blocks", bcHeight)
		glib.IdleAdd(func() {
			StatusElems.Lab.SetText(s)
			StatusElems.Pb.Hide()
		})
	}
}
Beispiel #27
0
// updateBalance listens for new wallet account balances, updating the GUI
// when necessary.
func updateBalance() {
	for {
		balance, ok := <-updateChans.balance
		if !ok {
			return
		}

		var s string
		if math.IsNaN(balance) {
			s = "unknown"
		} else {
			s = strconv.FormatFloat(balance, 'f', 8, 64) + " BTC"
		}
		glib.IdleAdd(func() {
			Overview.Balance.SetMarkup("<b>" + s + "</b>")
			SendCoins.Balance.SetText("Balance: " + s)
		})
	}
}
Beispiel #28
0
// updateBalance listens for new wallet account unconfirmed balances, updating
// the GUI when necessary.
func updateUnconfirmed() {
	for {
		unconfirmed, ok := <-updateChans.unconfirmed
		if !ok {
			return
		}

		var s string
		if math.IsNaN(unconfirmed) {
			s = "unknown"
		} else {
			balStr := strconv.FormatFloat(unconfirmed, 'f', 8, 64) + " BTC"
			s = "<b>" + balStr + "</b>"
		}
		glib.IdleAdd(func() {
			Overview.Unconfirmed.SetMarkup(s)
		})
	}
}
func TestWebView_LoadURI(t *testing.T) {
	setup()
	defer teardown()

	responseOk := false
	mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
		w.Write([]byte("abc"))
		responseOk = true
	})

	loadFinished := false
	webView.Connect("load-failed", func() {
		t.Errorf("load failed")
	})
	webView.Connect("load-changed", func(_ *glib.Object, loadEvent LoadEvent) {
		switch loadEvent {
		case LoadFinished:
			loadFinished = true
			gtk.MainQuit()
		}
	})

	glib.IdleAdd(func() bool {
		webView.LoadURI(server.URL)
		return false
	})

	gtk.Main()

	if !responseOk {
		t.Error("!responseOk")
	}
	if !loadFinished {
		t.Error("!loadFinished")
	}
}
Beispiel #30
0
func createRecvCoins() *gtk.Widget {
	store, err := gtk.ListStoreNew(glib.TYPE_STRING, glib.TYPE_STRING)
	if err != nil {
		log.Fatal(err)
	}
	RecvCoins.Store = store

	tv, err := gtk.TreeViewNewWithModel(store)
	if err != nil {
		log.Fatal(err)
	}
	RecvCoins.Treeview = tv

	renderer, err := gtk.CellRendererTextNew()
	if err != nil {
		log.Fatal(err)
	}
	renderer.Set("editable", true)
	renderer.Set("editable-set", true)
	renderer.Connect("edited", func(_ *glib.Object, path, text string) {
		iter, err := store.GetIterFromString(path)
		if err == nil {
			store.Set(iter, []int{0}, []interface{}{text})
		}
	})

	col, err := gtk.TreeViewColumnNewWithAttribute("Label", renderer,
		"text", 0)
	if err != nil {
		log.Fatal(err)
	}
	col.SetExpand(true)
	tv.AppendColumn(col)
	cr, err := gtk.CellRendererTextNew()
	if err != nil {
		log.Fatal(err)
	}
	col, err = gtk.TreeViewColumnNewWithAttribute("Address", cr, "text", 1)
	if err != nil {
		log.Fatal(err)
	}
	col.SetMinWidth(350)
	tv.AppendColumn(col)

	newAddr, err := gtk.ButtonNewWithLabel("New Address")
	if err != nil {
		log.Fatal(err)
	}
	newAddr.SetSizeRequest(150, -1)
	newAddr.Connect("clicked", func() {
		go func() {
			triggers.newAddr <- 1
			reply := <-triggerReplies.newAddr
			if err, ok := reply.(error); ok {
				glib.IdleAdd(func() {
					mDialog := errorDialog("New address generation failed",
						err.Error())
					mDialog.Run()
					mDialog.Destroy()

				})
			} else if addr, ok := reply.(string); ok {
				glib.IdleAdd(func() {
					iter := RecvCoins.Store.Append()
					RecvCoins.Store.Set(iter, []int{0, 1},
						[]interface{}{"", addr})
				})
			}
		}()
	})
	newAddr.SetSensitive(false)
	RecvCoins.NewAddrBtn = newAddr

	buttons, err := gtk.GridNew()
	if err != nil {
		log.Fatal(err)
	}

	buttons.Add(newAddr)
	cpyAddr, err := gtk.ButtonNewWithLabel("Copy Address")
	if err != nil {
		log.Fatal(err)
	}
	cpyAddr.SetSizeRequest(150, -1)
	cpyAddr.Connect("clicked", func() {
		sel, err := tv.GetSelection()
		if err != nil {
			log.Fatal(err)
		}
		var iter gtk.TreeIter
		if sel.GetSelected(nil, &iter) {
			val, err := store.GetValue(&iter, 1)
			if err != nil {
				log.Fatal(err)
			}

			display, err := gdk.DisplayGetDefault()
			if err != nil {
				log.Fatal(err)
			}

			clipboard, err := gtk.ClipboardGetForDisplay(
				display,
				gdk.SELECTION_CLIPBOARD)
			if err != nil {
				log.Fatal(err)
			}

			primary, err := gtk.ClipboardGetForDisplay(
				display,
				gdk.SELECTION_PRIMARY)
			if err != nil {
				log.Fatal(err)
			}

			s, _ := val.GetString()
			clipboard.SetText(s)
			primary.SetText(s)
		}
	})
	buttons.Add(cpyAddr)

	sw, err := gtk.ScrolledWindowNew(nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	sw.Add(tv)
	sw.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
	sw.SetHExpand(true)
	sw.SetVExpand(true)

	grid, err := gtk.GridNew()
	if err != nil {
		log.Fatal(err)
	}
	grid.SetOrientation(gtk.ORIENTATION_VERTICAL)
	grid.Add(sw)
	grid.Add(buttons)

	return &grid.Container.Widget
}