Drawing window border in Python xlib - python

I'm working on a window manager written using python's xlib bindings and I'm (initially) attempting to mimic dwm's behavior in a more pythonic way. I've gotten much of what I need, but I'm having trouble using X's built in window border functionality to indicate window focus.
Assuming I've got an instance of Xlib's window class and that I'm reading the documentation correctly, this should do what I want to do (at least for now) - set the window border of a preexisting window to a garish color and set the border width to 2px.
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(\
"#ff00ff").pixel
window.change_attributes(None,border_pixel=border_color,
border_width = 2 )
self.dpy.sync()
However, I get nothing from this - I can add print statements to prove that my program is indeed running the callback function that I associated with the event, but I get absolutely no color change on the border. Can anyone identify what exactly I'm missing here? I can pastebin a more complete example, if it will help. I'm not exactly sure it will though as this is the only bit that handles the border.

Looks like this was complete PEBKAC. I've found an answer. Basically, I was doing this:
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(
"#ff00ff"
).pixel
window.configure(border_width=2)
window.change_attributes(
None,
border_pixel=border_color,
border_width=2)
self.dpy.sync()
Apparently this was confusing X enough that it was doing nothing. The solution that I've stumbled upon was to remove the border_width portion from the window.change_attributes() call, like so:
def set_active_border(self, window):
border_color = self.colormap.alloc_named_color(
"#ff00ff"
).pixel
window.configure(border_width=2)
window.change_attributes(
None,
border_pixel=border_color
)
self.dpy.sync()
I hope this helps someone later on down the road!

Related

Gtk. widget - can't change bg color. Pygtk

I writing gtk interface with python code. the problem is:
init entry widget by gtkbuilder:
self.some_entry = self.builder.get_object('SomeEntry')
Define signal by typing button, after then must changed entry color:
def on_SomeButton_clicked(self, widget):
self.some_entry.modify_bg(Gtk.StateType.NORMAL,Gdk.Color(20000,10000,10000))
but it doesn't work, such 'modify_base'. And I don't know why. Help please.
Sorry for my English(
EDIT2:
Turns out it was an entry box giving the problem which is another issue in and of itself because the background is not the property you need to modify but the BASE color property which can typically be set using:
self.entry.override_background_color(Gtk.StateType.Normal, Gdk.RGBA(0.0, 1.0, 0.0, 1.0))
However for OP it was not working so a CSS option was explored, listed at: https://mail.gnome.org/archives/gtk-app-devel-list/2005-November/msg00236.html
EDIT:
So working with PyGtk3 I was able to get a button changing color using you line of code:
self.button.modify_bg(Gtk.StateType.Normal, Gdk.Color(20000, 10000, 10000))
It was grey on initialization and dark red after the code ran. The only thing I could think of is make sure that the object you are trying to modify is actually in a NORMAL state after you run the code and make sure the signal you think is triggering is actually triggering.
==============
Original post:
Without having the full code here there are a few things that could be causing this. I just threw together a test program in Python based off of: http://pygtk.org/pygtk2tutorial/examples/helloworld.py
When I set the Gtk State for the modify_bg I had to use:
gtk.STATE_NORMAL
Not sure if that is due to a different version of Gtk or what though.
Then when I went to use Gdk I had to refer to it as:
gtk.gdk
The line that I ended up with to change the button color was:
self.button.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(20000, 10000, 10000))
Hopefully that works out, in order to get any more detailed though we would definitely need more code and to know what kind of errors you are getting.
CSS works, code below:
style_provider = Gtk.CssProvider()
css = open('style.css', 'rb')
css_data = css.read()
css.close()
style_provider.load_from_data(css_data)
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
With line
"widgetname".get_style_context().add_class("colorize")
"widgetname" has been colorized.
CSS code:
.colorize {
background: rgba(200,50,50,0.3);
}

Issue with "dynamic" padding in matplotlib

I've been trying to set a fixed size padding (in pixels) on my matplotlib figure. I've never been able to find a solution that suits my needs on the internet so I had to make a little workaround for this, which is done with the following code :
def resizeEvent(self,e):
windowWidth=self.geometry().width()
windowHeight=self.geometry().height()
#print(windowWidth,windowHeight)
figure.subplots_adjust(left=100.0/windowWidth,right=1-100.0/windowWidth, top=1-100.0/windowHeight,bottom=100.0/windowHeight)
It works fine when manually resizing the window (we have a padding of 100px on every side).
Unfortunatly, when clicking Maximize, the padding (in 0 to 1) seems to be equal to it's previous value, even if the print returns the correct window size (1920px).
A second click to Restore Down will then set the padding to the value we should have when we maximized it.
I don't really get what's happening here, I must be missing something...
Tell me if you need more information such as more code.
Thank you for your kind help :)
I've had similar issues in the past (the figure not resizing at start up) and moved the recalculation of the figure subplots to the draw method. Something like this (I use tight_layout but you get the idea):
class PlotWidget(FigureCanvas):
def __init__(self):
self.__resizing_needed = True
def draw(self):
if self.__resizing_needed:
self.__resizing_needed = False
try:
self.figure.tight_layout()
except ValueError:
# Set the minimumSize of this widget to prevent this
print('Plot too small.')
super(PlotWidget, self).draw()
def resizeEvent(self, event):
self.__resizing_needed = True
super(PlotWidget, self).resizeEvent(event)

Drawing on a bitmap with wxpython (cross-platform)

I'm aware that there are literally hundred of examples out there for this task, though I don't manage to apply those examples to my specific problem. As you can see on the code below I am trying to draw a polygon on a bitmap "self.image". This code works absolutely fine on MS Windows. On Linux this code will not draw my polygon.
I tried to play around with different "dcs" like MemoryDC according to this How to draw text in a bitmap using wxpython?
but the result was the same.
My questions are:
Why does my code fail on Linux? Why does this work on MS Windows? (a bit off-topic) Why are people often exclusively drawing in the PaintDC in the OnPaint method bound to EVT_PAINT?
class attributes:
self.dc = wx.ClientDC(self.image)
self.dc.SetPen(wx.Pen(colour='red', width=4, style=wx.SOLID))
self.polygon = list()
this method is being called when I want to start drawing:
def start_drawing(self):
self.image.Bind(event=wx.EVT_LEFT_DOWN, handler=self.draw_polygon)
self.dc.BeginDrawing()
this method handles the binding from above:
def draw_polygon(self, event):
self.polygon.append(event.GetPositionTuple())
if len(self.polygon) > 1:
self.dc.DrawLines(points=self.polygon)
I fixed the bug myself.
The problem was actually not visible in the code I've been providing.
I have a method which changes self.image before any drawing is made. Thus the image which I assign to the ClientDC in the class body is not the same image than self.image when I begin to draw. Adding self.dc = wx.ClientDC(self.image) in the image setter solved my problem.
I don't understand why this code worked when being executed on MS Windows. This should not have never worked in the first place.

Can I make a custom pygtk tooltip stay on when the cursor is over it?

Please look at the following snippet :
import gtk
def callback(widget, x, y, keyboard_mode, tooltip):
hbox = gtk.HBox(False, 8)
button = gtk.Button('Exit Tooltip')
label = gtk.Label('Tooltip text')
hbox.pack_start(label)
hbox.pack_start(button)
hbox.show_all()
tooltip.set_custom(hbox)
return True
label = gtk.Label('Test label')
label.set_has_tooltip(True)
label.connect('query-tooltip', callback)
Here I've created a custom tooltip with a close button in it. Now I want it to stay until i click that close button. Searching google was not that helpful. besides I would also like to know the signals/events that are emitted when a tooltip is being closed.
Similar problems are handled smoothly for JQuery/JavaScript/Ajax tooltips etc. but
for gtk/pygtk there is no luck :(
Thanks in advance ...
I had this issue as well, and as far as I know, there isn't any way to determine how long a tooltip stays up.
What I did (and recommend to you) is that you make your own "tooltip" and set it's background color to yellow, or whatever color you want, via an eventbox. Make sure you don't show it yet. This is just a simplified code, as you will need to position and size this in your project yourself.
color = gtk.gdk.rgb_get_colormap().alloc_color('black')
ebTooltip = gtk.EventBox()
btnTooltip = gtk.Button("Close")
ebTooltip.add(btnTooltip)
ebTooltip.modify_bg(gtk.STATE_NORMAL, color)
Now, you just need to hide and show this eventbox via your callbacks. To show it, call...
ebTooltip.show()
And, to hide it (probably on the "clicked" event of your close button)...
ebTooltip.hide()
Hope that solves your issue!

pygtk: how to force message dialogs to show up in the center of the screen?

I have a glade GUI and i'm using dome gtk.MessageDialog widgets created with pygtk for user interaction. My problem is that whenever I throw a dialog message on the screen, they show up all over the place. One might show up on the top right corner, the next on the bottom left, top left, mid left etc...
Is there a way to force these things to show up in the center of the screen or at the position where the parent window is at?
Never mind. Found the solution.
For others who might wander about the same thing, the solution to this problem lies in specifying a parent value to the gtk.MessageDialog construct.
If you are using a glade gui, in your class, and your glade xml is loaded in to a variable named 'gui', it would look like this:
#!/usr/bin/env/python
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
if msg.run():
msg.destroy()
return None
Check out the reference material at PyGTK 2.0 Reference Manual
I have not had a chance to try this but MessageDialog seems to be derived from Window which has a set_position method.
This method accepts one of the following:
# No influence is made on placement.
gtk.WIN_POS_NONE
# Windows should be placed in the center of the screen.
gtk.WIN_POS_CENTER
# Windows should be placed at the current mouse position.
gtk.WIN_POS_MOUSE
# Keep window centered as it changes size, etc.
gtk.WIN_POS_CENTER_ALWAYS
# Center the window on its transient parent
# (see the gtk.Window.set_transient_for()) method.
gtk.WIN_POS_CENTER_ON_PARENT
None of the provided solutions will work if your parent window is not yet shown, that is if the messagedialog is to be shown during the instantiation of a class (your class, not the "parent" window class). During this time Gtk has not yet placed the window, even if code for messagedialog is after the code that shows the window. Which means your dialog box will be somehow "parentless" and the message dialog will appear wherever it likes...
My naive solution for that problem...
GObject.timeout_add(interval=50, function=self.stupid_dialog_1)
and
def stupid_dialog_1(self):
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
# do anything here...
return False #stop the timer...

Categories