How to save an image to Gtk Clipboard without creating a window? - python

I am trying to take a pixbuf image and drop it into the user's clipboard for pasting into any program that accepts images. If I don't run Gtk.main(), nothing happens. If I do run Gtk.main(), it works, but the program never exits (I don't want to open a window).
# pixbuf is a pixbuf image
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
clipboard.set_image(pixbuf)
clipboard.store()
Gtk.main()

I have bad news, and I suggest you use something other than gtk to set the clipboard. I recommend trying something like wl-clipboard, xsel, or xclip. I am sure you know how to chose one or two of these and call it from a python script.
If you are looking for a gtk-only solution, I have spent quite some time on this and given up though I am not yet an expert in any of this.
The traditional solution is documented here:
https://github.com/bstpierre/gtk-examples/blob/master/c/clipboard_simple.c.
For reasons beyond my knowledge it doesn't currently work, but the comments at the bottom would be important in creating a gtk-only solution. The problem could be for a number of reasons including a bug in gtk or glibc. Or it might be part of a poorly explained migration to wayland.
Another potential solution is documented here: https://docs.gtk.org/gtk3/func.events_pending.html. This also doesn't work for unknown reasons.
The next avenues for testing are to test historical versions of linux distributions, and once the library version is found try to pinpoint the exact commit to the exact library and make a change. I made a decent effort to debug gtk, but it is not yet my area of expertise.
Even if the the change could be maid to facilitate one of the above solutions, it would be to much to ask for a version that works on wayland. Although xwayland may offer residual support and wl-clipboard offers a hack, any clipboard read or write requires a window and for your window to be focused as mentioned here: https://gitlab.gnome.org/GNOME/gtk/-/issues/1874. There seams to be some exeption for non-gnome wayland implied in this discussion: https://github.com/bugaevc/wl-clipboard/issues/90. Although I never found the offending part of the wayland standard, I expect that it is present.

Related

Selectively request root access for a piece of a (packaged) python .app

This problem involves the collision of several problems, all of which I understand only somewhat well, but I include them together because they could all be the entry point for a solution. Here is the best description I can give.
I have an app, in python. (I imagine I could theoretically solve all of these problems by learning Cocoa and ObjectiveC, but that seems like QUITE a lift, for this problem -- AND, as noted below, this problem may not actually be related to python, really, at all. I just don't know.) A CORE feature of this app is to trigger a minigame, with a hotkey -- meaning, the hotkey itself is fundamental to the desired functionality. And furthermore, I would really like to package this app, to let other people use it. (Locally, it works great! Hey!)
The problem starts with the fact that adding the hotkey -- which I am doing with
import keyboard
keyboard.add_hotkey('windows+shift+y', trigger_minigame)
-- requires root access. Due to DIRE WARNINGS in another SO post Forcing a GUI application to run as root (which, honestly, I only vaguely understand), I would like to grant that access to ONLY this part of the program. I IMAGINE, such an approach would look something like this:
# needs_root.py
import keyboard
from shouldnt_have_root import trigger_minigame
keyboard.add_hotkey('windows+shift+y', trigger_minigame)
# shouldnt_have_root.py
def minigame():
buncha pygame, GUI stuff (which is dangerous???)
def trigger_minigame():
adds event to minigame's event queue
# bash script
sudo python needs_root.py
HOWEVER -- there are several major challenges!
The biggest is that I don't even know if THAT is safe, since I don't know how security and permissions (especially with imports) works at all! And more generally, how dangerous are the imports? It appears that I may in fact have to import substantially more, to make it clear what event queue the trigger is adding an event TO -- and I don't know how to have that communication happen, while still isolating the GUI parts (or generally dangerous ones) from unnecessary and hazardous access.
There's another layer too though; packaging it through pyinstaller means that I can't target the scripts directly, because they'll have been turned into binaries, but according to THIS answer Packaging multiple scripts in PyInstaller it appears I can just target the binaries instead, i.e. have the first binary call
osascript -e 'do shell script "python needs_root_binary" with admin.'
to get the user to bless only the necessary part, but I don't know if that will put OTHER obstacles, or vulnerabilities (or inter-file communication difficulties), in the way.
LAST, I could try STARTING as root, and then switching away from it, as soon as the hotkey is set (and before anything else happens) -- but would that be safe? I'm still worried about the fact that it involves running sudo on the whole app.
In any event --
is this as big a mess as it feels?
How do I give root access to only a piece of a packaged .app, that I've written in python?
I'd advice You to:
enable the root access,
write the script,
disable the root access
as it's closer described in here.
The Pyinstaller is another chapter. When I was making software requiring usage of hotkeys, I was forced to use another than keyboard, because it wasn't working properly on PC without Python, therefore I made a hotkey with tkinter built-in function canvas.bind() (more info here).
Hopefully I helped.
You can not run a specific Python function as root, only the Python process executing your script can be run with elevated permissions.
So my answer is: your problem as described is unsolvable.

How do I get the active window on Gnome Wayland?

Background: I'm working on a piece of software called ActivityWatch that logs what you do on your computer. Basically an attempt at addressing some of the issues with: RescueTime, selfspy, arbtt, etc.
One of the core things we do is log information about the active window (class and title). In the past, this has been done using on Linux using xprop and now python-xlib without issue.
But now we have a problem: Wayland is on the rise, and as far as I can see Wayland has no notion of an active window. So my fear is that we will have to implement support for each and every desktop environment available for Wayland (assuming they'll provide the capability to get information about the active window at all).
Hopefully they'll eventually converge and have some common interface to get this done, but I'm not holding my breath...
I've been anticipating this issue. But today we got our first user request for Wayland support by an actual Wayland user. As larger distros are adopting Wayland as the default display server protocol (Fedora 25 is already using it, Ubuntu will switch in 17.10 which is coming soon) the situation is going to get more critical over time.
Relevant issues for ActivityWatch:
https://github.com/ActivityWatch/aw-watcher-window/issues/18
https://github.com/ActivityWatch/activitywatch/issues/92
There are other applications like ActivityWatch that would require the same functionality (RescueTime, arbtt, selfspy, etc.), they don't seem to support Wayland right now and I can't find any details about them planning to do so.
I'm now interested in implementing support for Gnome to start off with and follow up with others as the path becomes more clear.
A similar question concerning Weston has been asked here: get the list of active windows in wayland weston
Edit: I asked in #wayland on Freenode, got the following reply:
15:20:44 ErikBjare Hello everybody. I'm working on a piece of self-tracking software called ActivityWatch (https://github.com/ActivityWatch/activitywatch). I know this isn't exactly the right place to ask, but I was wondering if anyone knew anything about getting the active window in any Wayland-using DE.
15:20:57 ErikBjare Created a question on SO: https://stackoverflow.com/questions/45465016/how-do-i-get-the-active-window-on-gnome-wayland
15:21:25 ErikBjare Here's the issue in my repo for it: https://github.com/ActivityWatch/activitywatch/issues/92
15:22:54 ErikBjare There are a bunch of other applications that depend on it (RescueTime, selfspy, arbtt, ulogme, etc.) so they'd need it as well
15:24:23 blocage ErikBjare, in the core protocol you cannot know which windnow has the keyboard or cursor focus
15:24:39 blocage ErikBjare, in the wayland core protocol *
15:25:10 blocage ErikBjare, you can just know if your window has the focus or not, it a design choise
15:25:23 blocage avoid client spying each other
15:25:25 ErikBjare blocage: I'm aware, that's my reason for concern. I'm not saying it should be included or anything, but as it looks now every DE would need to implement it themselves if these kind of applications are to be supported
15:25:46 ErikBjare So wondering if anyone knew the teams working with Wayland on Gnome for example
15:26:11 ErikBjare But thanks for confirming
15:26:29 blocage ErikBjare, DE should create a custom extension, or use D-bus or other IPC
15:27:31 blocage ErikBjare, I guess some compositor are around here, but I do not know myself if there is such extension already
15:27:44 blocage compositor developers *
15:28:36 ErikBjare I don't think there is (I've done quite a bit of searching), so I guess I need to catch the attention of some DE developers
15:29:16 ErikBjare Thanks a lot though
15:29:42 ErikBjare blocage: Would you mind if I shared logs of our conversation in the issue?
15:30:05 blocage just use it :) it's public
15:30:19 ErikBjare ty :)
Edit 2: Filed an enhancement issue in the Gnome bugtracker.
tl;dr: How do I get the active window on Gnome when using Wayland?
The two previous answers are outdated, this is the current state of querying appnames and titles of windows in (Gnome) Wayland.
A Gnome-specific JavaScript API which can be accessed over DBus
The wlr-foreign-toplevel-management Wayland protocol (unfortunately not implemented by Gnome)
The Gnome-specific API will likely break between Gnome versions, but it works. It is heavily dependent on Gnome internal API to work so there is no chance of it becoming a standard API. There is a PR on aw-watcher-window to add this, but it needs some clean-up and afk-support if that's possible.
The wlr-foreign-toplevel-management protocol is (at the time of writing this) implemented by the Sway, Mir, Phosh and Wayfire compositors. Together with the idle.xml protocol which is pretty widely implemented by wayland compositors there's a complete implementation with afk-detection for ActivityWatch in aw-watcher-window-wayland. I've been in discussions with sway/rootston developers about whether wayland appnames and X11 wm_class is interchangeable and both Sway and Phosh use these interchangeably now so there should no longer be any distinguishable differences between Wayland and XWayland windows in the API anymore.
I have not researched if KWin has some API similar to Gnome Shell to fetch appnames and titles, but it does at least not implement wlr-foreign-toplevel-management.
In my opinion the best choice you have is not Wayland or any available library (there are not one). Actually who know in gnome-wayland about the active windows is Mutter, so you need to find a way to ask to Mutter the active windows. Gnome can develop an API to internally ask to mutter the active window and restore the functionality. But really, you don't have a place to ask for it. Mutter will not develop an API to access to his internal representation, because this will be pretty specific of Mutter only and not to all Wayland windows manager. So this need to be added to an external library, where this library could talk probably with the current window manager that it's in use to resolve your request in a general way.
Another possibility is add a Wayland plugin where all windows manager will have a way to share the current active windows and in some way a library to talk directly with wayland to restore the functionality.
So, your app is in a big problem. Most you can do is request this on mutter (where is know the active windows), but in my opinion it can not be resolved in Mutter.
I hope this will help you and you can find a way. Good luck.
https://stackoverflow.com/a/64030239/388010 has the correct answer. Nevertheless, here's the concrete and unsatisfying solution that implements option (1). The following works through a gnome extension using Gnome 43 at the time of writing (and perhaps will keep on working as long as the extension is maintained):
Install https://extensions.gnome.org/extension/4974/window-calls-extended/
Run gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/WindowsExt --method org.gnome.Shell.Extensions.WindowsExt.FocusPID | sed -E "s/\\('(.*)',\\)/\\1/g" to get the PID of the focus window or use a different method of WindowsExt.
I have a script called preguiça.py, that does exactly what you're doing, though it is probably a lot simpler and I haven't released it.
For my script, I acquired the window title using PyGObject's Window Navigator Construction Kit (Wnck).
Here's a simplified version of it, with the essencial parts:
from gi.repository import Wnck
from gi.repository import GObject
def changed (screen, window, data):
print ("Changed!")
# window = screen.get_active_window()
if window:
print ("Title: %s" % window.get_name())
screen = Wnck.Screen.get_default ()
screen.connect ("active-window-changed", changed, None)
mainLoop = GObject.MainLoop ()
try:
mainLoop.run ()
except KeyboardInterrupt:
print ("Hey")
mainLoop.unref ()
The actual code for what you're asking is actually commented out on the example above (I didn't need to capture the window, as the callback already receives it), but you may need it depending on your implementation.
I wrote it for X, and it didn't complain when I switched to Wayland, so it should probably work for you.
Note it doesn't get the information from Wayland, as you asked, but it is probably actually better, as it will be X/Wayland-agnostic. It got the title from an xterm I opened, so it should be toolkit-agnostic, as well.
Don't ask me on the details of the implementation, though. The code is at least four years old :)

Python GUI without 'video system'

I'm currently at a crossroads. I'm somewhat versed in Python (2.7) and would really like to start getting into GUI to give my (although mini) projects some more depth and versibility.
For the most part, my scripts don't use anything graphical so this is the first time I'm dipping my toes in this water.
That said, I've tried using pygame and tkinter but seem to fail at every turn to get something up and running (although I had some slight success with pygame)
Am I correct to understand that for both I need X started in order to generate any type of interface, and with that, so I need X to get any type of input (touchscreen presses)?
Thanks in advance!
In order to use tkinter, you must have a graphics system running. For Windows and OSX that simply means you need to be logged in (ie: can't run as a service). For linux and other unix-like systems that means that you must have X running.
Neither tkinter nor any of the other common GUI toolkits will write directly to the screen.
I'm gonna give an alternative answer. If you know HTML, CSS and Javascript (or have time to give it a try) I would recommend using Flask, http://flask.pocoo.org/.
With flask you can create websites but you can also (as I am using it) let it be your GUI. It will work on any device and looks really good :).

Why does Python's IDLE crash when I type a parenthesis on Mac?

Ok, I realize this may be an extremely nuanced question, but it has been bugging me for a while. I like the simple scripting interface of IDLE, but it keeps crashing on me when: (1) I am coding on an external monitor and (2) I type the parenthesis button, "(". IDLE never crashes for me for any other reason than this very specific situation. Strangely, if I have an external monitor connected, but I have the IDLE dev window on my laptop's main screen, I have ZERO problems with crashing. (???) I have lost a substantial amount of code due to this problem.
I am running on Mac OSX Version 10.11.3 and I have a MacBook Pro (Retina, 15-inch, Mid 2015) Any thoughts would be appreciated!
Ok, answering my own question. Per the recomendation of Андрей, I reviewed the notes and comments here: http://bugs.python.org/issue16177 I did some experimentation and figured out a work-around to avoid this problem. The problem only occurs when you are coding in an external monitor AND when the "Arrangement" of the external monitor is set as being higher (or elevated) relative to the primary monitor. Specifically, it occurs when the IDLE development window is totally or near-totally in a space on the secondary screen that would be considered "North" of the top edge of the primary screen. Thus, the patch is to reconfigure your "Arrangement" settings on your Mac so that the monitors are systematically aligned in a near-horizontal fashion. This may make things feel less natural, but it will fix the problem. That being said, I have no idea what the root cause of the problem is. I'm just glad to finally have this figured out. Hope this helps at least one other person.
I found a fix! One that doesn't require changing monitor settings.
In IDLE:
Options Menu > Configure Extensions > CallTips > set to FALSE
Then restart.
Took much research to find that super simple solution... the problem is caused not by an error in IDLE but by an error in the mac's Tcl/Tk code when calltips are called in external monitors above the default monitor.
Typing '(' after a function name should bring up a calltip giving the signature of the function if the function is currently known. Functions can be made known by occasionally running your code. We recentlyly discovered that some combinations of Mac OSX or MacOS and tcl/tk require an addition of one line to idlelib/calltip_w.py (3.6+) or idlelib/CallTipWindow.py (3.5-). Issue 34275
self.label.pack() # Line 74
tw.update_idletasks() # ADD THIS LINE!
tw.lift()
Without this, the calltip does not appear. I don't know if this also prevents any of the crashes that people have reported. If the above does not work, please remove _idletasks and let me know in a comment.

Replacing Functionality of PIL (ImageDraw) in Google App Engine (GAE)

So, Google App Engine doesn't look like it's going to include the Python Imaging Library anytime soon. There is an images api, but it's paltry, and inadequate for what I need.
I'm wondering what Python only (no C-extensions) there are that can replace the Image.paste and the ImageDraw modules. I don't want to write them myself, but that is an option. I'm also open to other solutions, such as "do the processing somewhere else, then call via api", if they're not too ugly. (For the record, the solution I just suggested seems pretty ugly to me.)
How have others gotten around this?
(I'm not wedded to GAE, just exploring, and this looks like a deal breaker for my app.)
Notes:
For me, crop, resize is not enough. In particular I need
paste (replace part of an image with another.... can be faked with "compose")
draw (for drawing gridlines, etc. Can be faked as well)
text (write text on an image, much harder to fake, unless someone wants to correct me)
My skimpygimpy.sourceforge.net will do drawing and text, but it won't edit existing images (but it could be modified for that, of course, if you want to dive in). It is pure python. see it working on google apps, for example at
http://piopio.appspot.com/W1200_1400.stdMiddleware#Header51,
That's an experimental site that I'll be messing with. The link may not work forever.
Your assumption is wrong. If you use the Python 2.7 runtime, you can use PIL (version 1.1.7) as documented here: https://developers.google.com/appengine/docs/python/tools/libraries27.
This article also explains how to enable PIL for your app.
BTW, the last comment in the bug you referenced also mentions it.
I don't know if it has all features you want, but I have been messing with PNGCanvas, and it does some things I have done before with PIL
Now according to this ticket "On the Python 2.7 runtime, you can import PIL and use it directly. It's the real PIL, not a wrapper around the images API."

Categories

Resources