Double buffering with wxpython - python

I'm working on an multiplatform application with wxpython and I had flickering problems on windows, while drawing on a Panel.
I used to draw on a buffer (wx.Bitmap) during mouse motions events and my OnPaint method was composed of just on line:
dc = wx.BufferedPaintDC(self, self.buffer)
Pretty standard but still I had flickering problems on Windows, while everything worked fine on Linux.
I solved my problem calling SetDoubleBuffered(True) in the __init__ method.
The strange thing is that now everything works even if I don't use BufferedPaintDC anymore. I changed my application so that all the drawing part is done in the OnPaint method. I don't use a buffer and drawing is done directly on a wx.PaintDC with no flickering problems at all.
So my question is: is BufferedPaintDC totally useless? Or deprecated somehow? I'm owner of the book "WxPython in Action" (2006) and it doesn't even mention SetDoubleBuffered

There is a high probability that the SetDoubleBuffered actually makes your panel use a buffered dc automatically, the documentation doesn't mention that those classes are deprecated (and I rather think they would if that were the case).
About wxPython in Action... 2006 was a long time ago... it is possible that the SetDoubleBuffered method didn't exist back then or that the author wanted to show how things work at the lower level.

Related

WxPython Choice Field Invisible just on Mac

I am developing a cross platform app in Python using wxPython. The app is fully developed, and the graphics toolkit is set in stone, at least for the time being.
On Windows, everything looks great. On Linux, everything looks pretty good. On Mac, I am having trouble with a combobox/choice being hidden in the toolbar, even though it shows up fine on Windows.
Here is a snapshot of my app on Linux, noting the entire "CoeffConv ..." section is part of the perfectly displayed combobox:
And here is a snapshot of the same exact codebase on Mac:
I've tried with wx.ComboBox and wx.Choice with the same effect. I've made sure to call Realize() after I've added my toolbar items. I've made sure AddControl is called to actually add the object to the toolbar. It's definitely trying to render because the spacing is exactly what I would expect, given the contents of the choice field.
In fact, if I don't call AddControl, but I create the choice field with the toolbar as the parent, the box gets rendered but things aren't arranged properly due to the missing AddControl call:
As another check, I created a super simple toolbar with choice demo, and it works just fine:
So, here's the summary of things I know:
On Windows, the choice field works perfect, indicating the code isn't necessarily wrong.
On Linux, the choice field works perfect, supporting the idea that the code is actually OK.
On Mac, the choice field is present it seems, but somehow invisible, implying this is a problem with the Mac, or the Python distribution on Mac, or the combobox control in the wxPython distribution on Mac.
On Mac, I can get the choice to render (improperly but still) without an AddControl call, indicating the combobox can render properly, but something is goofy about the placement when added to the toolbar
However, On Mac, I can get a toolbar/choice to render totally fine in a dummy example, indicating it's something about my implementation...but I can't figure out what would cause it as I'm trying to make the exact same calls to the wx objects as in the dummy example.
I can't get the dummy example to reproduce the problem, but I'll keep trying. I'm happy to report out some object properties if they would be helpful in diagnosing. If someone has a clue for what could cause it to not show up, I'd really appreciate it!
While I couldn't find the root as to why it didn't work on Mac, I did find an issue that could help others.
First a little more background. In the app, we have multiple toolbars. Because of that, we are creating toolbars using plain wx.ToolBar objects and adding them to the app frame using sizers. This is in contrast to the more standard method of using self.CreateToolBar() which only allows a frame to have a single toolbar.
When I make a single change to the code to use the more natural CreateToolBar interface, the combobox immediately shows up. When I do that, the second toolbar is messed up, but at least the initial toolbar works perfectly. I'll be investigating how to get multiple toolbars on Mac, but it's a step in the right direction.
It's been a while, but there's another solution to this for wxPython 4 if you can't use CreateToolBar():
The widgets do get added to the bar and reserve the correct amount of space, but they fail to draw properly. You can resolve this by calling control.Hide() followed by control.Show() on each widget control, which then makes them draw properly.

Writing To The Framebuffer on macOS

I would like to recreate the programs shown in this article on a Mac. Is this possible? My research so far has pointed to "no" but I don't want to give up just yet. Python is preferred but my purpose for this is simple enough that most any language is fine.
Edit: To elaborate on my goal, it is to write individual pixels to the screen with no background. I don't care if they're removed by mouse movements, and if there is a better way to do this than framebuffers I will use that.
Unfortunately, the MacOS kernel doesn't expose a file to access the framebuffer (such as /dev/fb0 on Linux).
There could be a way to do this using the MacOS APIs. In 2004 the DirectFB project had this working (here's the commit that added it: https://github.com/DirectFB/directfb/commit/cbe9cfd0446bfa8c6fcd18b7cbc805566eec9b5d#diff-250fcad7219dfcf74cf05db93c9070445945c9e39cd6529f67d1a00ea93961da ). However, in the last decade it's likely that these APIs have been deprecated and you'd have to look into whatever replaced them.
It's easy enough to use Metal or OpenGL though. Just make a fullscreen window, make two large triangles the size of the screen, and update their texture.

Segmentation fault using Python gtk3 with pyOpenGL

I use Python in combination with the gtk3 and the GTKGLExt fork from https://github.com/tdz/gtkglext so I can use the gobject introspection feature to use Gtk3 from python.
I created a Gtk.DrawingArea to draw my OpenGL stuff. Everything works fine as long as I have just one instance of this widget.
However, I use a Gtk Notebook to have multiple instances of this widget present in different pages of the notebook (one widget per page).
Sometimes (meaning in a non deterministic way) the program crashes with a segmentation fault. I ran a stacktrace using gdb and located the problem to be the call to "gtk_widget_end_gl" which is placed at the end of my drawing, realize and configure handler methods (of course there is a gtk_widget_begin_gl at the beginning of each of those as well).
Here is the relevant excerpt from the stacktrace:
0 0xb1170b58 in _gdk_x11_gl_context_impl_get_current () at gdkglcontext-x11.c:514
1 0xb116c094 in gdk_gl_context_get_current () at gdkglcontext.c:244
2 0xb116c0b4 in gdk_gl_context_release_current () at gdkglcontext.c:215
3 0xb4d04592 in gtk_widget_end_gl (widget=0xa175608, do_swap=0) at gtkglwidget.c:549
and below is a minimal example of my realize method where the problem occurs where "widget" is an instance of Gtk.DrawingArea:
def on_realize(self, widget, *user_data):
if not GtkGLExt.widget_begin_gl(widget):
return False
gl.glClearColor(BACKGROUND_COLOR[0],
BACKGROUND_COLOR[1],
BACKGROUND_COLOR[2],
BACKGROUND_COLOR[3])
GtkGLExt.widget_end_gl(widget, False)
Since I am pretty much clueless why this problem occurs sometimes (around every 5th time a new widget is created) I wonder if anyone ever has experienced the same or can reproduce the problem or help me to find a solution.
I need to say that I don't manually create an OpenGL context here since in the provided examples this never seemed necessary and I figured the widget would do this on it's own. The stacktrace implies that there seems to be a problem getting the context. Whats startles me is the fact that this only happens sometimes. So if someone could even hint me how to tackle this problem I would be very glad as I am not an experienced C programmer.

How to delete a subwindow in the python curses module

I've got a curses application that uses subwindows, but I can't seem to be able to delete them.
For example, this code doesn't work:
import curses
def fill(window, ch):
y, x = window.getmaxyx()
s = ch * (x - 1)
for line in range(y):
window.addstr(line, 0, s)
def main(stdscr):
fill(stdscr, 'M')
stdscr.refresh()
stdscr.getch()
subwin = stdscr.subwin(1, 28, 20, 13)
fill(subwin, 'J')
subwin.refresh()
subwin.getch()
del subwin
stdscr.touchwin()
stdscr.refresh()
stdscr.getch()
curses.wrapper(main)
When you run this code, the screen fills with 'M', then when you hit a key, a subwindow is created and filled with 'J'. Finally, when you press a key again, the code deletes the subwindow and completely redraws the screen. However, those Js are still there.
After some experimentation, I've found that calling the clear() method of stdscr will make the subwindow go, but I would like to restore the background as it was, without blanking it and rewriting.
Does anyone know a way in which this could be done?
Is there a good reason why you're using a subwindow? If you create a new top-level window then the code works correctly - simply change stdscr.subwin to curses.newwin and it works as you'd expect.
I'm not a curses expert, but I believe a subwindow shares the character buffer with its parent such that changes to either one will also affect the other. So, if you're looking to sub-divide a window into logical areas (perhaps a menu bar, main area and status bar) then subwindows are useful. If, however, you're looking for something more like a dialog box or pop-up menu then a whole new window (with its own separate buffer) is what you're after.
I can't find any definitive reference for ncurses which agrees or disagrees with me, but man page for AIX seems to corroborate it:
Recall that the subwindow shares its parent's window buffer. Changes made to the shared window buffer in the area covered by a subwindow, through either the parent window or any of its subwindows, affects all windows sharing the window buffer.
Of course, this isn't definitive for ncurses, but I can't find anything to the contrary and it certainly seems to explain the behaviour observed. I also did a crude experiment where, immediately after the subwin.getch() line in your example, I added this line:
raise Exception(stdscr.instr(20, 15, 3))
In your example, I get JJJ as the content of the actual main window. If I change to use curses.newwin() to create the window instead of stdscr.subwin() I get the expected MMM.
I don't know how many specific Python curses resources there are, but most of the standard tutorials and documents about ncurses are quite useful for this sort of level. Back when I had to do some work in it, this document was quite useful. If you scroll down to the "An Example" section, you'll see that the menu pop-ups are not subwindows - he alludes to this with the following slightly vague explanation:
We don't want this new window to overwrite previously written characters on the background. They should stay there after the menu closes. This is why the menu window can't be created as a subwindow of stdscr.
Also, I remember that using both stdscr and your own windows can cause issues - the "official" ncurses introduction has some warnings about this sort of thing. It also suggests avoiding overlapping windows entirely, as they're apparently error-prone, but I don't recall having any issues with them for short-term transient modal dialogs (which is the only use to which I put them). Of course, just because my simple use-case didn't expose any issues doesn't mean there aren't any. In something as complicated as ncurses, however, I can see the wisdom in keeping things as simple as you can.
I hope that's some help. As I said, I'm by no means a curses expert, but hopefully this gets you a few steps further along.
There are two problems with this code.
First, as the previous poster noted, subwindows share a buffer with the parent window, so you should use curses.newwin() if you want a completely independent window.
Second, using del to remove a window is problematic because it relies on reference counting/garbage collection to work properly. (For one thing, you have to delete all references to the window for it to work.) I recommend using the curses.panel module to explicitly show/hide the window.

Take all input in Python (like UAC)

Is there any way I can create a UAC-like environment in Python? I want to basically lock the workstation without actually using the Windows lock screen. The user should not be able to do anything except, say, type a password to unlock the workstation.
You cannot do this without cooperation with operating system. Whatever you do, Ctrl-Alt-Del will allow the user to circumvent your lock.
The API call you're looking for Win32-wise is a combination of CreateDesktop and SetThreadDesktop.
In terms of the internals of Vista+ desktops, MSDN covers this, as does this blog post. This'll give you the requisite background to know what you're doing.
In terms of making it look like the UAC dialog - well, consent.exe actually takes a screenshot of the desktop and copies it to the background of the new desktop; otherwise, the desktop will be empty.
As the other answerer has pointed out - Ctrl+Alt+Delete will still work. There's no way around that - at least, not without replacing the keyboard driver, anyway.
As to how to do this in Python - it looks like pywin32 implements SetThreadDesktop etc. I'm not sure how compatible it is with Win32; if you find it doesn't work as you need, then you might need a python extension to do it. They're not nearly as hard to write as they sound.
You might be able to get the effect you desire using a GUI toolkit that draws a window that covers the entire screen, then do a global grab of the keyboard events. I'm not sure if it will catch something like ctrl-alt-del on windows, however.
For example, with Tkinter you can create a main window, then call the overrideredirect method to turn off all window decorations (the standard window titlebar and window borders, assuming your window manager has such things). You can query the size of the monitor, then set this window to that size. I'm not sure if this will let you overlay the OSX menubar, though. Finally, you can do a grab which will force all input to a specific window.
How effective this is depends on just how "locked out" you want the user to be. On a *nix/X11 system you can pretty much completely lock them out (so make sure you can remotely log in while testing, or you may have to forcibly reboot if your code has a bug). On windows or OSX the effectiveness might be a little less.
I would try with pygame, because it can lock mouse to itself and thus keep all input to itself, but i wouldn't call this secure without much testing, ctr-alt-del probably escape it, can't try on windows right now.
(not very different of Bryan Oakley's answer, except with pygame)

Categories