matryer / xbar

Put the output from any script or program into your macOS Menu Bar (the BitBar reboot)
https://xbarapp.com
MIT License
17.59k stars 642 forks source link

Add support Windows and Linux #691

Open hmsjy2017 opened 3 years ago

hmsjy2017 commented 3 years ago

xbar is a good software. I want to use it in other platforms. This software is written in Go, so I think it will not be too difficult to support Windows and Linux. Thank you.

xfangfang commented 3 years ago

I have used this in Linux.

More precisely, Argos is a GNOME Shell extension that turns executables' standard output into panel dropdown menus. It is inspired by, and fully compatible with, the BitBar app for macOS. Argos supports many BitBar plugins without modifications, giving you access to a large library of well-tested scripts in addition to being able to write your own.

https://github.com/p-e-w/argos

dAnjou commented 3 years ago

This software is written in Go, so I think it will not be too difficult to support Windows and Linux.

That's a wrong assumption. The programming language itself is rarely the reason for something to work or not work on certain platforms as there is hardly any popular language that doesn't work on all major platforms.

The reason why GUI applications are harder to port to other platforms is usually because of their GUI toolkits, desktop environments, and often other intricacies of the underlying operating systems. And even though xbar is built using Wails which theoretically allows you to build cross-platform GUI applications that's usually only easy for quite simple windowed applications. As soon as you enter deeper territory of the desktop environment, like docks and menu bars, it becomes more difficult.

So, while adding support for more desktop environments directly to xbar could theoretically be possible it would also add a lot of maintenance overhead. Things would have to be tested and kept up-to-date with all target platforms which are evolving as well. That would take quite some bandwidth away from developling actual features.

That is why I personally would be a big fan of a different approach.

The thing that makes xbar (and BitBar before) so great is the simple protocol between plugins and xbar's UI. This should be somehow formalized and versioned, and maybe even extracted into some kind of library or CLI tool, so that a desktop environment specific UI can be built on top of it.

Argos (as mentioned by @xfangfang) kinda already does this but only loosely and I don't think that there's a formalized or even automatable way for it to ensure compatibility.

matryer commented 3 years ago

The Wails project (the tech that allows us to build the xbar UI and to control the menus) is indeed cross-platform, so when Wails v2 is released, we do expect to be able to build xbar for other operating systems. @dAnjou does raise some good points.

leaanthony commented 3 years ago

@dAnjou does raise good points and full compatibility cross platform is a lofty goal, however not unachievable. For instance, Linux is hard to support as gnome dropped support for system trays but you can hack around it using libappindicator, etc. I'm not even sure you can get text into a windows tray icon.

hmsjy2017 commented 3 years ago

I think it might be possible to use OpenSwiftUI instead of SwiftUI on Windows and Linux platforms. https://github.com/Cosmo/OpenSwiftUI

matryer commented 3 years ago

@leaanthony One option is just to build a new UI that looks and works like menus for cases where traditional menu bars are unavailable. @hmsjy2017 we use Wails, not SwiftUI.

K1ngjulien commented 3 years ago

I'm not even sure you can get text into a windows tray icon.

On windows It should be possible to somehow create a "toolbar" to do this. Lenovo usually has something like this to show the battery percentage preinstalled on their laptops (for some reason). Here's a screenshot i found:

image

Unfortunately, after half an hour of googling about "windows taskbar toolbars" i was no closer to finding the underlying api which allows you to do this. But I am sure there are windows development wizards out there that could help if this turns into a serious effort 😄

xfangfang commented 3 years ago

@K1ngjulien pystray can do this on windows

https://github.com/moses-palmer/pystray/blob/master/lib/pystray/_win32.py

laher commented 3 years ago

I'd really like to see this, it would be really useful to be able to share custom xbar plugins with non-Mac users. e.g. in my team we have all 3 of these OSes represented within the team.

I figure there's 2 parts to this:

The app

For the most part the xbar code seems pretty cross-platform friendly. I managed to get it to compile & run on linux with just a little refactoring. But sadly, no system tray icon appeared, because ...

Wails un-readiness

Wails itself (v2) doesn't currently support system tray (or much else) on linux or windows ... They have begun ports to windows and linux, but it looks like they're doing one after the other and progress is slow. It might take years to get systray parity with the mac support ... They mention their roadmaps here: https://github.com/wailsapp/wails/issues/661

Alternatives?

I'm not sure if you're aware but https://github.com/getlantern/systray is a decent & workable system tray library in go. I've used it in Mac and Linux happily... There's one awkward limitation though, it only supports a single icon per process. Possibly because of some specific per-os limitations, I don't know the rationale.

I'm going to assume it would be really gross to try to crowbar this library it into xbar instead of wails. I mean, systray does integrate with a webview component but I just figure it'd be a big change for an app which is already working nicely for a lot of folks...

A fork/clone?

I'm tempted to build a compatible xbar clone with getlantern/systray (managing multiple processes to get multiple icons). If argos can do it in js then why not try it in another Go app ...

But really, it'd be nice not to fork/clone the app. It's preferable not to fragment an ecosystem, but I don't have the appetite to work on the C parts of Wails myself...

Any thoughts on how to go about this while playing nicely with the xbar community?


The plugin repo

It would still be good for the plugin repo to be cross-platform, even while the xbar app isn't. By that I think I'm just talking about marking and filtering plugins by OS.

xbar.os?

So, I figure it would be good to define some per-OS tagging support to the plugin system, and to have xbar's plugin browser respect those labels... xbar already defines plugin metadata fields ...

Probably this warrants its own ticket, but I'm just airing it here first...

Cheers

leaanthony commented 3 years ago

There are a number of technical reasons why this is hard, and you list some. The fact that there are libraries to do some of the work doesn't get around the fact that for a gui application, you have the problem of who owns the main event loop.

Despite these technical issues, the biggest issue with making xbar cross platform IMHO is that the concept of system trays on both Linux and Windows do not have parity with MacOS. The main difference being that they do not show text next to them. There doesn't seem to be any good solution to this other than to mimic the functionality with hacks that are a support concern, especially on Linux.

No matter what libraries you use, this disparity is still a core issue. Do you have any thoughts on a good solution?

laher commented 3 years ago

Hi, fair point that Windows can't support text in the systray. The getlantern/systray docs confirm that 'set title' takes no effect in Windows, but it shows text just fine in Linux (it uses libappindicator; I've used it with gnome shell)

... For my use case this one thing isn't a deal breaker... I'm hoping that a first line of mytitle | icon=x.png could hypothetically be used to indicate a systray icon?

... I'd be happy to use icons for the plugins I have in mind, and I think it's OK generally - assuming the possibility to mark some plugins as 'unsupported' on a per-OS basis, and then a plugin author would need some guidance in order to support multiple platforms ....

Are there any other platform-related obstacles you're aware of?

...

you have the problem of who owns the main event loop.

Sorry, I don't understand how this relates to the cross-platform thing.

leaanthony commented 3 years ago

The libraries you mentioned all have a Run function that owns the main event loop.

laher commented 3 years ago

right, and xbar currently owns that loop? OK. Yeah my experiment with getlantern/systray lib is presenting each icon in a separate process and attempting some IPC (not very well as yet)... I don't know specifically why the library works this way but I'm just running with it.

You asked if I had any ideas for cross-platform support... Mainly I have just notes about obstacles and weird workarounds. Maybe some of these are helpful, maybe not ...

Icons vs text for the tray item

Icons vs text - as you say we'd need an alternative for platforms with icon-only tray items, and I haven't thought of anything amazing ...

Refreshing the tray

Generally refreshing works fine in each platform, but with there's some challenges with the specific library I'm using ...

Authoring plugins for cross-platform

I feel like it would be really challenging for someone to write a plugin and feel confident it was ready for cross-platform use. Little differences would trip people up IMO... But also dependency management. It'd be hard for someone to say 'well if you're on windwos then you need to install bash, oh and on mac the grep binary needs to be from gnu... etc'

OS integration ...

zebroc commented 2 years ago

Wails 2.0 was released yesterday: https://wails.io/blog/wails-v2-released/

K1ngjulien commented 2 years ago

Wails 2.0 was released yesterday: https://wails.io/blog/wails-v2-released/

Last, but not least, a huge thank you to Mat Ryer who has provided advice and support during the development of v2. Writing xBar together using an early Alpha of v2 was helpful in shaping the direction of v2, as well as give me an understanding of some design flaws in the early releases. I'm happy to announce that as of today, we will start to port xBar to Wails v2, and it will become the flagship application for the project. Cheers Mat!

That's Awesome!

sansar-choinyambuu commented 2 years ago

@matryer do you have an estimate when the ported xBar on Wails v2 could be released?

nafg commented 1 year ago

Is there anything for windows that exists that is at all similar to xbar?

leaanthony commented 1 year ago

The issue is that tray icons don't support text. Would you run it if it created a bar at the top of the screen permanently? Or maybe there's a better UI?

nafg commented 1 year ago

If it was auto-hide, maybe

On Tue Jan 24, 2023, 08:03 AM GMT, Lea Anthony @.***> wrote:

The issue is that tray icons don't support text. Would you run it if it created a bar at the top of the screen permanently? Or maybe there's a better UI? — Reply to this email directly, view it on GitHub https://github.com/matryer/xbar/issues/691#issuecomment-1401519378, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAYAUAII6TO5SMUS55QPLDWT6EEZANCNFSM42M6X5WA. You are receiving this because you commented.Message ID: @.***>

gedw99 commented 1 year ago

I am using this on all desktops

https://pkg.go.dev/fyne.io/systray

works well and designed for extensibility

—-

Good example that’s like xbar ?

https://github.com/wobsoriano/systray-portable

leaanthony commented 1 year ago

Most plugins output text, and are updated multiple times a minute. Doesn't systray use bubble notifications on windows? So that would mean having a continuous stream of bubble notifications from all enabled plugins?

gedw99 commented 1 year ago

hey

screenshot:

(https://raw.githubusercontent.com/fyne-io/systray/master/example/screenshot.png)

i don’t have windows to test on though

leaanthony commented 1 year ago

Yeah Linux isn't a problem (apart from the shambles of whether the user will need to install a shared lib or not as it isn't standard)... It's Windows that has no concept of text next to the tray icon

gedw99 commented 1 year ago

Can someone run this on windows maybe. I would like to see what it looks like :) Sorry but just don’t have windows machine.

gedw99 commented 1 year ago

Yeah Linux isn't a problem (apart from the shambles of whether the user will need to install a shared lib or not as it isn't standard)... It's Windows that has no concept of text next to the tray icon

Fyne has installers and updaters. We can try them

line 7 and 8:

https://github.com/fynelabs/iot-blog-example/blob/main/go.mod

mkilinskidev commented 11 months ago

Hey. Is there any update in this case? It would be great to have xbar on Windows 🥰

leaanthony commented 11 months ago

We would love to do that but what would it look like? Tray menus on windows do not support text so it wouldn't be a 1:1 port. Would it be a bar at the top? Same for Linux.

mkilinskidev commented 11 months ago

We would love to do that but what would it look like? Tray menus on windows do not support text so it wouldn't be a 1:1 port. Would it be a bar at the top? Same for Linux.

As mentioned above, there is a systray package that allow to create an icon in the tray menu, but it doesn't support refreshing menu itself. I guess that it wouldn't be a 1:1 port because yesterday I studied the wails 2.7 package and there are a lot of differences, so probably it should be a new repository calls I don't know... wbar maybe...

mkilinskidev commented 11 months ago

Now I noticed that there is a v3-alpha version available of the Wails and there is a new systray package (https://v3alpha.wails.io/whats-new/#systrays) I will try to write something using v3-alpha version for fun :)

image

mkilinskidev commented 11 months ago

OK, I know that the code is not perfect and it should be refactored, but it is a prototype :) Because I used the xbar mostly for the Jira issues counter, inspired by the python Jira plugin, I've made a simple app with a dynamically generated icon tray icon and issue list.

package main

import (
    "bytes"
    _ "embed"
    "fmt"
    "image"
    "image/png"
    "log"
    "strings"
    "time"

    jira "github.com/andygrunwald/go-jira"
    "github.com/fogleman/gg"
    "github.com/wailsapp/wails/v3/pkg/application"
)

type JIRAAuth struct {
    juser  string
    jtoken string
    jql    string
    uri    string
}

func generateIcon(number int) []byte {
    const size = 16
    dc := gg.NewContext(size, size)

    dc.SetRGB(0, 0, 0)
    dc.Clear()

    dc.SetRGB(1, 1, 1)
    dc.DrawStringAnchored(fmt.Sprintf("%d", number), size/2, size/2, 0.5, 0.5)

    var img image.Image = dc.Image()
    result := new(bytes.Buffer)
    png.Encode(result, img)

    return result.Bytes()
}

func FetchJIRAIssues(JIRA JIRAAuth) *[]jira.Issue {
    tp := jira.BasicAuthTransport{
        Username: JIRA.juser,
        Password: JIRA.jtoken,
    }
    jiraClient, err := jira.NewClient(tp.Client(), JIRA.uri)

    opt := jira.SearchOptions{
        MaxResults: 20,
        Expand:     "summary,issuetype,status,assignee,project",
    }

    issues, _, err := jiraClient.Issue.Search(JIRA.jql, &opt)
    if err != nil {
        log.Fatal(err)
    }

    return &issues
}

func GenerateMenu(app *application.App, systemTray *application.SystemTray, issueTypes []string, JIRA JIRAAuth) int {
    myMenu := app.NewMenu()
    issues := FetchJIRAIssues(JIRA)
    var added bool

    for _, issueType := range issueTypes {
        added = false

        for _, issue := range *issues {
            if strings.ToUpper(issue.Fields.Status.Name) == strings.ToUpper(issueType) {
                if added == false {
                    myMenu.Add(issueType).SetEnabled(false)
                    added = true
                }

                label := fmt.Sprintf("[%s] %s", issue.Key, issue.Fields.Summary)
                myMenu.Add(label).
                    SetTooltip(issue.Key).
                    OnClick(func(ctx *application.Context) {
                        app.BrowserOpenURL(fmt.Sprintf("%s/browse/%s", JIRA.uri, ctx.ClickedMenuItem().Tooltip()))
                    })
            }
        }
    }

    myMenu.AddSeparator()
    myMenu.Add("Go to JIRA Issues").OnClick(func(ctx *application.Context) {
        app.BrowserOpenURL(fmt.Sprintf("%s/issues/?jql=%s", JIRA.uri, JIRA.jql))
    })
    myMenu.Add("Quit").OnClick(func(ctx *application.Context) {
        app.Quit()
    })
    systemTray.SetMenu(myMenu)

    return len(*issues)
}

func main() {
    app := application.New(application.Options{
        Name:        "JIRA Issue Counter",
        Description: "A demo of the Wails v3 API",
        Assets:      application.AlphaAssets,
        Mac: application.MacOptions{
            ActivationPolicy: application.ActivationPolicyAccessory,
        },
    })
    JIRA := JIRAAuth{
        juser:  "username@mail.com",
        jtoken: "jira_ptoken",
        jql:    "assignee = currentUser() ORDER BY created DESC",
        uri:    "https://yourcompany.atlassian.net",
    }
    systemTray := app.NewSystemTray()

    var issueTypes []string
    issueTypes = append(issueTypes, "New")
    issueTypes = append(issueTypes, "In Progress")
    // issueTypes = append(issueTypes, "Oczekuje na odpowiedź klienta")
    // issueTypes = append(issueTypes, "Odpowiedź od klienta")
    // issueTypes = append(issueTypes, "Wstrzymane")

    go func() {
        for {
            cnt := GenerateMenu(app, systemTray, issueTypes, JIRA)
            systemTray.SetDarkModeIcon(generateIcon(cnt))

            time.Sleep(60 * time.Second)
        }
    }()

    err := app.Run()
    if err != nil {
        log.Fatal(err)
    }

}

image

So yes, it is possible, the wbar will have few limitations, f.ex. it is not possible to put into Windows tray a long text, but it works :)

p3ddd commented 5 months ago

I'm not even sure you can get text into a windows tray icon.

On windows It should be possible to somehow create a "toolbar" to do this. Lenovo usually has something like this to show the battery percentage preinstalled on their laptops (for some reason). Here's a screenshot i found:

image

Unfortunately, after half an hour of googling about "windows taskbar toolbars" i was no closer to finding the underlying api which allows you to do this. But I am sure there are windows development wizards out there that could help if this turns into a serious effort 😄

There's a tool called Traffic Monitor can do this.

image

But its wrote with c, the method is a bit hack. It seems to create a transparent and borderless window as a child window of explorer.exe.

leaanthony commented 5 months ago

But its wrote with c, the method is a bit hack. It seems to create a transparent and borderless window as a child window of explorer.exe.

Oh wow. I wonder what it looks like if you fill the taskbar with icons or move it to be vertical 😬