There seems to be a distinct lack of documentation of the GObjects module for python at the moment, so maybe somebody can help me.
I am making an application which occasionally will have to notify the user that an event has occurred. I have found about using from gi.repository import Notify and the relating classes from using a short snippet for skype notifications and the C documentation, but it seems to not close when I call Notify.uninit. The program closes, but the little notification window thing stays put and has to be closed by right clicking on it and selecting "Remove". So, I am wondering if there is perhaps another way like if there was something similar to how in Mac OS the application icon shakes/bounces when something happens or in Windows the application icon glowing a different color?
I like the Gnome 3 notification system with the message stack and such, but since I can't seem to get it to disappear when my application exits I don't really want to use it (unless someone knows how to properly do this...it may be that I forgot to set a timeout, but that still doesn't make sense as to why I can't just make the notification spot disappear).
Calling Notify.uninit is not supposed to make the notifications disappear, it only tells libnotify that it will no longer be needed for your application. To make notifications disappear, you have to close them explicitly like in the following example:
import time
from gi.repository import Notify
Notify.init('myapp')
# optionally set an icon as the last argument
n = Notify.Notification.new('summary text', 'body text', "dialog-information")
n.show()
# do whatever your application is doing
time.sleep(10)
n.close()
Notify.uninit()
Related
I am making application that controls a browser with SendKeys. But as SendKeys get the full control over the keyboard, I want to run this app under the different user. This way I will be working, the application will do what it have to do, and we will not make problems for each other).
The simplest code is
import time
import SendKeys
time.sleep(10)
SendKeys.SendKeys('hello')
I run it, focus on the field where I want to insert my text "hello", and wait. If I don't change the user, all is done as expected.
But when I run it, change the user and return after 10 seconds, I see that SendKeys sent nothing to the program.
How to send keystrokes to the program under the different user?
(I was trying to do the same with pywinauto, but the result was almost the same - all is good if I don't change the user, and error if I change it. So I thought that it is much simplier to resolve this problem with only SendKeys).
Just to summarize our discussion in comments and in the chat. Your wishes are very wide. I'm just trying to show you some directions to learn.
If you want to use SendKeys/TypeKeys/ClickInput methods (working as a real user), you need to run your automation script in the remote session, not locally. This is explained in details in my other answer: SetCursorPos fail with "the parameter is incorrect" after rdp session terminated.
If you want to run the automation on the same machine silently (in minimized state), there is an example for dealing with hidden windows: Python - Control window with pywinauto while the window is minimized or hidden. Just minimize the window and use silent methods (almost all except ClickInput and TypeKeys).
Feel free to ask more detailed questions about pywinauto and GUI automation.
I have a tkinter program written in python 3.3.3. I see myself in the need of making the the program get focus when the user unlocks the computer. I don't really know how to go ahead and start with this, users have a .exe version of the program that I created with cxfreeze. I f i need to modify the .py and create another .exe, that wouldn't be a problem.
After some research I found that one can use the ctypes module to lock the computer, but it's not very helpful because i need to know if it is locked or unlocked. I also saw commands from win32com, but i can't seem to be able to find a way to trigger a command when it gets unlocked.
What is the best way to get focus on my program after the computer is unlocked??
Any help is greatly appreciated.
I cannot answer this specifically for 'unlock' event (if there even is one in the GUI; I can't find one by cursory search.).
But I think the real answer is to change the question. Having a program simply take focus when user unlocks the display is very un-Windows-ish behavior. The Windows user expects to see the desktop just as s/he left it before the display was locked -- why does s/he want to see your program on top when unlocking, regardless of why Windows might have locked the display?
Maybe you want to recast your program as something that runs in the background and pops up a notification (in the notification area on the right side of toolbar) when it wants user to do something?
I have created a service which display a sort of splash screen on the desktop of a specific user and only when that user is logged in (kiosk user).
That splash screen, once entered a valid code, will tell that to the service and the service goes to sleep for an x amount of time (depending of the code).
The splash screen simply quits. Now when the service wakes up it sees that the splash is no longer there and so start it up.
This all is working, the only problem is that the launched application does not have focus, i.e. if I am working in notepad and the time is up, the splash screen is displayed (full screen though) behind notepad.
I only have to worry about Windows Vista, I am coding in Python using win32 extensions but I believe this problem lies in CreateProcessAsUser when called from the LocalSystem account.
Update:
The 'problem' is actually an on purpose limitation to prevent 'irritating' applications like mine from stealing focus.
You can change the behaviour by setting:
win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0)
which is equivalent in temporarily setting the registry value:
HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout
This must be done as the user itself, so either build it in the app you are launching or build an launching helper for the app you want to launch.
However an application might want to prevent getting it's focus stolen by using some API call which I don't remember right now.
A probably good solution would be to find all window handles currently from that user and then use each of these handles to use win32gui.ShowWindow(handle, command) to minimize it.
Although for this particular problem setting the locktimeout setting was enough.
If anyone wonders how I managed to launch an application to a desktop from a service, here is a link to the code.
Have you tried launching another processes than your own from the service to see if it gets focus? Like notepad and see if it steals focus from your browser? If so perhaps its the program that can take back the focus when it starts.
I otherwise beilive it's the wShowWindow attribute from the STARTUPINFO struct the lpStartupInfo points to that should control it. You also need STARTF_USESHOWWINDOW in dwFlags to use nShowWindow. The values should be SW_SHOW i think, they are listed for the ShowWindow function if you want to try other.
For various very legitimated reasons, Microsoft would rather not see a service launching an app and stealing focus, however I found the following work around to still accomplish what I want.
The original intend is to have a kiosk like application hindered by a pass code like splash screen, which upon entering a 8 character code closes the splash screen for a period time as in the pass code defined. Originally the actual application to use was started by the autostart folder.
However I now rewrote it that it is launched from my service, this way I can hide the application by launching an helper application from the service that just hides the program and launches the splash screen, upon exiting the splash screen the program is returned to the previous state.
I've created a very simple app, which presents an easygui entrybox() and continues to loop this indefinitely as it receives user input.
I can quit the program using the Cancel button as this returns None, but I would also like to be able to use the standard 'close' button to quit the program. (ie. top right of a Windows window, top left of a Mac window) This button currently does nothing.
Taking a look at the easygui module I found this line:
root.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
This would seem to be the culprit. I'm no TKinter expert but I could probably work out how to alter this handler to act the way I want.
However, as I'd rather not mess about with the easygui module, Is there a way to override this behavior from my main script, and have the close button either close the program outright or return None?
It would require altering the easygui module, yes. I will get it modified!
** I have sent in a e-mail to the EasyGUI creator explaning this [12:12 PM, January 23/09]
** I just want to say that the possibility of this change happening - if at all, which I doubt - is very tiny. You see, EasyGUI is intended to be a simple, discrete way to create GUIs. I think that this addition wouldn't help any, especially since the interface is very sequential, so it would be confusing to new users. [12:19 PM, January 23/09]
** The EasyGUI creator said this in reply to my e-mail:
An easygui dialog should never exit
the application -- it should pass back
a value to the caller and let the
caller decide what to do.
But this is an interesting idea.
Rather than simply ignoring a click on
the "close" icon, easygui boxes could
return the same value that a click on
the "cancel" button would return.
I'll meditate on this.
-- Steve Ferg
I think that this is progress at least. [2:40 PM, January 23/09]
I don't know right now, but have you tried something like this?:
root.protocol('WM_DELETE_WINDOW', self.quit)
or
root.protocol('WM_DELETE_WINDOW', self.destroy)
I haven't tried, but google something like "Tkinter protocol WM_DELETE_WINDOW"
I found a solution, the answer is below the choice box, when he defines some functions (you can just type to find denyWindowManagerClose) and go to where he defines it. Just erase it and put this code in its place.
def denyWindowManagerClose():
#------------------------------------------------------------------
# Changed by ProgrammingBR
# Enables the user to close the window without entering a value
# Youtube URL: https://www.youtube.com/channel/UCTZh6kWz_iYACNE6Jcy2lhw
#------------------------------------------------------------------
global __enterboxText
__enterboxText = None
boxRoot.quit()
You can create a backup file, but this will work for all boxes, the suggestions given here aside from this will not work, I tried the them. if you want to see I have a video on it (it is in Portuguese, but you can follow it) just go to the youtube channel, I will upload it soon and post the link here :)
How can I detect, or be notified, when windows is logging out in python?
Edit:
Martin v. Löwis' answer is good, and works for a full logout but it does not work for a 'fast user switching' event like pressing win+L which is what I really need it for.
Edit: im not using a gui this is running as a service
You can detect fast user switching events using the Terminal Services API, which you can access from Python using the win32ts module from pywin32. In a GUI application, call WTSRegisterSessionNotification to receive notification messages, WTSUnRegisterSessionNotification to stop receiving notifications, and handle the WM_WTSSESSION_CHANGE message in your window procedure.
If you're writing a Windows service in Python, use the RegisterServiceCtrlHandlerEx function to detect fast user switching events. This is available in the pywin32 library as the RegisterServiceCtrlHandler function in the servicemanager module. In your handler function, look for the SERVICE_CONTROL_SESSIONCHANGE notification. See also the WM_WTSSESSION_CHANGE documentation for details of the specific notification codes.
There's some more detail in this thread from the python-win32 mailing list, which may be useful.
I hope this helps!
In a console application, you can use win32api.SetConsoleCtrlHandler and look for CTRL_LOGOFF_EVENT. In a GUI application, you need a window open and wait for the WM_QUERYENDSESSION message. How precisely that works (and if it works at all) depends on your GUI library.