pygtk: overriding gtk.Paned.compute_position - python

I have a HPaned that one of its children changes its size requirement frequently, since its text changes. The result is that the pane moves every time the text is changed. I'd like to override the Paned.compute_position method so that the size of the child will not decrease, just increase. However, I can't find a way to override it. Even
class MyHPaned(gtk.HPaned):
def do_compute_position(self, allocation, child1_req, child2_req):
print "Hi"
return gtk.HPaned.compute_position(self, allocation, child1_req, child2_req)
gobject.type_register(MyHPaned)
doesn't work. Do you have a suggestion? Thanks!

Overriding gtk_paned_compute_position is not possible, since that function is not virtual in GTK itself. Also, gtk_paned_compute_position is marked as internal and deprecated and is not called anywhere from GTK+-2.24.x sources. I suspect it was only exported so that you could find out the position of the separator, not to affect it through overriding.
Instead of attempting to override HPaned.compute_position, you should place into the paned a single-child container (e.g. a child of gtk.Bin) that implements the desired resizing policy by hooking into the size-allocate signal and calling set_size_request with the desired size. This will be automatically respected by HPaned.

Related

LLDB Python scripting create variable

I am using LLDB Python scripting support to add custom Variable Formatting for a complex C++ class type in XCode.
This is working well for simple situations, but I have hit a wall when I need to call a method which uses a pass-by-reference parameter, which it populates with results. This would require me to create a variable to pass here, but I can't find a way to do this?
I have tried using the target's CreateValueFromData method, as below, but this doesn't seem to work.
import lldb
def MyClass(valobj, internal_dict):
class2_type = valobj.target.FindFirstType('class2')
process = valobj.process
class2Data = [0]
data = lldb.SBData.CreateDataFromUInt32Array(process.GetByteOrder(), process.GetAddressByteSize(), class2Data)
valobj.target.CreateValueFromData("testClass2", data, class2_type)
valobj.EvaluateExpression("getType(testClass2)")
class2Val = valobj.frame.FindVariable("testClass2")
if not class2Val.error.success:
return class2Val.error.description
return class2Val.GetValueAsUnsigned()
Is there some way to be able to achieve what I'm trying to do?
SBValue names are just labels for the SBValue, they aren't guaranteed to exist as symbols in the target. For instance if the value you are formatting is an ivar of some other object, it's name will be the ivar name... And lldb does not inject new SBValue's names into the symbol table - that would end up causing lots of name collisions. So they don't exist in the namespace the expression evaluator queries when looking up names.
If the variable you are formatting is a pointer, you can get the pointer value and cons up an expression that casts the pointer value to the appropriate type for your getType function, and pass that to your function. If the value is not a pointer, you can still use SBValue.AddressOf to get the memory location of the value. If the value exists only in lldb (AddressOf will return an invalid address) then you would have to push it to the target with SBProcess.AllocateMemory/WriteMemory, but that should only happen if you have another data formatter that makes these objects out of whole cloth for its own purposes.
It's better not to call functions in formatters if you can help it. But if you really must call a function in your data formatter, you should to do that judiciously.
They can cause performance problems (if you have an array of 100 elements of this type, your formatter will require 100 function calls in the target to render the array... That's 200 context switches between your process and the debugger, plus a bunch of memory reads and writes) for every step operation.
Also, since you can't ensure that the data in your value is correct (it might represent a variable that has not been initialized yet, or already deallocated) you either need to have your function handle bad data, or at least be prepared for the expression to crash. lldb can clean up the stack and suppress the exception from crashes, but it can't undo any side-effects the expression might have had before crashing.
For instance, if the function you called took some lock before crashing that it was expecting to release on the way out, your formatter will damage the state of the program. So you have to be careful what you call...
And by default, EvaluateExpression will allow all threads to run so that expressions don't deadlock against a lock held by another thread. You probably don't want that to happen, since that means looking at the locals of one thread will "change" the state of another thread. So you really should only call functions you are sure don't take locks. And use the version of EvaluateExpression that takes an SBExpressionOption, in which you set the SBExpressionOptions.StopOthers to True, and SetTryAllThreads to False.

Why are python generator frames' (gi_frame) f_back attribute always none?

The title is pretty self-explanatory. I'm doing something like:
gen = obj #some generator instance running
frame = obj.gi_frame
prevframe = frame.f_back
But I always get None for prevframe. Why is this the case. Also, is there some workaround for this?
CONTEXT: I'm trying to write a simple call stack method to determine what called a particular function. I'm using twisted manhole and telnetting into a running process, where I then execute these commands but I can't seem to access the previous frames.
To the best of my knowledge, this is both intentional and cannot be worked around. The code in cpython responsible for it is here, which indicates that the reference to the previous frame is broken as soon as the generator yields (or excepts out) in order to prevent issues with reference counting. It also appears that the intended behavior is that the generator's previous frame is swapped out every time it's entered, so while it's not running, the notion of "the parent frame" doesn't make much sense.
The correct way to do this, at least in the post-mortem context, is to use traceback objects, which have their frame lists linked in the reverse order, tb_next instead of f_back.

HTML like layouting

I'm trying to implement my own little flow-based layout engine. It should imitate the behavior of HTML layouting, but only the render-tree, not the DOM part. The base class for elements in the render-tree is the Node class. It has:
A link to the element in the DOM (for the ones that build a render-tree with that library)
A reference to it's parent (which is a ContainerNode instance or None, see later)
A reference to the layouting-options
X, Y, width and height (the position is computed in layout(), after the size has been computed in compute_size(). While the position is defined by the layout() method of the parent, the size is defined by the options reference, for instance).
It's methods are:
reflow() invoking compute_size() and layout()
compute_size() that is intended to compute the width and height of the node.
layout() which is intended to position the sub-nodes of the node, not the node itself.
paint() which is there to be overwritten by the user of the library.
The ContainerNode class is implementing the handling of sub-nodes. It provides a new method called add_node(), which adds the passed node to the containers children. The function also accepts a parameter force which defaults to False, because the container is allowed to deny the passed node, except force is set to True.
These two classes do not implement any layouting algorithm. My aim was to create different classes for the different types of layouts (In CSS, mainly defined by the display attribute). I did some tests with text-layouting last night and you can find my code from at pastebin.com (requires pygame). You can save it to a python script file and invoke it like this:
python text_test block -c -f "Georgia" -s 15
Note: The code is really really crappy. I appreciate comments on deep lying misconceptions.
The class InlineNodeRow from the code mentioned above actually represents my idea of how to implement the node that lays out similar to the display:inline attribute (in combination with the NodeBox).
Problem 1 - Margin & Padding for inline-text
Back to my current approach in the library: A single word from a text would also be represented as a single node (just like in the code above). But I noticed two things about margins and paddings in a <span> tag.
When margin is set, only horizontal margin is taken in account, the vertical margin is ignored.
The padding is overflowing the parent container and does not "move" the span node.
See http://jsfiddle.net/CeRkT/1/.
I see the problem here: When I want to compute the size of the InlineNodeBox, I ask a text-node for it's size and add it to the size of the node. But the text-nodes size is including it's margin and padding, which is not included in the HTML renderer's positioning. Therefore the following code would not be right:
def compute_size(self):
# Propagates the computation to the child-nodes.
super(InlineNodeBox, self).compute_size()
self.w = 0
self.h = 0
for node in self.nodes:
self.w += node.w
if self.h < node.h:
self.h = node.h
node.w would include the margin and padding. Next problem I see is, that I for laying out the text-nodes correctly, I wanted to split them into single TextNodes for each word, but the margin and padding would then be applied to all these nodes, while the margin and padding in HTML is to the <span> tag only.
I think my current idea of putting each word into a seperate node is not ideal. How to browsers structure their render-tree, or do you have a better idea?
Problem 2 - Word too long, put it into the next line.
The InlineNodeBox class currently only organizes a single line. In the code example above, I've created a new InlineNodeBox from within the NodeBox when the former refused to accept the node (which means it didn't fit in). I can not to this with my current approach, as I do not want to rebuild the render-tree all over again. When a node was accepted once, but exceeds the InlineNodeBox on the next reflow, how do I properly manage to put the word into the next line (assuming I keep the idea of the InlineNodeBox class only organizing a single line of nodes)?
I really hope this all makes sense. Feel free to ask if you do not understand my concept. I'm also very open to criticism and ideas for other concepts, links to resources, documentations, publications and alike.
Problem 2:
You can do it like HTML renderers do and render a multiline (e.g. check if the new word to be added exceeds the width and add a new line if it does). You can do it in your InlineNodeRow, by taking care of height too and wrapping words if they exceed the max width.
Problem 1:
If you do figure out problem 2 for text, then you can put in the offset (horizontal padding) only for the first line.
Although <span> doesn't take height into consideration, it does take line-height, so your calculation could be that the default height is the font height unless you have a line-height option available.
Mind you, if you have two or more successive InlineNodeRow representing spans, you'd need some smart logic to make the second one continue from where the first one ended :)
As a side note, From what I remember from Qt's rich text label, each set of words with the same rendering properties is considered to be a node, and its render function takes care of calculating all the stuff. Your approach is a bit more granular and its only disadvantage from what I see is that you can't split words.
HTH,
May have found solution to problem 1 in the box model documentation (you may want to check out the documentation about clearance and the one for overflow as well for problem 2).
"margins of absolutely positioned boxes do not collapse."
You can see this jsfiddle for an example.

pygtk GtkTreeIter comparision

I have a ListStore in PyGTK, which has a bunch of rows. There is a background job processing the data represented by the rows, and when it finishes, it needs to update the row. Of course, to do this, it needs to know which row to update, and is thus keeping an iterator to the row around. However, during the background jobs life, the user might remove the row. This is OK — we just replace the stored iterator with "None", and the background job continues along merrily. The problem is that when the row is removed, the iterators don't compare as equal, and nothing gets set to None. In fact, no two iterators, AFAIK, compare equal. The problem, in a minimal example, is this:
>>> store = gtk.ListStore(int)
>>> store.insert(1)
<GtkTreeIter at 0x1d49600>
>>> print store[0].iter == store[0].iter
False
False, yet they're the same iterator! (I'm aware they are different instances, but they represent the same thing, and they define a __eq__ method.) What am I missing here, and how do I keep track of rows in a ListStore for later updating?
Try using the list store's .get_path(iter) method, and compare the resulting paths, instead of comparing the iterators directly.
UPDATE: You can just call set_value with the invalid iter. gtk will give you a warning but will not throw an exception or anything. It probably just checks whether it's a valid iter anyway.
I would approach this differently — here's what I've done in a similar situation:
The underlying data object represented in each row is an instance of a GObject
This GObject subclass has a bunch of properties
When the property changes, it emits the notify::myproperty signal
At the same time:
My ListStore stores these objects, and uses the gtk.TreeViewColumn.set_cell_data_func() method to render each column (see note below)
For each object/row, my object managing the TreeView connects to the notify::myproperty
The function connected to this notify::... signal triggers the row-changed signal on the ListStore
Some code:
def on_myprop_changed(self, iter, prop):
path = self.model.get_path(iter)
self.model.row_changed(path ,iter)
def on_thing_processed(self, thingdata):
# Model is a ListStore
tree_iter = self.model.append((thingdata,))
# You might want to connect to many 'notify::...' signals here,
# or even have your underlying object emit a single signal when
# anything is updated.
hid = thingdata.connect_object('notify::myprop',
self.on_myprop_changed,
tree_iter)
self.hids.add((thingdata, hid))
I keep the hids in a list so I can disconnect them when the table is cleared. If you let individual rows get removed, you'll probably need to store them in a map (path -> hid, or object -> hid).
Note: You need to remember that set_cell_data_func causes the row to re-check its information every time there's a redraw, so the underlying function should just be a lookup function, not an intensive computation. Practically speaking, because of this you could get away with not doing the "connect-to-signal/emit-row-changed" procedure, but personally I feel better knowing that there won't be any edge cases.

Get a layout's widgets in PyQT

I have a QVBoxLayout that I've added a few widgets to, via addWidget(). I need to now delete those widgets, and it seems I need to use removeWidget() (which takes in a widget to be removed) to do that.
I thought that calling children() or findChildren(QWidget) on my layout would return a list of the widgets I've added into it; I'm in the debugger, though, and am just receiving empty lists.
Am I terribly misunderstanding something? I've just started doing PyQT this last week and have mostly been learning through trial and error with the API docs.
To get a widget from a QLayout, you have to call its itemAt(index) method.
As the name of this method implies, it will return an item instead of a widget. Calling widget() on the result will finally give you the widget:
myWidget = self.myLayout.itemAt(index).widget()
To remove a widget, set the parent widget to None:
myWidget.setParent(None)
Also really helpfull is the QLayout count() method. To find and delete all contents of a layout:
index = myLayout.count()
while(index >= 0):
myWidget = myLayout.itemAt(index).widget()
myWidget.setParent(None)
index -=1
That's odd. My understanding is that adding widgets via addWidget transfers ownership to the layout so calling children() ought to work.
However, as an alternative you could loop over the layout items by using count() and itemAt(int) to supply a QLayoutItem to removeItem(QLayoutItem*).
Edit:
I've just tried addWidget with a straight C++ test app. and it doesn't transfer QObject ownership to the layout so children() is indeed an empty list. The docs clearly say that ownership is transferred though...
Edit 2:
Okay, it looks as though it transfers ownership to the widget that has that layout (which is not what the docs said). That makes the items in the layout siblings of the layout itself in the QObject hierarchy! It's therefore easier to stick with count and itemAt.

Categories