robotgo_x11.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // https://github.com/go-vgo/robotgo/blob/master/LICENSE
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. //go:build !darwin && !windows
  11. // +build !darwin,!windows
  12. package robotgo
  13. import (
  14. "errors"
  15. "log"
  16. "github.com/robotn/xgb"
  17. "github.com/robotn/xgb/xinerama"
  18. "github.com/robotn/xgb/xproto"
  19. "github.com/robotn/xgbutil"
  20. "github.com/robotn/xgbutil/ewmh"
  21. )
  22. var xu *xgbutil.XUtil
  23. // GetBounds get the window bounds
  24. func GetBounds(pid int, args ...int) (int, int, int, int) {
  25. var isPid int
  26. if len(args) > 0 || NotPid {
  27. isPid = 1
  28. return internalGetBounds(pid, isPid)
  29. }
  30. xid, err := GetXid(xu, pid)
  31. if err != nil {
  32. log.Println("Get Xid from Pid errors is: ", err)
  33. return 0, 0, 0, 0
  34. }
  35. return internalGetBounds(int(xid), isPid)
  36. }
  37. // GetClient get the window client bounds
  38. func GetClient(pid int, args ...int) (int, int, int, int) {
  39. var isPid int
  40. if len(args) > 0 || NotPid {
  41. isPid = 1
  42. return internalGetClient(pid, isPid)
  43. }
  44. xid, err := GetXid(xu, pid)
  45. if err != nil {
  46. log.Println("Get Xid from Pid errors is: ", err)
  47. return 0, 0, 0, 0
  48. }
  49. return internalGetClient(int(xid), isPid)
  50. }
  51. // internalGetTitle get the window title
  52. func internalGetTitle(pid int, args ...int) string {
  53. var isPid int
  54. if len(args) > 0 || NotPid {
  55. isPid = 1
  56. return cgetTitle(pid, isPid)
  57. }
  58. xid, err := GetXid(xu, pid)
  59. if err != nil {
  60. log.Println("Get Xid from Pid errors is: ", err)
  61. return ""
  62. }
  63. return cgetTitle(int(xid), isPid)
  64. }
  65. // ActivePidC active the window by Pid,
  66. // If args[0] > 0 on the unix platform via a xid to active
  67. func ActivePidC(pid int, args ...int) error {
  68. var isPid int
  69. if len(args) > 0 || NotPid {
  70. isPid = 1
  71. internalActive(pid, isPid)
  72. return nil
  73. }
  74. xid, err := GetXid(xu, pid)
  75. if err != nil {
  76. log.Println("Get Xid from Pid errors is: ", err)
  77. return err
  78. }
  79. internalActive(int(xid), isPid)
  80. return nil
  81. }
  82. // ActivePid active the window by Pid,
  83. //
  84. // If args[0] > 0 on the Windows platform via a window handle to active,
  85. // If args[0] > 0 on the unix platform via a xid to active
  86. func ActivePid(pid int, args ...int) error {
  87. if xu == nil {
  88. var err error
  89. xu, err = xgbutil.NewConn()
  90. if err != nil {
  91. return err
  92. }
  93. }
  94. if len(args) > 0 {
  95. err := ewmh.ActiveWindowReq(xu, xproto.Window(pid))
  96. if err != nil {
  97. return err
  98. }
  99. return nil
  100. }
  101. // get the xid from pid
  102. xid, err := GetXidFromPid(xu, pid)
  103. if err != nil {
  104. return err
  105. }
  106. err = ewmh.ActiveWindowReq(xu, xid)
  107. if err != nil {
  108. return err
  109. }
  110. return nil
  111. }
  112. // GetXid get the xid return window and error
  113. func GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
  114. if xu == nil {
  115. var err error
  116. xu, err = xgbutil.NewConn()
  117. if err != nil {
  118. // log.Println("xgbutil.NewConn errors is: ", err)
  119. return 0, err
  120. }
  121. }
  122. xid, err := GetXidFromPid(xu, pid)
  123. return xid, err
  124. }
  125. // GetXidFromPid get the xid from pid
  126. func GetXidFromPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {
  127. windows, err := ewmh.ClientListGet(xu)
  128. if err != nil {
  129. return 0, err
  130. }
  131. for _, window := range windows {
  132. wmPid, err := ewmh.WmPidGet(xu, window)
  133. if err != nil {
  134. return 0, err
  135. }
  136. if uint(pid) == wmPid {
  137. return window, nil
  138. }
  139. }
  140. return 0, errors.New("failed to find a window with a matching pid.")
  141. }
  142. // DisplaysNum get the count of displays
  143. func DisplaysNum() int {
  144. c, err := xgb.NewConn()
  145. if err != nil {
  146. return 0
  147. }
  148. defer c.Close()
  149. err = xinerama.Init(c)
  150. if err != nil {
  151. return 0
  152. }
  153. reply, err := xinerama.QueryScreens(c).Reply()
  154. if err != nil {
  155. return 0
  156. }
  157. return int(reply.Number)
  158. }
  159. // GetMainId get the main display id
  160. func GetMainId() int {
  161. conn, err := xgb.NewConn()
  162. if err != nil {
  163. return -1
  164. }
  165. setup := xproto.Setup(conn)
  166. defaultScreen := setup.DefaultScreen(conn)
  167. id := -1
  168. for i, screen := range setup.Roots {
  169. if defaultScreen.Root == screen.Root {
  170. id = i
  171. break
  172. }
  173. }
  174. return id
  175. }
  176. // Alert show a alert window
  177. // Displays alert with the attributes.
  178. // If cancel button is not given, only the default button is displayed
  179. //
  180. // Examples:
  181. //
  182. // robotgo.Alert("hi", "window", "ok", "cancel")
  183. func Alert(title, msg string, args ...string) bool {
  184. defaultBtn, cancelBtn := alertArgs(args...)
  185. c := `xmessage -center ` + msg +
  186. ` -title ` + title + ` -buttons ` + defaultBtn + ":0,"
  187. if cancelBtn != "" {
  188. c += cancelBtn + ":1"
  189. }
  190. c += ` -default ` + defaultBtn
  191. c += ` -geometry 400x200`
  192. out, err := Run(c)
  193. if err != nil {
  194. // fmt.Println("Alert: ", err, ". ", string(out))
  195. return false
  196. }
  197. if string(out) == "1" {
  198. return false
  199. }
  200. return true
  201. }