github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/usersession/userd/ui/ui.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package ui 21 22 import ( 23 "fmt" 24 "os" 25 "strings" 26 "time" 27 28 "github.com/snapcore/snapd/osutil" 29 ) 30 31 // UI is an interface for user interaction 32 type UI interface { 33 // YesNo asks a yes/no question. The primary text 34 // will be printed in a larger font, the secondary text 35 // in the standard font and the (optional) footer will 36 // be printed in a small font. 37 // 38 // The value "true" is returned if the user clicks "yes", 39 // otherwise "false". 40 YesNo(primary, secondary string, options *DialogOptions) bool 41 } 42 43 // Options for the UI interface 44 type DialogOptions struct { 45 Footer string 46 Timeout time.Duration 47 } 48 49 var hasZenityExecutable = func() bool { 50 return osutil.ExecutableExists("zenity") 51 } 52 53 var hasKDialogExecutable = func() bool { 54 return osutil.ExecutableExists("kdialog") 55 } 56 57 func MockHasZenityExecutable(f func() bool) func() { 58 oldHasZenityExecutable := hasZenityExecutable 59 hasZenityExecutable = f 60 return func() { 61 hasZenityExecutable = oldHasZenityExecutable 62 } 63 } 64 65 func MockHasKDialogExecutable(f func() bool) func() { 66 oldHasKDialogExecutable := hasKDialogExecutable 67 hasKDialogExecutable = f 68 return func() { 69 hasKDialogExecutable = oldHasKDialogExecutable 70 } 71 } 72 73 // New returns the best matching UI interface for the given system 74 // or an error if no ui can be created. 75 func New() (UI, error) { 76 hasZenity := hasZenityExecutable() 77 hasKDialog := hasKDialogExecutable() 78 79 switch { 80 case hasZenity && hasKDialog: 81 // prefer kdialog on KDE, otherwise use zenity 82 currentDesktop := os.Getenv("XDG_CURRENT_DESKTOP") 83 if strings.Contains("kde", strings.ToLower(currentDesktop)) { 84 return &KDialog{}, nil 85 } 86 return &Zenity{}, nil 87 case hasZenity: 88 return &Zenity{}, nil 89 case hasKDialog: 90 return &KDialog{}, nil 91 default: 92 return nil, fmt.Errorf("cannot create a UI: please install zenity or kdialog") 93 } 94 }