source: tags/0.2.1/screenshot.py @ 335

Revision 215, 8.2 KB checked in by marc, 5 years ago (diff)

Minor UI changes, debug meta option in config, fixed a major bug in screenshooting active windows

  • Property svn:keywords set to Id Rev
Line 
1#! /usr/bin/env python
2# -*- coding: utf8 -*-
3#
4# Itaka is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# any later version.
8#
9# Itaka is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with Itaka; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17#
18# Copyright 2003-2007 Marc E.
19# http://itaka.jardinpresente.com.ar
20#
21# $Id$
22
23""" Itaka screenshot engine """
24
25import gc, os, gtk, pygtk, error, traceback
26pygtk.require("2.0")
27
28class Screenshot:
29    """
30    Takes screenshots of windows or screens.
31    """
32
33    def __init__(self, guiinstance, scalingmethod=gtk.gdk.INTERP_BILINEAR):
34        """
35        Constructor.
36
37        @type scalingmethod: gtk.gdk.INTERP_TYPE
38        @param scalingmethod: A type of interpolation for screenshot scaling. U{http://pygtk.org/pygtk2reference/class-gdkpixbuf.html#method-gdkpixbuf--scale-simple}
39
40        @type guiinstance: instance
41        @param guiinstance: An instance of our L{Gui} class.
42        """
43
44        self.gui = guiinstance
45        self.itakaglobals = self.gui.itakaglobals
46        self.configuration = self.gui.configuration
47        self.console = self.gui.console
48        self.scalingmethod = scalingmethod
49
50        #: Whether our current window method failed or not
51        self.currentwindowfailed = False
52
53        #: Final absolute path to the screenshot file
54        self.shotFile = os.path.join(self.configuration['screenshot']['path'], 'itakashot.%s' % (self.configuration['screenshot']['format']))
55       
56        self.rootscreen = gtk.gdk.screen_get_default()
57        self.rootwindow = gtk.gdk.get_default_root_window()
58
59        self.screenwidth = gtk.gdk.screen_width()
60        self.screenheight = gtk.gdk.screen_height()
61
62    def find_current_active_window(self):
63        """
64        Find the current active window through the _NET_ACTIVE_WINDOW hint.
65
66        @rtype: tuple
67        @return: (int) window width, (int) window heigth, (int) window position x, (int) window position y.
68        """
69
70        if self.rootscreen.supports_net_wm_hint("_NET_ACTIVE_WINDOW") and self.rootscreen.supports_net_wm_hint("_NET_WM_WINDOW_TYPE"):
71            self.activewindow = self.rootscreen.get_active_window()
72
73            # Calculate the size of the window including window manager decorations
74            self.relativex, self.relativey, self.winw, self.winh, self.d = self.activewindow.get_geometry()
75            self.windowwidth = self.winw + (self.relativex*2)
76            self.windowheight = self.winh + (self.relativey+self.relativex)
77
78            # Calculate the position of where the window manager decorations start.
79            # get_position() will return the position of the window relative to the WM.
80            self.windowpositionx, self.windowpositiony = self.activewindow.get_root_origin()
81        else:
82            self.currentwindowfailed = True
83            raise error.ItakaScreenshotErrorWmHints, 'Window Manager does not support _NET_WM hints'
84   
85        # We do not want to grab the desktop window
86        if self.activewindow.property_get("_NET_WM_WINDOW_TYPE")[-1][0] == '_NET_WM_WINDOW_TYPE_DESKTOP':
87            self.currentwindowfailed = True
88            raise error.ItakaScreenshotErrorActiveDesktop, 'Active window is desktop'
89
90        return (self.windowwidth, self.windowheight, self.windowpositionx, self.windowpositiony)
91
92    def take_screenshot(self):
93        """
94        Take a screenshot of the whole screen or a window.
95
96        @rtype: str
97        @return: Path to the screenshot (L{self.shotFile})
98        """
99
100        # Get up to date configuration values everytime there is a request
101       
102        self.configuration = self.gui.configuration
103
104        if self.configuration['screenshot']['currentwindow'] and not self.itakaglobals.system == 'nt':
105            try:
106                self.currentwindow = self.find_current_active_window()
107            except error.ItakaScreenshotErrorWmHints:
108                self.gui.log.failure(('Screenshot', 'take_screenshot'), ('Can not grab the current window', 'Can not grab the curren window because your window manager does not support NET_WM_* hints'), 'WARNING')
109            except error.ItakaScreenshotErrorActiveDesktop:
110                self.gui.log.failure(('Screenshot', 'take_screenshot'), ('Not grabing the desktop as the current window', 'Your focus was on the destop when a client requested a screenshot, Itaka instead took a screenshot of the whole screen'), 'WARNING')
111
112            if not self.currentwindowfailed:
113                # Make the window size also the screen size for scaling purposes
114                self.activewindowwidth = self.currentwindow[0]
115                self.activewindowheight = self.currentwindow[1]
116
117                self.screenshot = gtk.gdk.Pixbuf.get_from_drawable(
118                        gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, self.activewindowwidth, self.activewindowheight),
119                        self.rootwindow,
120                        gtk.gdk.colormap_get_system(),
121                        self.currentwindow[2], self.currentwindow[3], 0, 0, self.activewindowwidth, self.activewindowheight)
122
123        if self.currentwindowfailed or not self.configuration['screenshot']['currentwindow'] or self.itakaglobals.system == 'nt':
124            self.screenshot = gtk.gdk.Pixbuf.get_from_drawable(
125                    gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, self.screenwidth, self.screenheight),
126                    self.rootwindow,
127                    gtk.gdk.colormap_get_system(),
128                    0, 0, 0, 0, self.screenwidth, self.screenheight)
129
130        # GTK manages errors this way
131        if not hasattr(self, 'screenshot') or self.screenshot is None:
132            # Reset the failure flag
133            self.currentwindowfailed = False
134            self.gui.log.failure(('Screenshot', 'take_screenshot'), ('Could not grab screenshot', 'GTK+ could not grab a screenshot of the screen.'), 'ERROR')
135            raise error.ItakaScreenshotError, 'Could not grab screenshot, GTK+ error'
136
137        if self.configuration['screenshot']['scale']:
138            # Make it just work, dont bother warning about very rare cases
139            if self.configuration['screenshot']['scalepercent'] == 0:
140                self.configuration['screenshot']['scalepercent'] = 1
141
142            if self.configuration['screenshot']['currentwindow'] and not self.currentwindowfailed and not self.itakaglobals.system == 'nt':
143                self.scalewidth = self.activewindowwidth * int(self.configuration['screenshot']['scalepercent']) / 100
144                self.scaleheight = self.activewindowheight * int(self.configuration['screenshot']['scalepercent']) / 100
145            else:
146                self.scalewidth = self.screenwidth * int(self.configuration['screenshot']['scalepercent']) / 100
147                self.scaleheight = self.screenheight * int(self.configuration['screenshot']['scalepercent']) / 100
148            self.screenshot = self.screenshot.scale_simple(self.scalewidth, self.scaleheight, self.scalingmethod)
149
150        # Save the screnshot, checking before if to set JPEG quality
151        try:
152            if self.configuration['screenshot']['format'] == 'jpeg':
153                self.screenshot.save(self.shotFile, self.configuration['screenshot']['format'].lower(), {"quality":str(self.configuration['screenshot']['quality'])})
154            else:
155                self.screenshot.save(self.shotFile, self.configuration['screenshot']['format'].lower())
156        except:
157            self.gui.log.failure(('Screenshot','take_screenshot'), ('Could not save screenshot', 'Could not save screenshot %s' % (traceback.format_exc())), 'ERROR')
158            raise error.ItakaSaveScreenshotError, "Could not save screenshot"
159
160        # Important workaround to avoid a memory leak.
161        # http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq08.004.htp
162        del self.screenshot
163        gc.collect()
164
165        # Reset the failure flag
166        self.currentwindowfailed = False
167
168        return self.shotFile
Note: See TracBrowser for help on using the repository browser.