Gtk3 with Python, TextView rising multiple 'mark-set' signals - python

Consider the following example code, which puts a TextView inside a window and registers the mark-set event:
#!/usr/bin/env python3
from gi.repository import Gtk
win = Gtk.Window(title='test')
text_view = Gtk.TextView()
def test (*args):
print('test!')
win.add(text_view)
text_view.get_buffer().connect('mark-set', test)
win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()
If I launch it, and I click on the visualized TextView once I get the debug output multiple times:
$ ./test.py 2>/dev/null
test!
test!
test!
test!
Do you know why this is happening? Is there a way of avoiding it?

I don't know why exactly it's happening, but I found something to help you understand, or use it to prevent duplicate actions in handler, using mark.get_name(). Here I changed your code, type some text and play with it (select some text, click somewhere, ...)
#!/usr/bin/env python3
import time
from gi.repository import Gtk
win = Gtk.Window(title='test')
text_view = Gtk.TextView()
def mark_set(buf, itr, mark):
### mark.get_name() ==> 'selection_bound' | 'insert' | None
print('Time: %.2f, Mark Name: %s'%(time.time()%100, mark.get_name()))
win.add(text_view)
text_view.get_buffer().connect('mark-set', mark_set)
win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()

Related

How to Pygtk WindowTypeHint to DOCK on XFCE and have it visible on the desktop

So I've run into an issue where whenever I set the WindowTypeHint to anything other than normal the window just disappears. I've verified the hint type with print.Below is my sample code
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
# Create the main window
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Hello World")
# Innitially setting the bar to off
self.set_decorated(False)
# Attempting to set window type to prevent minimizing when show desktop is hit and to stay behind other objects etc.
self.set_type_hint(Gdk.WindowTypeHint.DOCK)
# Defining the button and drawing it
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
# define the button functions
def on_button_clicked(self, widget):
if win.props.decorated == False:
win.set_decorated(True)
else:
win.set_decorated(False)
print("Hello World")
print(win.props.decorated)
print(self.props.type_hint)
# Set alias for the window
win = MyWindow()
# Testing. Print the hint type to console
print(win.props.type_hint)
# Window settings.
win.set_keep_below(True)
win.connect("destroy", Gtk.main_quit)
win.show_all()
print(win.props.type_hint)
Gtk.main()
Window to appear as a dock on the desktop where the mouse pointer is or in the corner of one of the monitors the same way glava works with it's settings.
Item was drawing off screen. Multiple monitors had it throwing the item into the corner off screen between them. If anyone else comes across this I resolved it by setting the coordinates with self.move(x, y) in the initialisation. Found where I wanted it to root with win.get_position() on button press to find where I wanted it.

Python3 GTK3 - Change button to insensitive immediately after click

Please take a look on my test code below:
import time
import subprocess
import os,re
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="test")
self.set_default_size(400, 190)
self.set_border_width(10)
fixed = Gtk.Fixed()
self.add(fixed)
self.button2 = Gtk.Button(label='press')
self.button2.connect("clicked", self.aaabbb)
self.button2.set_size_request(100, 20)
fixed.put(self.button2, 170, 10)
def aaabbb(self,widget):
self.button2.set_sensitive(False)
p = subprocess.run( ['/bin/bash','-c', '/bin/sleep 5'] )
print(p.returncode)
window = MyWindow()
window.connect("delete-event", Gtk.main_quit)
window.show_all()
Gtk.main()
If you run this simple application you will notice that button gets disabled only after 5 second, after subprocess finishes "sleep 5"
Question - how to make the button insensitive before subprocess starts?
Thank you in advance
That happens because the subprocess call isn't asynchronous and blocks the mainloop and the user interface as a consequence.
So, the approach is not correct.
The clicked signal requires a button to be pressed and released but you have other signals that you can use, eg. button-press-event and button-release-event. The callback prototypes vary from the clicked one and you'll have access to the event, if needed.
The answer to your question would be, set a callback to the button press event, BUT this will not solve your problem! The call should be async and to achieve that you can use GLib spawn async method.

Make a vte terminal communicate with running python script

I am trying to achieve the following. I built some gtk application which will have some data, let's say a,b and c.
What I want now is some sort of terminal window in which I can query and change the data as I would in e.g. iPython:
$ a
[1 2 3]
$ a= a+1
$ a
[2 3 4]
And let this take effect in the gtk application. Is this doable?
You can try to launch xterm by subprocess, and to communicate between file.py and term, copy the vars in environment variable, and get it by:
os.environ[your_var]
Take a look of this. Once you are in type "python". About communicating with the script, the only way that I've found is with an external file. What you want it is possible but complicated. here you have an example that i made where i return the variable "tty" from the VTE terminal to the python script.
from gi.repository import Gtk, GObject, Vte
#GObject is not required. I just import it everywhere just in case.
#Gtk, Vte, and GLib are required.
from gi.repository import GLib
import os
#os.environ['HOME'] helps to keep from hard coding the home string.
#os is not required unless you want that functionality.
class TheWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="inherited cell renderer")
self.set_default_size(600, 300)
self.terminal = Vte.Terminal()
self.terminal.fork_command_full(
Vte.PtyFlags.DEFAULT, #default is fine
os.environ['HOME'], #where to start the command?
["/bin/sh"], #where is the emulator?
[], #it's ok to leave this list empty
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
None, #at least None is required
None,
)
#Set up a button to click and run a demo command
self.button = Gtk.Button("Do The Command")
#To get the command to automatically run
#a newline(\n) character is used at the end of the
#command string.
self.command = "echo \"Sending this command to a virtual terminal.\"\n"
command = Gtk.Label("The command: "+self.command)
self.button.connect("clicked", self.InputToTerm)
#end demo command code
#set up the interface
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.pack_start(self.button, False, True, 0)
box.pack_start(command, False, True, 1)
#a scroll window is required for the terminal
scroller = Gtk.ScrolledWindow()
scroller.set_hexpand(True)
scroller.set_vexpand(True)
scroller.add(self.terminal)
box.pack_start(scroller, False, True, 2)
self.add(box)
def InputToTerm(self, clicker):
#get the command when the button is clicked
length = len(self.command)
#A length is not required but is the easiest mechanism.
#Otherwise the command must be null terminated.
#Feed the command to the terminal.
self.terminal.feed_child(self.command, length)
win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

How to send commands to pygobject virtual terminal?

Right now I can make a terminal but the output is not used as a command.
It just prints a string to the virtual terminal.
from gi.repository import Gtk, GObject, Vte
class TheWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="inherited cell renderer")
self.set_default_size(400, 200)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
v = Vte.Terminal()
#v.connect ("child-exited", lambda term: gtk.main_quit())
length = len("echo \"string\"\n")
v.feed("echo \"string\"\n", length)
box.pack_start(v, True, True, 0)
self.add(box)
I tried to use the docs here
http://developer.gnome.org/vte/0.30/ , but I had some trouble figuring all that out. I couldn't find any documentation on vte for python gtk3 at all.
Mainly I'm just trying to figure out how to get the command prompt in the virtual terminal so it will accept commands from inside the python gtk3 interface.
Here's the answer. :)
The important parts are fork_command_full and feed_child.
from gi.repository import Gtk, GObject, Vte
#GObject is not required. I just import it everywhere just in case.
#Gtk, Vte, and GLib are required.
from gi.repository import GLib
import os
#os.environ['HOME'] helps to keep from hard coding the home string.
#os is not required unless you want that functionality.
class TheWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="inherited cell renderer")
self.set_default_size(600, 300)
self.terminal = Vte.Terminal()
self.terminal.fork_command_full(
Vte.PtyFlags.DEFAULT, #default is fine
os.environ['HOME'], #where to start the command?
["/bin/sh"], #where is the emulator?
[], #it's ok to leave this list empty
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
None, #at least None is required
None,
)
#Set up a button to click and run a demo command
self.button = Gtk.Button("Do The Command")
#To get the command to automatically run
#a newline(\n) character is used at the end of the
#command string.
self.command = "echo \"Sending this command to a virtual terminal.\"\n"
command = Gtk.Label("The command: "+self.command)
self.button.connect("clicked", self.InputToTerm)
#end demo command code
#set up the interface
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.pack_start(self.button, False, True, 0)
box.pack_start(command, False, True, 1)
#a scroll window is required for the terminal
scroller = Gtk.ScrolledWindow()
scroller.set_hexpand(True)
scroller.set_vexpand(True)
scroller.add(self.terminal)
box.pack_start(scroller, False, True, 2)
self.add(box)
def InputToTerm(self, clicker):
#get the command when the button is clicked
length = len(self.command)
#A length is not required but is the easiest mechanism.
#Otherwise the command must be null terminated.
#Feed the command to the terminal.
self.terminal.feed_child(self.command, length)
win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Python cpu temp in system tray Linux

I'm using tint2 for a panel and want to show the cpu temp as a system tray icon since there aren't any plugins for tint2 that do that and I'd just like to know how to do this anyway whether there was one or not. The script I have so far is:
#! /usr/bin/python
import pygtk,os
pygtk.require("2.0")
import gtk
import egg.trayicon
t = egg.trayicon.TrayIcon("CPUTemp")
cpu_temp=os.popen('sensors | grep "temp1:" | cut -d+ -f2 | cut -c1-2').read()
t.add(gtk.Label(cpu_temp))
t.show_all()
gtk.main()
Basically, it works the first time around but I'd also like it to update every 5 seconds or so. Any help greatly appreciated.
you can define a timer via timeout_add_seconds and update your tray icon in the callback. See if an example below would work for you:
import gtk, gobject, os
class CPUTimer:
def __init__(self, timeout):
self.window = gtk.Window()
vbox = gtk.VBox()
self.window.add(vbox)
self.label = gtk.Label('CPU')
self.label.set_size_request(200, 40)
vbox.pack_start(self.label)
# register a timer
gobject.timeout_add_seconds(timeout, self.timer_callback)
self.window.connect("destroy", lambda w: gtk.main_quit())
self.window.connect("delete_event", lambda w, e: gtk.main_quit())
self.window.show_all()
self.timer_callback()
def timer_callback(self):
cpu_temp = os.popen('sensors | grep "temp1:" | cut -d+ -f2 | cut -c1-2').read()
print 'update CPU: ' + cpu_temp
self.label.set_text('CPU: ' + cpu_temp)
return True
if __name__ == '__main__':
timer = CPUTimer(1) # sets 1 second update interval
gtk.main()
hope this helps, regards
Look at Python's "threading" module. Create a function which runs the command an update gtk.Label's text with new output(t.set_text(str)). And run this function on a thread.
http://docs.python.org/library/threading.html

Categories