diff --git a/bar.go b/bar.go new file mode 100644 index 0000000..d64adc2 --- /dev/null +++ b/bar.go @@ -0,0 +1,213 @@ +package main + +import ( + "fmt" + "time" + + "github.com/MiracleOS-Team/desktoplib/batteryHandler" + "github.com/MiracleOS-Team/desktoplib/foreignToplevel" + "github.com/MiracleOS-Team/desktoplib/networkManagerHandler" + "github.com/MiracleOS-Team/desktoplib/volumeHandler" + "github.com/dlasky/gotk3-layershell/layershell" + "github.com/gotk3/gotk3/gdk" + "github.com/gotk3/gotk3/glib" + "github.com/gotk3/gotk3/gtk" +) + +func getDateInfo() (string, string) { + hours, minutes, _ := time.Now().Clock() + curTimeInString := fmt.Sprintf("%d:%02d", hours, minutes) + + curDay := time.Now().Day() + curDayName := firstN(time.Now().Weekday().String(), 3) + var curDayCal string + + if curDay <= 5 { + curMonth := time.Now().Month() + curDayCal = fmt.Sprintf("%s. %02d %s", curDayName, curDay, curMonth) + } else { + curDayCal = fmt.Sprintf("%s. %02d", curDayName, curDay) + } + return curDayCal, curTimeInString +} + +func createSidestuff() *gtk.Box { + sideBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + sideBox.SetHAlign(gtk.ALIGN_END) + sc, _ := sideBox.GetStyleContext() + sc.AddClass("sidestuff") + + otherIcons, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + keyboardImage, _ := gtk.ImageNewFromIconName("input-keyboard-symbolic", gtk.ICON_SIZE_BUTTON) + sc, _ = keyboardImage.GetStyleContext() + sc.AddClass("keyboard") + + otherIcons.PackStart(keyboardImage, false, false, 0) + sc, _ = otherIcons.GetStyleContext() + sc.AddClass("other-icons-wrapper") + + statusBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + + volumeIcon, err := volumeHandler.GetAudioIcon() + + if err == nil { + volumeImage, _ := gtk.ImageNewFromIconName(volumeIcon, gtk.ICON_SIZE_BUTTON) + sc, _ = volumeImage.GetStyleContext() + sc.AddClass("sound") + + statusBox.PackStart(volumeImage, false, false, 0) + } + + networkIcon, err := networkManagerHandler.GetNetworkIcon() + + if err == nil { + networkImage, _ := gtk.ImageNewFromIconName(networkIcon, gtk.ICON_SIZE_BUTTON) + + sc, _ = networkImage.GetStyleContext() + sc.AddClass("network") + + statusBox.PackStart(networkImage, false, false, 0) + } + + if batteryHandler.IsBattery() { + batteryImage, _ := gtk.ImageNewFromIconName(batteryHandler.GetBatteryIcon(), gtk.ICON_SIZE_BUTTON) + + sc, _ = batteryImage.GetStyleContext() + sc.AddClass("power") + + statusBox.PackStart(batteryImage, false, false, 0) + } + + sc, _ = statusBox.GetStyleContext() + sc.AddClass("status-icons-wrapper") + + curDayCal, currUTCTimeInString := getDateInfo() + + clock, _ := gtk.LabelNew(currUTCTimeInString) + sc, _ = clock.GetStyleContext() + sc.AddClass("clock-text") + + dayText, _ := gtk.LabelNew(curDayCal) + sc, _ = dayText.GetStyleContext() + sc.AddClass("day-text") + + glib.TimeoutAdd(uint(500), func() bool { + // Get new date/time info. + newDayCal, newTime := getDateInfo() + + // Update the labels. + clock.SetText(newTime) + dayText.SetText(newDayCal) + + // Return true to keep the timeout active. + return true + }) + + notificationButton, _ := gtk.ButtonNew() + notificationBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + sc, _ = notificationBox.GetStyleContext() + sc.AddClass("notification-bell-wrapper") + + notificationImage, _ := gtk.ImageNewFromIconName("preferences-system-notifications-symbolic", gtk.ICON_SIZE_BUTTON) + sc, _ = notificationImage.GetStyleContext() + sc.AddClass("notification-bell") + + notificationBox.PackStart(notificationImage, false, false, 0) + notificationButton.Add(notificationBox) + + sideBox.PackStart(otherIcons, false, false, 0) + sideBox.PackStart(statusBox, false, false, 0) + sideBox.PackStart(clock, false, false, 0) + sideBox.PackStart(dayText, false, false, 0) + sideBox.PackStart(notificationButton, false, false, 0) + + return sideBox +} + +func createWorkspaces() *gtk.Box { + box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + box.SetHAlign(gtk.ALIGN_START) + sc, _ := box.GetStyleContext() + sc.AddClass("workspaces") + + toplevels, err := foreignToplevel.ListToplevels() + if err != nil { + fmt.Println("Error getting toplevels:", err) + return box + } + + for _, k := range toplevels { + imgButton, _ := gtk.ButtonNew() + sc, _ := imgButton.GetStyleContext() + sc.AddClass("app") + + img, _ := gtk.ImageNewFromIconName(k.AppID, gtk.ICON_SIZE_BUTTON) + imgButton.Add(img) + box.PackStart(imgButton, false, false, 0) + } + // Placeholder for dynamic window list + imgButton1, _ := gtk.ButtonNew() + sc, _ = imgButton1.GetStyleContext() + sc.AddClass("app") + img1, _ := gtk.ImageNewFromIconName("preferences-desktop", gtk.ICON_SIZE_BUTTON) + imgButton1.Add(img1) + box.PackStart(imgButton1, false, false, 0) + + return box +} + +func createMainIcons() *gtk.Box { + box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + box.SetHAlign(gtk.ALIGN_CENTER) + + desktopImage, _ := gtk.ImageNewFromIconName("preferences-system-windows-symbolic", gtk.ICON_SIZE_LARGE_TOOLBAR) + searchImage, _ := gtk.ImageNewFromIconName("system-search-symbolic", gtk.ICON_SIZE_LARGE_TOOLBAR) + customIcon, _ := gtk.ImageNewFromFile("images/pp.png") + customButton, _ := gtk.ButtonNew() + customButton.Add(customIcon) + + customButton.Connect("clicked", func() { + createMainMenu().ShowAll() + box.Hide() + }) + + box.PackStart(desktopImage, false, false, 0) + box.PackStart(customButton, false, false, 0) + box.PackStart(searchImage, false, false, 0) + + return box +} + +func createBar() *gtk.Window { + win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) + win.SetTitle("Main Bar") + win.SetDecorated(false) + win.SetResizable(false) + win.SetTypeHint(gdk.WINDOW_TYPE_HINT_DOCK) + + layershell.InitForWindow(win) + layershell.SetNamespace(win, "miracleos") + layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_LEFT, true) + layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_BOTTOM, true) + layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_RIGHT, true) + + layershell.SetLayer(win, layershell.LAYER_SHELL_LAYER_TOP) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_TOP, 0) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_LEFT, 0) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_RIGHT, 0) + + layershell.SetExclusiveZone(win, 75) + layershell.SetKeyboardMode(win, layershell.LAYER_SHELL_KEYBOARD_MODE_NONE) + disp, _ := gdk.DisplayGetDefault() + mon, _ := disp.GetMonitor(0) + layershell.SetMonitor(win, mon) + + box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + sc, _ := box.GetStyleContext() + sc.AddClass("bar") + box.PackStart(createWorkspaces(), false, false, 0) + box.SetCenterWidget(createMainIcons()) + box.PackEnd(createSidestuff(), false, false, 0) + win.Add(box) + return win +} diff --git a/desktop.css b/desktop.css index ccf684d..74454ce 100644 --- a/desktop.css +++ b/desktop.css @@ -279,4 +279,8 @@ .status-icons-wrapper image { margin: 5px; - } \ No newline at end of file + } + + .workspaces * { + margin: 0px; + } diff --git a/go.mod b/go.mod index eb371cb..a0ad624 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,28 @@ module github.com/MiracleOS-Team/desktop go 1.22.2 require ( - github.com/MiracleOS-Team/libxdg-go v0.0.0-20250130123149-66a2b3e59a66 + github.com/MiracleOS-Team/desktoplib v0.0.0-20250204155824-a42d5b7c24e3 + github.com/MiracleOS-Team/libxdg-go v0.0.0-20250203122932-0d6a9fc71582 + github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774 github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56 ) require ( github.com/cli/safeexec v1.0.1 // indirect - golang.org/x/text v0.21.0 // indirect + github.com/distatus/battery v0.11.0 // indirect + github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell v1.4.0 // indirect + github.com/gek64/displayController v1.0.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/itchyny/volume-go v0.2.2 // indirect + github.com/jfreymuth/pulse v0.1.1 // indirect + github.com/lucasb-eyer/go-colorful v1.0.3 // indirect + github.com/mattn/go-runewidth v0.0.7 // indirect + github.com/moutend/go-wca v0.3.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect google.golang.org/protobuf v1.36.4 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + howett.net/plist v1.0.1 // indirect ) diff --git a/go.sum b/go.sum index be21494..4c5877f 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,17 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250203164533-9daac46041b5 h1:bnMP6ciWaT2zl+IJcWDfwhDFbp9iF4vZ9g50HRQkWC8= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250203164533-9daac46041b5/go.mod h1:LvzdmHbq2om/X8sPOcR3faqsZQRHTVMCm58NFp2aLIU= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250203213240-ff0177e4ccaa h1:yAqSw/ahPqVO7O5LxpzJpNuZlW5Q366BKUwZWIJ2nDE= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250203213240-ff0177e4ccaa/go.mod h1:LvzdmHbq2om/X8sPOcR3faqsZQRHTVMCm58NFp2aLIU= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250204155824-a42d5b7c24e3 h1:+UZtfbdcpSCXIap83dOHxWcMOqc42jCpYepfidv6xGY= +github.com/MiracleOS-Team/desktoplib v0.0.0-20250204155824-a42d5b7c24e3/go.mod h1:lsr1apHlN/KIBNQdH2ngannvIIBKnYRvyo8oCgBoaVE= github.com/MiracleOS-Team/libxdg-go v0.0.0-20250126160842-bc18282c37ee h1:jsl3imeBR+qACjnTzGHJt1zrvrkW5MkHyFFpsmYnzxk= github.com/MiracleOS-Team/libxdg-go v0.0.0-20250126160842-bc18282c37ee/go.mod h1:mKskdRQzPihHpgc1aUN06dlR2ECTxQWgPzOY3u2To+I= github.com/MiracleOS-Team/libxdg-go v0.0.0-20250130123149-66a2b3e59a66 h1:zax0cvv63QOakMKGH4p1UN9UfVW9bRHEe1Q2GGRPt00= github.com/MiracleOS-Team/libxdg-go v0.0.0-20250130123149-66a2b3e59a66/go.mod h1:mKskdRQzPihHpgc1aUN06dlR2ECTxQWgPzOY3u2To+I= +github.com/MiracleOS-Team/libxdg-go v0.0.0-20250203122932-0d6a9fc71582 h1:Ce5u6O6M1586/JQxVvGr/GCClbxUJbtRPckg4ZfFawY= +github.com/MiracleOS-Team/libxdg-go v0.0.0-20250203122932-0d6a9fc71582/go.mod h1:mKskdRQzPihHpgc1aUN06dlR2ECTxQWgPzOY3u2To+I= github.com/bep/godartsass v1.2.0 h1:E2VvQrxAHAFwbjyOIExAMmogTItSKodoKuijNrGm5yU= github.com/bep/godartsass v1.2.0/go.mod h1:6LvK9RftsXMxGfsA0LDV12AGc4Jylnu6NgHL+Q5/pE8= github.com/bep/godartsass/v2 v2.3.2 h1:meuc76J1C1soSCAnlnJRdGqJ5S4m6/GW+8hmOe9tOog= @@ -15,10 +23,27 @@ github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/distatus/battery v0.11.0 h1:KJk89gz90Iq/wJtbjjM9yUzBXV+ASV/EG2WOOL7N8lc= +github.com/distatus/battery v0.11.0/go.mod h1:KmVkE8A8hpIX4T78QRdMktYpEp35QfOL8A8dwZBxq2k= +github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774 h1:o87OVL4olQBlVwN3+NSVQpS6gj9FWUYtxOfHXWZigUE= +github.com/dlasky/gotk3-layershell v0.0.0-20240515133811-5c5115f0d774/go.mod h1:JHLx2Wz4mAPVwn4PFhC69ydwyHP4A3wQvlg7HKVVc1U= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= +github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= +github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0= +github.com/gek64/displayController v1.0.2 h1:xx1Um0aBResxS6eVjhEXU4U0LqjH723E9UPTDsC/j7M= +github.com/gek64/displayController v1.0.2/go.mod h1:N9v4SImJeiH2Ep/epdg2OvGPeRhqVRthu04WhhF/S6Q= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -36,8 +61,14 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56 h1:eR+xxC8qqKuPMTucZqaklBxLIT7/4L7dzhlwKMrDbj8= github.com/gotk3/gotk3 v0.6.5-0.20240618185848-ff349ae13f56/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= +github.com/itchyny/volume-go v0.2.2 h1:v+FX58TV+g/IelerseqMO1LmdRoIuSS2uB26Ggljzx0= +github.com/itchyny/volume-go v0.2.2/go.mod h1:0JOgisElMS/72B2DI4ha8CH2JXPUPTbe1agjk8jTU3s= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jfreymuth/pulse v0.1.1 h1:9WLNBNCijmtZ14ZJpatgJPu/NjwAl3TIKItSFnTh+9A= +github.com/jfreymuth/pulse v0.1.1/go.mod h1:cpYspI6YljhkUf1WLXLLDmeaaPFc3CnGLjDZf9dZ4no= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -45,6 +76,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/moutend/go-wca v0.2.0 h1:AEzY6ltC5zPCldKyMYdyXv3TaLqwxSW1TIradqNqRpU= +github.com/moutend/go-wca v0.2.0/go.mod h1:L/ka++dPvkHYz0UuQ/PIQ3aTuecoXOIM1RSAesh6RYU= +github.com/moutend/go-wca v0.3.0 h1:IzhsQ44zBzMdT42xlBjiLSVya9cPYOoKx9E+yXVhFo8= +github.com/moutend/go-wca v0.3.0/go.mod h1:7VrPO512jnjFGJ6rr+zOoCfiYjOHRPNfbttJuxAurcw= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -63,9 +102,19 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10= +golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -91,9 +140,15 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= +howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= diff --git a/images/logo-rs.png b/images/logo-rs.png new file mode 100644 index 0000000..2b2aa08 Binary files /dev/null and b/images/logo-rs.png differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000..2318084 Binary files /dev/null and b/images/logo.png differ diff --git a/images/pp.png b/images/pp.png new file mode 100644 index 0000000..28442d0 Binary files /dev/null and b/images/pp.png differ diff --git a/main.go b/main.go index 354e828..01d31d8 100644 --- a/main.go +++ b/main.go @@ -1,22 +1,19 @@ package main import ( - "fmt" "log" "os" - "sort" - "github.com/MiracleOS-Team/libxdg-go/desktopFiles" "github.com/gotk3/gotk3/gdk" "github.com/gotk3/gotk3/gtk" ) func loadCSS() { - // Load CSS into GTK provider, _ := gtk.CssProviderNew() //err = provider.LoadFromData(css) err := provider.LoadFromPath("/opt/miracleos-software/desktop/desktop.css") + //err := provider.LoadFromPath("desktop.css") if err != nil { log.Println("Failed to load CSS into GTK:", err) return @@ -58,40 +55,6 @@ func scalePixbuf(pixbuf *gdk.Pixbuf, maxWidth, maxHeight int) *gdk.Pixbuf { return scaledPixbuf } -func createAppGroup(apps []desktopFiles.DesktopFile) *gtk.Box { - group, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) - for _, app := range apps { - buttonBox, _ := gtk.ButtonNew() - appBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5) - sc, _ := appBox.GetStyleContext() - sc.AddClass("mm_applist_app") - - pixbuf, err := gdk.PixbufNewFromFile(app.Icon) // Replace with your image path - if err == nil { - // Define max size - maxWidth := 16 - maxHeight := 16 - - scaledPixbuf := scalePixbuf(pixbuf, maxWidth, maxHeight) - - icon, _ := gtk.ImageNewFromPixbuf(scaledPixbuf) - appBox.PackStart(icon, false, false, 5) - } - - label, _ := gtk.LabelNew(app.Name) - - appBox.PackStart(label, false, false, 5) - buttonBox.Add(appBox) - buttonBox.Connect("button-press-event", func() { - fmt.Println("Clicked on", app.Name) - go desktopFiles.ExecuteDesktopFile(app, []string{}, "") - }) - group.PackStart(buttonBox, false, false, 5) - - } - return group -} - func firstN(s string, n int) string { i := 0 for j := range s { @@ -103,185 +66,14 @@ func firstN(s string, n int) string { return s } -func createAppList() *gtk.ScrolledWindow { - scroll, _ := gtk.ScrolledWindowNew(nil, nil) - scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - vbox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) - - apps, _ := desktopFiles.ListAllApplications() - - categories := map[string][]desktopFiles.DesktopFile{} - - for _, app := range apps { - if _, ok := categories[firstN(app.Name, 1)]; !ok { - categories[firstN(app.Name, 1)] = []desktopFiles.DesktopFile{} - } - categories[firstN(app.Name, 1)] = append(categories[firstN(app.Name, 1)], app) - } - - // Sort categories alphabetically - sortedCategories := make([]string, 0, len(categories)) - for category := range categories { - sortedCategories = append(sortedCategories, category) - } - sort.Strings(sortedCategories) - - for _, category := range sortedCategories { - label, _ := gtk.LabelNew(category) - label.SetMarkup("" + category + "") - label.SetXAlign(0) - vbox.PackStart(label, false, false, 5) - - // Sort applications within each category - appList := categories[category] - sortedAppNames := make([]string, 0, len(appList)) - for _, app := range appList { - sortedAppNames = append(sortedAppNames, app.Name) - } - sort.Strings(sortedAppNames) - - sortedApps := make([]desktopFiles.DesktopFile, 0, len(appList)) - for _, appName := range sortedAppNames { - for _, app := range appList { - if app.Name == appName { - sortedApps = append(sortedApps, app) - } - } - } - - vbox.PackStart(createAppGroup(sortedApps), false, false, 5) - } - - scroll.Add(vbox) - return scroll -} - -func createUserInfo() *gtk.Box { - userBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) - userImage, _ := gtk.ImageNewFromFile("images/pp.png") - userLabel, _ := gtk.LabelNew("Abdi\nanonymous@gmail.com") - userLabel.SetXAlign(0) - userBox.PackStart(userImage, false, false, 5) - userBox.PackStart(userLabel, false, false, 5) - return userBox -} - -func createPowerButtons() *gtk.Box { - powerBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) - shutdownBtn, _ := gtk.ButtonNewWithLabel("Shutdown") - shutdownBtn.Connect("clicked", func() { - os.Exit(0) - }) - powerBox.PackEnd(shutdownBtn, false, false, 5) - return powerBox -} - -func createMainMenu() *gtk.Window { - win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) - win.SetTitle("Main Menu") - win.SetDefaultSize(600, 600) - win.SetDecorated(false) - win.Move(0, 0) - win.SetResizable(false) - win.SetTypeHint(gdk.WINDOW_TYPE_HINT_DOCK) - - screen, _ := gdk.ScreenGetDefault() - - // Get the primary monitor dimensions - rootWindow, _ := screen.GetRootWindow() - - rootWindow.WindowGetHeight() - - // Get the monitor width and height - monitorWidth := rootWindow.WindowGetWidth() - monitorHeight := rootWindow.WindowGetHeight() - - fmt.Println(monitorWidth) - fmt.Println(monitorHeight) - - // Calculate the center position - windowWidth, windowHeight := win.GetSize() - x := (monitorWidth - windowWidth) / 2 - y := (monitorHeight - windowHeight*2) - - fmt.Println(x) - fmt.Println(y) - win.Move(x, y) - - mainBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10) - sc, _ := mainBox.GetStyleContext() - sc.AddClass("mm_menu_m2") - - topBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) - sc, _ = topBox.GetStyleContext() - sc.AddClass("mm_toppart") - - searchEntry, _ := gtk.EntryNew() - searchEntry.SetPlaceholderText("Search Anything") - sc, _ = searchEntry.GetStyleContext() - sc.AddClass("mos-input") - searchEntry.SetHAlign(gtk.ALIGN_CENTER) - searchEntry.SetSizeRequest(100, -1) - topBox.PackStart(searchEntry, true, true, 5) - - contentBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) - - appList := createAppList() - sc, _ = appList.GetStyleContext() - sc.AddClass("mm_tab") - - fastApps := createPlaceholder("Most Used") - sc, _ = fastApps.GetStyleContext() - sc.AddClass("mm_tab") - - otherTab := createPlaceholder("Other") - sc, _ = otherTab.GetStyleContext() - sc.AddClass("mm_tab") - - appList.SetSizeRequest(300, 600) - fastApps.SetSizeRequest(300, 600) - otherTab.SetSizeRequest(300, 600) - - contentBox.PackStart(appList, false, false, 10) - contentBox.PackStart(fastApps, false, false, 10) - contentBox.PackStart(otherTab, false, false, 10) - - mainBox.PackStart(topBox, true, true, 10) - mainBox.PackStart(contentBox, true, true, 10) - - userInfo := createUserInfo() - sc, _ = userInfo.GetStyleContext() - sc.AddClass("mm_profileinfo") - - powerButtons := createPowerButtons() - sc, _ = userInfo.GetStyleContext() - sc.AddClass("mm_managingicons") - - bottomBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) - bottomBox.PackStart(userInfo, false, false, 10) - bottomBox.PackEnd(powerButtons, false, false, 10) - sc, _ = bottomBox.GetStyleContext() - sc.AddClass("mm_bottompart") - mainBox.PackStart(bottomBox, false, false, 10) - - win.Add(mainBox) - return win -} - -func createPlaceholder(name string) *gtk.Box { - box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10) - label, _ := gtk.LabelNew(name + "\nThis functionality isn't available for now") - box.PackStart(label, false, false, 10) - return box -} - func main() { gtk.Init(&os.Args) loadCSS() - win := createMainMenu() - win.Connect("destroy", func() { - gtk.MainQuit() - }) - win.ShowAll() + //win := createMainMenu() + //win.ShowAll() + + bar := createBar() + bar.ShowAll() + gtk.Main() } diff --git a/mainMenu.go b/mainMenu.go new file mode 100644 index 0000000..2e6aec6 --- /dev/null +++ b/mainMenu.go @@ -0,0 +1,208 @@ +package main + +import ( + "fmt" + "os" + "sort" + + "github.com/MiracleOS-Team/libxdg-go/desktopFiles" + "github.com/dlasky/gotk3-layershell/layershell" + "github.com/gotk3/gotk3/gdk" + "github.com/gotk3/gotk3/gtk" +) + +func createAppGroup(apps []desktopFiles.DesktopFile) *gtk.Box { + group, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) + for _, app := range apps { + buttonBox, _ := gtk.ButtonNew() + appBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5) + sc, _ := appBox.GetStyleContext() + sc.AddClass("mm_applist_app") + + pixbuf, err := gdk.PixbufNewFromFile(app.Icon) // Replace with your image path + if err == nil { + // Define max size + maxWidth := 16 + maxHeight := 16 + + scaledPixbuf := scalePixbuf(pixbuf, maxWidth, maxHeight) + + icon, _ := gtk.ImageNewFromPixbuf(scaledPixbuf) + appBox.PackStart(icon, false, false, 5) + } + + label, _ := gtk.LabelNew(app.Name) + + appBox.PackStart(label, false, false, 5) + buttonBox.Add(appBox) + buttonBox.Connect("button-press-event", func() { + fmt.Println("Clicked on", app.Name) + go desktopFiles.ExecuteDesktopFile(app, []string{}, "") + }) + group.PackStart(buttonBox, false, false, 5) + + } + return group +} + +func createAppList() *gtk.ScrolledWindow { + scroll, _ := gtk.ScrolledWindowNew(nil, nil) + scroll.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + vbox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) + + apps, _ := desktopFiles.ListAllApplications() + + categories := map[string][]desktopFiles.DesktopFile{} + + for _, app := range apps { + if _, ok := categories[firstN(app.Name, 1)]; !ok { + categories[firstN(app.Name, 1)] = []desktopFiles.DesktopFile{} + } + categories[firstN(app.Name, 1)] = append(categories[firstN(app.Name, 1)], app) + } + + // Sort categories alphabetically + sortedCategories := make([]string, 0, len(categories)) + for category := range categories { + sortedCategories = append(sortedCategories, category) + } + sort.Strings(sortedCategories) + + for _, category := range sortedCategories { + label, _ := gtk.LabelNew(category) + label.SetMarkup("" + category + "") + label.SetXAlign(0) + vbox.PackStart(label, false, false, 5) + + // Sort applications within each category + appList := categories[category] + sortedAppNames := make([]string, 0, len(appList)) + for _, app := range appList { + sortedAppNames = append(sortedAppNames, app.Name) + } + sort.Strings(sortedAppNames) + + sortedApps := make([]desktopFiles.DesktopFile, 0, len(appList)) + for _, appName := range sortedAppNames { + for _, app := range appList { + if app.Name == appName { + sortedApps = append(sortedApps, app) + } + } + } + + vbox.PackStart(createAppGroup(sortedApps), false, false, 5) + } + + scroll.Add(vbox) + return scroll +} + +func createUserInfo() *gtk.Box { + userBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + userImage, _ := gtk.ImageNewFromFile("images/pp.png") + userLabel, _ := gtk.LabelNew("Abdi\nanonymous@gmail.com") + userLabel.SetXAlign(0) + userBox.PackStart(userImage, false, false, 5) + userBox.PackStart(userLabel, false, false, 5) + return userBox +} + +func createPowerButtons() *gtk.Box { + powerBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + shutdownBtn, _ := gtk.ButtonNewWithLabel("Shutdown") + shutdownBtn.Connect("clicked", func() { + os.Exit(0) + }) + powerBox.PackEnd(shutdownBtn, false, false, 5) + return powerBox +} + +func createMainMenu() *gtk.Window { + win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) + win.SetTitle("Main Menu") + win.SetDefaultSize(600, 600) + win.SetDecorated(false) + win.SetResizable(false) + win.SetTypeHint(gdk.WINDOW_TYPE_HINT_DOCK) + + layershell.InitForWindow(win) + layershell.SetNamespace(win, "miracleos") + + layershell.SetAnchor(win, layershell.LAYER_SHELL_EDGE_BOTTOM, true) + + layershell.SetLayer(win, layershell.LAYER_SHELL_LAYER_OVERLAY) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_TOP, 0) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_LEFT, 0) + layershell.SetMargin(win, layershell.LAYER_SHELL_EDGE_RIGHT, 0) + + disp, _ := gdk.DisplayGetDefault() + mon, _ := disp.GetMonitor(0) + layershell.SetMonitor(win, mon) + + mainBox, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10) + sc, _ := mainBox.GetStyleContext() + sc.AddClass("mm_menu_m2") + + topBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + sc, _ = topBox.GetStyleContext() + sc.AddClass("mm_toppart") + + searchEntry, _ := gtk.EntryNew() + searchEntry.SetPlaceholderText("Search Anything") + sc, _ = searchEntry.GetStyleContext() + sc.AddClass("mos-input") + searchEntry.SetHAlign(gtk.ALIGN_CENTER) + searchEntry.SetSizeRequest(100, -1) + topBox.PackStart(searchEntry, true, true, 5) + + contentBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + + appList := createAppList() + sc, _ = appList.GetStyleContext() + sc.AddClass("mm_tab") + + fastApps := createPlaceholder("Most Used") + sc, _ = fastApps.GetStyleContext() + sc.AddClass("mm_tab") + + otherTab := createPlaceholder("Other") + sc, _ = otherTab.GetStyleContext() + sc.AddClass("mm_tab") + + appList.SetSizeRequest(300, 600) + fastApps.SetSizeRequest(300, 600) + otherTab.SetSizeRequest(300, 600) + + contentBox.PackStart(appList, false, false, 10) + contentBox.PackStart(fastApps, false, false, 10) + contentBox.PackStart(otherTab, false, false, 10) + + mainBox.PackStart(topBox, true, true, 10) + mainBox.PackStart(contentBox, true, true, 10) + + userInfo := createUserInfo() + sc, _ = userInfo.GetStyleContext() + sc.AddClass("mm_profileinfo") + + powerButtons := createPowerButtons() + sc, _ = userInfo.GetStyleContext() + sc.AddClass("mm_managingicons") + + bottomBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 10) + bottomBox.PackStart(userInfo, false, false, 10) + bottomBox.PackEnd(powerButtons, false, false, 10) + sc, _ = bottomBox.GetStyleContext() + sc.AddClass("mm_bottompart") + mainBox.PackStart(bottomBox, false, false, 10) + + win.Add(mainBox) + return win +} + +func createPlaceholder(name string) *gtk.Box { + box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 10) + label, _ := gtk.LabelNew(name + "\nThis functionality isn't available for now") + box.PackStart(label, false, false, 10) + return box +}