LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-15-2010, 09:51 PM   #1
skykooler
Member
 
Registered: Feb 2010
Distribution: Ubuntu
Posts: 90

Rep: Reputation: 17
How to create PyGTK Gnome Screensaver?


I have created a PyGTK app (a binary clock) that I would like to turn into a screensaver. I added the .desktop file to /usr/share/applications/screensavers/ but all I get when I select it is a black screen. On the GnomeScreensaver FAQ (here) it says to use a gsthemewindow as the toplevel window, but the libraries given are in C. Is there any way to:
  1. Import this C library to get access to this toplevel window,
  2. Convert this GTK+ C library to PyGTK,
  3. or use a pygtk app as a screensaver in some other way?

Moved: This thread is more suitable in Programming and has been moved accordingly to help your thread/question get the exposure it deserves.

Last edited by archtoad6; 12-19-2010 at 06:47 AM. Reason: Moved
 
Old 01-23-2011, 02:34 PM   #2
Julian Andrews
LQ Newbie
 
Registered: Jan 2011
Distribution: Ubuntu
Posts: 21

Rep: Reputation: 13
I had a similar question myself, and was unable to find any good documentation online. I did, however find code which accomplishes exactly what you are looking for. (I found it in a project called gphotoframe - since this is my first post, I can't post any actual links). To save you some time, here's a somewhat stripped down version of the code you probably need:

Code:
class GsThemeWindow(gtk.Window):
    __gtype_name__ = 'GsThemeWindow'
    
    def __init__(self):
        super(GsThemeWindow, self).__init__()

    def do_realize(self):
        ident = os.environ.get('XSCREENSAVER_WINDOW')
        if ident:
            self.window = gdk.window_foreign_new(int(ident, 16))
            self.window.set_events(gdk.EXPOSURE_MASK | gdk.STRUCTURE_MASK)
            x, y, w, h, depth = self.window.get_geometry()
            self.size_allocate(gdk.Rectangle(x, y, w, h))
            self.set_default_size(w, h)
            self.set_decorated(False)
        else:
            self.window = gdk.Window(
                self.get_parent_window(),
                width=self.allocation.width,
                height=self.allocation.height,
                window_type=gdk.WINDOW_TOPLEVEL,
                wclass=gdk.INPUT_OUTPUT,
                event_mask=self.get_events() | gdk.EXPOSURE_MASK)
        self.window.set_user_data(self)
        self.set_flags(self.flags() | gtk.REALIZED)
        self.style.attach(self.window)
You will, of course, also need to write a .desktop file, but most of your other problems should be solved by using one of these GsThemeWindow objects in place of your application's main gtk.Window. As far as I can tell, this code simply tries to find as XSCREENSAVER_WINDOW to draw to, and if that fails, it creates a standalone window.
 
1 members found this post helpful.
Old 01-24-2011, 01:56 AM   #3
skykooler
Member
 
Registered: Feb 2010
Distribution: Ubuntu
Posts: 90

Original Poster
Rep: Reputation: 17
Thank you, but how do I use the new window type? Here is the code I am using for my app ( a binary clock app) - for some reason Cairo won't draw anything to the screen. The button (only there for testing purposes) shows up fine in regular mode, but not when run as a screensaver.

Code:
#!/usr/bin/python
import sys
import os
import gtk
from gtk import gdk
import cairo
import time
import gobject
launchpad_available = False

# Add project root directory (enable symlink, and trunk execution).
PROJECT_ROOT_DIRECTORY = os.path.abspath(
    os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))

if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'gbinclock'))
    and PROJECT_ROOT_DIRECTORY not in sys.path):
    sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
    os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses

def d2b(n):
	x=bin(n)[2:]
	y=[0, 0, 0, 0, 0, 0]
	for i in range(0, len(x)):
		y[i-len(x)]=x[i]
	return y

class GsThemeWindow(gtk.Window):
    __gtype_name__ = 'GsThemeWindow'
    def __init__(self):
        super(GsThemeWindow, self).__init__()
    def do_realize(self):
        ident = os.environ.get('XSCREENSAVER_WINDOW')
        if ident:
            self.window = gdk.window_foreign_new(int(ident, 16))
            self.window.set_events(gdk.EXPOSURE_MASK | gdk.STRUCTURE_MASK)
            x, y, w, h, depth = self.window.get_geometry()
            self.size_allocate(gdk.Rectangle(x, y, w, h))
            self.set_default_size(w, h)
            self.set_decorated(False)
        else:
            self.window = gdk.Window(
                self.get_parent_window(),
                width=self.allocation.width,
                height=self.allocation.height,
                window_type=gdk.WINDOW_TOPLEVEL,
                wclass=gdk.INPUT_OUTPUT,
                event_mask=self.get_events() | gdk.EXPOSURE_MASK)
        self.window.set_user_data(self)
        self.set_flags(self.flags() | gtk.REALIZED)
        self.style.attach(self.window)
        vbox = gtk.VBox(False, 0)
        self.add(vbox)
        drawingarea1 = gtk.DrawingArea()
	drawingarea1.set_size_request(500, 500)
        vbox.show()
        vbox.pack_start(drawingarea1, True, True, 0)
        drawingarea1.show()
        abutton = gtk.Button("OK")
        abutton.set_use_stock(True)
        abutton.set_size_request(50, -1)
        vbox.pack_start(abutton, True, True, 0)
        abutton.show()
        self.show()
        cra = drawingarea1.window.cairo_create()
        x,y,w,h = drawingarea1.allocation
        self.expose_event(cra, x, y, w, h)
        self.connect("expose-event", self.expose_event)
        self.connect("destroy", self.on_destroy)
    def expose_event(self, cra, x, y, w, h):
        print "g"
        timemat = [d2b(time.localtime(time.time())[3]), d2b(time.localtime(time.time())[4]), d2b(time.localtime(time.time())[5])]
        surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, w,h)
        cr = cairo.Context(surf)
        surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/background.png")
        pattern = cairo.SurfacePattern(surface)
        pattern.set_extend(cairo.EXTEND_REPEAT)
        cr.set_source(pattern)
        cr.paint()
        try:
            print sys.argv[1]
            if sys.argv[1]=="1":
                for i in range(0, 3):
                    py = 0-(h/3.0*(i+0.5))
                    for j in range(0, 6):
                        px = (w/6.0*(5-j+0.5))-w+32
                        if timemat[i][j]=="1":
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_on.png")
                        else:
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_off.png")
                        pattern = cairo.SurfacePattern(surface)
                        pattern.set_extend(cairo.EXTEND_NONE)
                        matrix = cairo.Matrix(1,0,0,1,px,py)
                        pattern.set_matrix(matrix)
                        cr.set_source(pattern)
                        cr.paint() 
            else:
                for i in range(0, 3):
                    px = 0-(w/3.0*(i+0.5))
                    for j in range(0, 6):
                        py = (h/6.0*(5-j+0.5))-h+32
                        if timemat[i][j]=="1":
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_on.png")
                        else:
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_off.png")
                        pattern = cairo.SurfacePattern(surface)
                        pattern.set_extend(cairo.EXTEND_NONE)
                        matrix = cairo.Matrix(1,0,0,1,px,py)
                        pattern.set_matrix(matrix)
                        cr.set_source(pattern)
                        cr.paint()
        except:
                for i in range(0, 3):
                    px = 0-(w/3.0*(i+0.5))
                    for j in range(0, 6):
                        py = (h/6.0*(5-j+0.5))-h+32
                        if timemat[i][j]=="1":
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_on.png")
                        else:
                            surface = cairo.ImageSurface.create_from_png("/usr/share/gbinclock/media/light_off.png")
                        pattern = cairo.SurfacePattern(surface)
                        pattern.set_extend(cairo.EXTEND_NONE)
                        matrix = cairo.Matrix(1,0,0,1,px,py)
                        pattern.set_matrix(matrix)
                        cr.set_source(pattern)
                        cr.paint()
        cra.set_source_surface(surf)
        cra.paint()
        source_id = gobject.timeout_add(100, self.expose_event, cra, x, y, w, h)
    def quit(self, widget, data=None):
        """Signal handler for closing the GsThemeWindow."""
        self.destroy()
    def on_destroy(self, widget, data=None):
        """Called when the GbinclockWindow is closed."""
        # Clean up code for saving application state should be added here.
        gtk.main_quit()

if __name__ == "__main__":
    # Run the application.
    window = GsThemeWindow()
    window.show()
    window.set_decorated (False);
    window.set_skip_taskbar_hint (True);
    window.set_skip_pager_hint (True);
    window.set_keep_above (True);
    window.fullscreen();
    gtk.main()
 
Old 01-24-2011, 12:14 PM   #4
Julian Andrews
LQ Newbie
 
Registered: Jan 2011
Distribution: Ubuntu
Posts: 21

Rep: Reputation: 13
Hi,

First, a caveat - I'm pretty far from an expert in GTK, in fact, this screensaver was my first GTK project. That said, I was also using a gtk.DrawingArea with cairo in a box, so what worked for me ought to work for you!

I think the problem with your code has to do with how you're dealing with expose events. When I run your code, I get a TypeError every time an actual expose_event signal comes down the line (rather than your direct calls of expose_event) because the wrong number of arguments are being passed. If gnome-screensaver gets an error when it tries to run the code, it will stop running the screensaver even if the main thread doesn't crash. You might want to create a custom drawing area class to do your drawing.

Code:
class MyDrawingArea(gtk.DrawingArea):
    __gsignals__ = {"expose_event": "override"}
    
    def do_expose_event(self, event):
        cra = self.window.cairo_create()
        x = event.area.x
        y = event.area.y
        w = event.area.width
        h = event.area.height
        # Your drawing code here

    def run(self):
        self.queue_draw()
        gobject.timeout_add(100, self.run)
Then don't connect expose events in the main window, and instantiate a custom drawing area object instead of the generic gtk.DrawingArea. When I ran your code modified like this, I was able to get it to draw some shapes (obviously without your graphics, I couldn't easily test your whole drawing routine.) Also, you don't really want to queue a new expose event on every expose event since this will lead to an ever increasing number of timeouts, and program slowdown. I've suggested one possible approach above - you can call run on your drawing area once you've instantiated it.

I hope this helps!
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Create Default Screensaver mccartjd Linux - Newbie 1 05-14-2008 08:34 AM
FC6 GNOME + Beryl + gnome-screensaver focus issue rhoekstra Fedora 3 01-09-2007 01:03 AM
gnome-screensaver fakie_flip Linux - Software 2 06-26-2006 03:05 AM
pygtk-2.0 not found during install of gnome-python? morrolan Linux - Software 9 02-02-2004 01:13 AM
gDesklets, pyGTK, gnome-python ilhbutshm Slackware 4 12-11-2003 07:44 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:32 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration