1

I've tried to search, but nothing seems to work. For example:

Separate threads

I am currently writing simple communication app in Python2.7 with PyGTK. I have background process, which is listening socket in while loop like that. I want to display message, when I receive it form server. But when I start gtk.main(), it obviously starts to loop again, so my listening loop doesn't working. I need to display new window for each message or close old window and display new window with all unread messages. Can I somehow display window (or more than one window) and don't block my listening loop?

IOChannel solution

 while True: #listening loop
  print 'Start'
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  sock.bind((socket.gethostname(), 80))
  sock.listen(2)
  conn, address = sock.accept()
  conn.sendall('200 OK')
  fd = conn.fileno() #Make file descriptor from socket
  gio_channel = glib.IOChannel(fd) #Pass it to IOChannel

  if(new_message):
    #display message with gtk.main()
  else
    #Do something else like update file

subprocess.Popen solution

while True: #listening loop
  print 'Start'
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  sock.bind((socket.gethostname(), 80))
  sock.listen(2)
  conn, address = sock.accept()
  conn.sendall('200 OK')
  all_json = conn.recv(2048)

  if(new_message):
    # This script run pygtk app in the background
    subprocess.Popen(['python', 'communication_app.py'])
  else
    #Do something else like update file
Morasiu
  • 1,204
  • 2
  • 16
  • 38

1 Answers1

0

You may want to give a try using GLib's GIOChannel (GLib.IOChannel in the Python doc) to handle the sockets as en event source (a GSource). Then use g_io_create_watch (GLib.IOChannel.add_watch in Python) to integrate in GTK+ main loop.

You also have lots of more advanced socket handling stuff in the Gio library:

liberforce
  • 11,189
  • 37
  • 48
  • Hi! Thanks for help. I just have one question. So, gtk.man() should be in watch or socket should be in watch? – Morasiu Nov 14 '17 at 08:45
  • 1
    `gtk.main` creates a main event loop. There you can watch event sources, like timeouts, idles, or I/O channels. The main loop will take care of calling your callbacks when events on these event sources trigger. You can even create you own event sources by creating new `GSource`s. The C documentation for `g_io_add_watch` says: `Adds the GIOChannel into the default main loop context with the default priority` so you basically say to the main loop: "here's a new event source I want to catch, call the associated callback when a event happens on that source". – liberforce Nov 14 '17 at 09:11
  • Ok. And how to pass socket as fd in `gio_channel = glib.IOChannel(sock)`? I get _TypeError: an integer is required_ – Morasiu Nov 14 '17 at 09:52
  • https://developer.gnome.org/glib/stable/glib-IO-Channels.html#glib-IO-Channels.description – liberforce Nov 14 '17 at 13:25
  • Call `glib.IOChannel.unix_new(fd)` with the file descriptor of your socket. – liberforce Nov 14 '17 at 13:26
  • Yeah, I've tried it but I get `AttributeError: type object 'glib.IOChannel' has no attribute 'unix_new` – Morasiu Nov 14 '17 at 13:36
  • Check your imports. This works for me: `python -c "import gi; gi.require_version('GLib', '2.0'); from gi.repository import GLib; help(GLib.IOChannel.unix_new)"` – liberforce Nov 14 '17 at 15:25
  • No, that command works for me with both python 2.7 and python 3. – liberforce Nov 15 '17 at 10:38
  • I am working right now on terminal and installing new libraries can be problematic. I have this lib on Python 3, but not Python 2.7. I need really need some solutions :/ – Morasiu Nov 15 '17 at 10:51
  • Don't you think that actually **running** the command line I gave to you and copy/pasting the actual result would be more productive than whining? I have no crystal ball to know how your system is configured or if you mistyped something... – liberforce Nov 15 '17 at 10:57
  • BTW, the doc clearly state GTK+ 3 (and hence, dependencies like GLib) work with both Python 2 & Python 3, wo there's no such thing as "I have this lib on Python 3, but not Python 2.7". See http://python-gtk-3-tutorial.readthedocs.io/en/latest/install.html#dependencies – liberforce Nov 15 '17 at 11:00
  • I did and got `ImportError: No module named gi`. Just like I told. I don't have this module. – Morasiu Nov 15 '17 at 11:01
  • Oh, my bad. I browse through a lot of questions and didn't realize it's pygtk you're using (meaning you're programming in GTK+ 2), and not pygobject (for GTK+ 3). The last release of pygtk is from 2011: this is an old and outdated and deprecated project, that no one should use in new development. Especially since GTK 4 is in preparation and will most probably be released in 2019. That being said, pygtk and pygobject are 2 different bindings, so the API is not the same. – liberforce Nov 15 '17 at 11:16
  • Yeah, I know. But I am working in closed, limited environment based on old, customized arch version with xfce. – Morasiu Nov 15 '17 at 11:20
  • You'll then get the help for `IOChannel` s with `python -c "import glib; help(glib.IOChannel)"`. However there's no `unix_new` method, so the best you can do is either try passing the fd to the (undocumented) constructor, or try to find an old exemple of code that uses an `IOChannel` with a socket, or give a look the pyglib code and see what it's really doing and expecting. – liberforce Nov 15 '17 at 11:25
  • I'll try. Thanks for everything. Do you know if there is a way to... I don't know, run everything in separate threads or something? That would at least solved part of the problem. – Morasiu Nov 15 '17 at 11:28
  • 1
    If you have a problem and try to solve it using threads, then you have two problems. GTK is not thread-safe, so if you start using threads the wrong way, you will shoot yourself in the foot. If you have no UI, that might be a solution, but try anything else before. So please try to pass you socket's file descriptor to the constructor of `glib.IOChannel` like I said. This should work, and there's an exemple (not using sockets, though) here: https://stackoverflow.com/questions/19294929/pygtk-asynchronous-output-implemented-with-io-add-watch-blocks-when-printing-la – liberforce Nov 15 '17 at 11:33
  • 1
    Hey. Sorry for my absent. I managed to pass socket to gio.Channel() like that `fd = conn.fileno()`. Thanks! – Morasiu Nov 16 '17 at 12:53
  • Sure. I decided to use Subprocess.Popen, but your idea was great too. I own you. – Morasiu Nov 21 '17 at 08:36