Using GTK and Xlib in Python - python

I am writing some code where I need to drop down from GTK+ to Xlib. Specifically, I would like to set the icon of a toplevel window to be a window itself, rather than a pixmap, in order to write a GTK+ Window Maker dockapp.
I got this to work in C as follows:
gdkDockapp = gtk_widget_get_window(dockapp);
xDockapp = GDK_WINDOW_XID(gdkDockapp);
gdkDisplay = gdk_window_get_display(gdkDockapp);
xDisplay = GDK_DISPLAY_XDISPLAY(gdkDisplay);
wmhints.icon_window = xDockapp;
wmhints.flags = IconWindowHint;
XSetWMHints(xDisplay, xDockapp, &wmhints);
However, I am hoping to actually code my application in Python. When I try to convert the code, e.g.,
gdkDockapp = dockapp.get_window()
xDockapp = gdkDockapp.get_xid()
a long is returned rather than a Window, so I can't perform any of the Xlib functions. Any suggestions?

You can get Xlib.Display.Window object with this function: d.create_resource_object("window", xid), where d is Xlib.display.Display object.

Not sure using Xlib is a wise move in times where the X server is meant to disappear in favor of a Wayland compositor.

Related

What is the non-deprecated way to display a stock icon in GTK3?

I'm assembling a GUI using PyGObject. This Python code works in context. I get a toolbar button with the stock "Open" icon.
from gi.repository import Gtk
# ...
toolbar = Gtk.Toolbar()
toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
# ...
self.fileOpen = Gtk.ToolButton.new_from_stock(Gtk.STOCK_OPEN)
self.fileOpen.connect("clicked", self.on_FileOpenStandard_activate)
toolbar.insert(self.fileOpen, -1)
But according to this resource, new_from_stock() is deprecated:
Deprecated since version 3.10: Use Gtk.ToolButton.new () together with Gtk.Image.new_from_icon_name () instead.
Okay then. So after digging further, this is what I came up with for a replacement:
self.fileOpen = Gtk.ToolButton(
Gtk.Image.new_from_icon_name("document-open",
Gtk.IconSize.LARGE_TOOLBAR),
"Open")
self.fileOpen.connect("clicked", self.on_FileOpenStandard_activate)
toolbar.insert(self.fileOpen, -1)
But this is the result:
What is the correct way to do this that is still supported by the current GTK library?
Looking at this C++ GitHub example, I'm surprised to discover a direct call to the static new() function rather than the constructor.
So I decided to try it. Look carefully at the difference. It's subtle.
#vvv
self.fileOpen = Gtk.ToolButton.new(
Gtk.Image.new_from_icon_name("document-open",
Gtk.IconSize.LARGE_TOOLBAR),
"Open")
self.fileOpen.connect("clicked", self.on_FileOpenStandard_activate)
toolbar.insert(self.fileOpen, -1)
To my surprise, this displays the icon where the other approach does not.
Bonus: Cleaner version of the above:
# iconSize to be reused
iconSize = Gtk.IconSize.LARGE_TOOLBAR
# ...
openIcon = Gtk.Image.new_from_icon_name("document-open", iconSize)
self.fileOpen = Gtk.ToolButton.new(openIcon, "Open")
self.fileOpen.connect("clicked", self.on_FileOpenStandard_activate)
toolbar.insert(self.fileOpen, -1)

cget('image') method returning pyimage1 instead of the image name

I'm new to programming and I'm attempting to create an application using tkinter from python 3.3. In this application I'm using buttons containing images and I want to perform actions that depend on the kind of image that the buttons are containing. This is a simplified version of my program:
from tkinter import *
master=Tk()
c_black = PhotoImage(file="c_black.gif")
b=Button(master, image=c_black)
print(b.cget('image'))
master.mainloop()
Instead of
c_black
the console returns
pyimage1
And I have no idea why. I've been trying to figure it out for hours now. Perhaps there's a way to do it differently?
With cget() you can only retrieve the property as a string, so you need to store the reference to the PhotoImage object:
b = Button(...)
b.image = c_black
print(b.image.cget('file'))

wx.ListBox.HitTest not working on Mac

The following code sample works under linux (ubuntu) and Windows XP, but not under OSX.
import wx
class frame(wx.Frame):
def __init__(self,p=None):
wx.Frame.__init__(self,p)
self.box = wx.ListBox(self)
self.box.AppendItems( ["Zero","One","Two","Three","Four","Five","Six"])
self.box.Bind(wx.EVT_MOUSE_EVENTS,self.onMouse)
def onMouse(self,evt):
pos = evt.GetPosition()
print self.box.HitTest(pos)
evt.Skip()
class guiApp(wx.App):
def __init__(self,redirect=False):
wx.App.__init__(self,redirect)
def OnInit(self):
f = frame()
f.Show()
self.SetTopWindow(f)
return True
if __name__=="__main__":
app = guiApp()
app.MainLoop()
On Linux and Windows, the correct items are identified when moused over. On OSX hittest always returns -1 (wx.NOT_FOUND)
I'm running 32-bit wxPython, 2.8.12.1 (mac-unicode) which uses the Carbon API in 32bit python 2.7.2.
I can't find this listed as a known bug in wxWidgets and I'm hesitant to submit as it seems this should work. The listbox control is deeply integrated into out GUI and I really don't want to swap it out for ListCtrl or something similar as we have all other functionality working now. Does anyone know a workaround?
There is no work around if the listbox is scrolling. The scroll is handled be the underlying Carbon library and scroll position is not accurately reported back through wx.
I found the bug in the wxWidgets source code and opened a ticket on the wxWidgets trac, http://trac.wxwidgets.org/ticket/13699, with a patch.
The root of the bug is a call to the Mac's underlying DataBrowser with an incorrect rowId argument. wxWidgets was passing row position offsets, assuming this would be the rowId's (and maybe at some point apple used these internally when true Id's weren't specified.) Adding a call to another function translates a row's position (offset) into it's real id. With a patched version of wxWidgets the above script works as expected.

Simple Hotkey Script in Python - How to set a global hotkey to send a string of text?

I was wondering how I could use wxPython along with the win32apis to create a simple script that will activate a window (if it is not already active) with a certain title and output text (keystrokes). One possible application for this would be keyboard shortcuts in gaming. I have read up on the wxPython RegisterHotKey(), but- as an amateur Python programmer- it is unclear to me.
The basic structure of the script will be:
Define the hotkey (something like win+F_)
Watch for the hotkey keystroke
See if the desired window (title) is already active, and activate it if it isn't
Simulate the typing of some text
I know there are simpler methods to accomplish this (such as AutoHotkey), but I feel more comfortable using something I have written myself and have taken an interest in Python.
Thanks!
For the record, I am using Python 2.7 on Windows 7 AMD64, though I doubt that the interpreter version/platform/architecture makes much of a difference here.
Are you talking about activating a window that you created in wx or a separate application, like notepad? If it's with wx, then it's trivial. You'd just use Raise() to bring whatever frame you need into focus. You would probably use PubSub or PostEvent to let the sub-frame know that it needs to Raise.
If you're talking about notepad, then things get much stickier. Here's an ugly hack I created based on some stuff I got from various locations on the web and the PyWin32 mailing list:
def windowEnumerationHandler(self, hwnd, resultList):
'''
This is a handler to be passed to win32gui.EnumWindows() to generate
a list of (window handle, window text) tuples.
'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
def bringToFront(self, windowText):
'''
Method to look for an open window that has a title that
matches the passed in text. If found, it will proceed to
attempt to make that window the Foreground Window.
'''
secondsPassed = 0
while secondsPassed <= 5:
# sleep one second to give the window time to appear
wx.Sleep(1)
print 'bringing to front'
topWindows = []
# pass in an empty list to be filled
# somehow this call returns the list with the same variable name
win32gui.EnumWindows(self.windowEnumerationHandler, topWindows)
print len(topWindows)
# loop through windows and find the one we want
for i in topWindows:
if windowText in i[1]:
print i[1]
win32gui.ShowWindow(i[0],5)
win32gui.SetForegroundWindow(i[0])
# loop for 5-10 seconds, then break or raise
handle = win32gui.GetForegroundWindow()
if windowText in win32gui.GetWindowText(handle):
break
else:
# increment counter and loop again
secondsPassed += 1
Then I used the SendKeys package to send text to the window (see http://www.rutherfurd.net/python/sendkeys/). If the user opens anything else, the script will break or weird things will happen. If you open something like MS Office, use win32com instead of SendKeys. That's much more reliable.

How do I take out the focus or minimize a window with Python?

I need to get focus to a specified window, and the only way I'm seeing on my head, is minimizing all windows on front of it until I get the right one...
How can I do it?
Windows 7, and no specific toolkit....
Every type of window, for example, firefox and console command
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus:
import win32gui
toplist = []
winlist = []
def enum_callback(hwnd, results):
winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
win32gui.EnumWindows(enum_callback, toplist)
firefox = [(hwnd, title) for hwnd, title in winlist if 'firefox' in title.lower()]
# just grab the first window that matches
firefox = firefox[0]
# use the window handle to set focus
win32gui.SetForegroundWindow(firefox[0])
To minimize the window, the following line:
import win32con
win32gui.ShowWindow(firefox[0], win32con.SW_MINIMIZE)
You'll need to enumerate through the windows and match the title of the window to get the one you want. The code below searches for a window with "firefox" in the title and sets the focus
To minimize the window use the following line:
def enumHandler(hwnd, lParam):
if 'firefox' in win32gui.GetWindowText(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
win32gui.EnumWindows(enumHandler, None)
This works for Windows 10, Python3.5 32bit, pywin32‑223.
I reported the above case, but an error occurred.
Traceback (most recent call last):
TypeError: The object is not a PyHANDLE object
I'm assuming from the question, that you want to write a generic to that can work with any window from any application.
You might want to try the Python Win32 GUI Automation library. I haven't used it but sounds like it might be what you are looking for. If that doesn't work, your best option might be forgo python and use a tool like AutoIt that provides built in support for window manipulation.
If neither of those solutions work you will probable have to directly invoke windows api. I do not know if the win32api package wraps the necessary functionality, otherwise you will have write a python module in c/c++.
If this kind of functionality is available in the .net api, you could use IronPython.

Categories