main.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package main
  2. import (
  3. "fmt"
  4. "flag"
  5. "os"
  6. "syscall"
  7. "time"
  8. "hypr-dock/cfg"
  9. "github.com/dlasky/gotk3-layershell/layershell"
  10. "github.com/gotk3/gotk3/gdk"
  11. "github.com/gotk3/gotk3/gtk"
  12. "github.com/allan-simon/go-singleinstance"
  13. "strconv"
  14. )
  15. const version = "0.0.5-0-alpha"
  16. // Only during development
  17. // const CONFIG_DIR = "/home/lotsmannc/repos/gotk/configs"
  18. const CONFIG_DIR = "./configs"
  19. const THEMES_DIR = CONFIG_DIR + "/themes/"
  20. const MAIN_CONFIG = CONFIG_DIR + "/config.jsonc"
  21. const ITEMS_CONFIG = CONFIG_DIR + "/pinned.json"
  22. var err error
  23. var config cfg.Config
  24. var window *gtk.Window
  25. var detectArea *gtk.Window
  26. var orientation gtk.Orientation
  27. func initSettings() {
  28. configFile := flag.String("config", MAIN_CONFIG, "config file")
  29. config = cfg.ConnectConfig(*configFile, false)
  30. pinnedApps = cfg.ReadItemList(ITEMS_CONFIG)
  31. currentTheme := flag.String("theme", config.CurrentTheme, "theme")
  32. config.CurrentTheme = *currentTheme
  33. themeConfig := cfg.ConnectConfig(
  34. THEMES_DIR + config.CurrentTheme + "/" + config.CurrentTheme + ".jsonc", true)
  35. config.Blur = themeConfig.Blur
  36. config.Spacing = themeConfig.Spacing
  37. flag.Parse()
  38. }
  39. func main() {
  40. signalHandler()
  41. lockFilePath := fmt.Sprintf("%s/hypr-dock-%s.lock", tempDir(), os.Getenv("USER"))
  42. lockFile, err := singleinstance.CreateLockFile(lockFilePath)
  43. if err != nil {
  44. file, err := loadTextFile(lockFilePath)
  45. if err == nil {
  46. pidStr := file[0]
  47. pidInt, _ := strconv.Atoi(pidStr)
  48. syscall.Kill(pidInt, syscall.SIGUSR1)
  49. }
  50. os.Exit(0)
  51. }
  52. defer lockFile.Close()
  53. // Window build
  54. initSettings()
  55. gtk.Init(nil)
  56. window, err = gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
  57. if err != nil {
  58. fmt.Println("Unable to create window:", err)
  59. }
  60. window.SetTitle("hypr-dock")
  61. orientation := setWindowProperty(window)
  62. err = addCssProvider(THEMES_DIR + config.CurrentTheme + "/style.css")
  63. if err != nil {
  64. fmt.Println(
  65. "CSS file not found, the default GTK theme is running!\n", err)
  66. }
  67. buildApp(orientation)
  68. window.Add(app)
  69. window.Connect("destroy", func() {gtk.MainQuit()})
  70. window.ShowAll()
  71. // Build detect area
  72. if config.Layer == "auto" {initDetectArea()}
  73. // Hyprland socket connect
  74. go initHyprEvents()
  75. gtk.Main()
  76. }
  77. func initDetectArea() {
  78. detectArea, _ = gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
  79. detectArea.SetName("detect")
  80. layershell.InitForWindow(detectArea)
  81. layershell.SetNamespace(detectArea, "dock-detect")
  82. layershell.SetAnchor(detectArea, Edge, true)
  83. layershell.SetMargin(detectArea, Edge, 0)
  84. layershell.SetLayer(detectArea, layershell.LAYER_SHELL_LAYER_TOP)
  85. switch orientation {
  86. case gtk.ORIENTATION_HORIZONTAL:
  87. detectArea.SetSizeRequest(config.IconSize * len(addedApps) * 2 - 20, 1)
  88. case gtk.ORIENTATION_VERTICAL:
  89. detectArea.SetSizeRequest(1, config.IconSize * len(addedApps) * 2 - 20)
  90. }
  91. detectArea.Connect("enter-notify-event", func(window *gtk.Window, e *gdk.Event) {
  92. event := gdk.EventCrossingNewFromEvent(e)
  93. isInWindow := event.Detail() == 3 || event.Detail() == 4 || true
  94. isCancelHide = 1
  95. if isInWindow {
  96. go func() {
  97. setLayer("top")
  98. }()
  99. }
  100. })
  101. detectArea.ShowAll()
  102. }
  103. func addCssProvider(cssFile string) error {
  104. cssProvider, _ := gtk.CssProviderNew()
  105. err := cssProvider.LoadFromPath(cssFile)
  106. if err == nil {
  107. screen, _ := gdk.ScreenGetDefault()
  108. gtk.AddProviderForScreen(
  109. screen, cssProvider,
  110. gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
  111. return nil
  112. }
  113. return err
  114. }
  115. var Edge = layershell.LAYER_SHELL_EDGE_BOTTOM
  116. func setWindowProperty(window *gtk.Window) gtk.Orientation {
  117. AppOreintation := gtk.ORIENTATION_HORIZONTAL
  118. Layer := layershell.LAYER_SHELL_LAYER_BOTTOM
  119. Edge = layershell.LAYER_SHELL_EDGE_BOTTOM
  120. switch config.Layer {
  121. case "background":
  122. Layer = layershell.LAYER_SHELL_LAYER_BACKGROUND
  123. case "bottom":
  124. Layer = layershell.LAYER_SHELL_LAYER_BOTTOM
  125. case "top":
  126. Layer = layershell.LAYER_SHELL_LAYER_TOP
  127. case "overlay":
  128. Layer = layershell.LAYER_SHELL_LAYER_OVERLAY
  129. }
  130. switch config.Position {
  131. case "left":
  132. Edge = layershell.LAYER_SHELL_EDGE_LEFT
  133. AppOreintation = gtk.ORIENTATION_VERTICAL
  134. case "bottom":
  135. Edge = layershell.LAYER_SHELL_EDGE_BOTTOM
  136. case "right":
  137. Edge = layershell.LAYER_SHELL_EDGE_RIGHT
  138. AppOreintation = gtk.ORIENTATION_VERTICAL
  139. case "top":
  140. Edge = layershell.LAYER_SHELL_EDGE_TOP
  141. }
  142. layershell.InitForWindow(window)
  143. layershell.SetNamespace(window, "hypr-dock")
  144. layershell.SetAnchor(window, Edge, true)
  145. layershell.SetMargin(window, Edge, 0)
  146. addLayerRule()
  147. if config.Layer == "auto" {
  148. layershell.SetLayer(window, Layer)
  149. autoLayer()
  150. return AppOreintation
  151. }
  152. layershell.SetLayer(window, Layer)
  153. return AppOreintation
  154. }
  155. func autoLayer() {
  156. window.Connect("enter-notify-event", func(window *gtk.Window, e *gdk.Event) {
  157. event := gdk.EventCrossingNewFromEvent(e)
  158. isInWindow := event.Detail() == 3 || event.Detail() == 4 || true
  159. isCancelHide = 1
  160. if isInWindow && !special {
  161. go func() {
  162. setLayer("top")
  163. }()
  164. }
  165. })
  166. window.Connect("leave-notify-event", func(window *gtk.Window, e *gdk.Event) {
  167. event := gdk.EventCrossingNewFromEvent(e)
  168. isInWindow := event.Detail() == 3 || event.Detail() == 4
  169. isCancelHide = 0
  170. if isInWindow {
  171. go func() {
  172. time.Sleep(time.Second / 3)
  173. setLayer("bottom")
  174. }()
  175. }
  176. })
  177. }
  178. func setLayer(layer string) {
  179. switch layer {
  180. case "top":
  181. layershell.SetLayer(window, layershell.LAYER_SHELL_LAYER_TOP)
  182. case "bottom":
  183. if isCancelHide == 0 {
  184. layershell.SetLayer(window, layershell.LAYER_SHELL_LAYER_BOTTOM)
  185. }
  186. isCancelHide = 0
  187. }
  188. }