diff --git a/set_gdm_backgroud.py b/set_gdm_backgroud.py index 16540db..c2d48c1 100755 --- a/set_gdm_backgroud.py +++ b/set_gdm_backgroud.py @@ -14,234 +14,273 @@ if gtk.pygtk_version < (2,3,90): print "PyGtk 2.3.90 or later required for this example" raise SystemExit -class HelloWorld: - pixbuf = None - imagen = gtk.Image() - ruta = "/home/mauro/Imágenes/art/4995443800_e68125ac35_o.jpg" - conffile = "/home/mauro/git/greeter.gconf-defaults" - layout = "zoom" #wallpaper, centered, scaled, stretched, zoom +class App: + path = "/usr/share/images/desktop-base/moreblue-orbit-gdm.svg" + disp = "stretched" + conffile = "/etc/gdm3/greeter.gconf-defaults" + image = gtk.Image() + screenw = -1 + screenh = -1 - def dibujar_imagen(self): - imagen_cargada = gtk.gdk.pixbuf_new_from_file(self.ruta) - ancho_img = imagen_cargada.get_width() - alto_img = imagen_cargada.get_height() + # redraw the screen thumbnail with currently selected file and disposition + def redraw(self): - ratio_disp = float(self.wscreen)/float(self.hscreen) - ratio_imag = float(ancho_img)/float(alto_img) + # new pixbuf from current path + readimg = gtk.gdk.pixbuf_new_from_file(self.path) + imgw = readimg.get_width() + imgh = readimg.get_height() - ancho_img_scaled = None - alto_img_scaled = None + # calculate selected image and screen proportions (width-to-height ratio) + disp_ratio = float(self.screenw)/float(self.screenh) + img_ratio = float(imgw)/float(imgh) - self.pixbuf.fill(0x88888888) - self.pixbuf.saturate_and_pixelate(self.pixbuf, 0.0, True) + # actual width of the image on the screen thumbnail + thumbw = -1 + thumbh = -1 + + # create an pixbuf for the thumbn, and fill it with a "background" pattern + thumbpixbuf = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, True, 8, + int(self.screenw/4.0), + int(self.screenh/4.0) ) + thumbpixbuf.fill(0x88888888) + thumbpixbuf.saturate_and_pixelate(thumbpixbuf, 0.0, True) - if self.layout == "zoom": - if ratio_disp > ratio_imag: - ancho_img_scaled = self.wscreen/4.0 - alto_img_scaled = alto_img*((self.wscreen/4.0)/ancho_img) + # switch between the different disposition styles + if self.disp == "zoom": + + # if display wider than image, scale image to fit screen width + if disp_ratio > img_ratio: + thumbw = int(self.screenw/4.0) + thumbh = int(imgh*((self.screenw/4.0)/imgw)) + + # else scale image to fit screen height else: - alto_img_scaled = self.hscreen/4.0 - ancho_img_scaled = ancho_img*((self.hscreen/4.0)/alto_img) + thumbh = int(self.screenh/4.0) + thumbw = int(imgw*((self.screenh/4.0)/imgh)) + + # scale previously loaded image and copy to the screen thumbnail pixbuf + readimg = readimg.scale_simple(thumbw,thumbh,gtk.gdk.INTERP_BILINEAR) + readimg.copy_area( int((thumbw-self.screenw/4.0)/2), + int((thumbh-self.screenh/4.0)/2), + int(self.screenw/4), int(self.screenh/4), + thumbpixbuf, 0, 0) - imagen_cargada = imagen_cargada.scale_simple(int(ancho_img_scaled), - int(alto_img_scaled), - gtk.gdk.INTERP_BILINEAR) - imagen_cargada.copy_area( int((ancho_img_scaled-self.wscreen/4.0)/2), - int((alto_img_scaled-self.hscreen/4.0)/2), - int(self.wscreen/4), int(self.hscreen/4), - self.pixbuf, 0, 0) - elif self.layout == "scaled": - scale_x = (self.wscreen/4.0)/ancho_img - scale_y = (self.hscreen/4.0)/alto_img - ancho_img_scaled = ancho_img*min(scale_x, scale_y) - alto_img_scaled = alto_img*min(scale_x, scale_y) + elif self.disp == "scaled": - imagen_cargada = imagen_cargada.scale_simple(int(ancho_img_scaled), - int(alto_img_scaled), - gtk.gdk.INTERP_BILINEAR) - imagen_cargada.copy_area( 0, 0, ancho_img_scaled, alto_img_scaled, - self.pixbuf, - int((self.wscreen/4-ancho_img_scaled)/2), - int((self.hscreen/4-alto_img_scaled)/2)) - elif self.layout == "centered": - imagen_cargada = imagen_cargada.scale_simple(int(ancho_img/4), - int(alto_img/4), - gtk.gdk.INTERP_BILINEAR) + # with the "scaled" disposition, image is scaled + # so that it fits entirely onscreen + xscale = (self.screenw/4.0)/imgw + yscale = (self.screenh/4.0)/imgh - x0 = (self.wscreen-ancho_img)/8 - y0 = (self.hscreen-alto_img)/8 + thumbw = int(imgw*min(xscale, yscale)) + thumbh = int(imgh*min(yscale, yscale)) + + readimg = readimg.scale_simple(thumbw,thumbh,gtk.gdk.INTERP_BILINEAR) + readimg.copy_area( 0, 0, thumbw, thumbh, thumbpixbuf, + int((self.screenw/4-thumbw)/2), + int((self.screenh/4-thumbh)/2)) + + + elif self.disp == "centered": - imagen_cargada.copy_area( max(-x0,0), max(-y0,0), - min(self.wscreen/4,ancho_img/4), - min(self.hscreen/4,alto_img/4), - self.pixbuf, max(x0,0), max(y0,0)) - print "copy_area(" + str(max(-x0,0)) + "," + str(max(-y0,0)) + "," \ - + str(min(self.wscreen/4,ancho_img/4)) + "," \ - + str(min(self.hscreen/4,alto_img/4)) + ",self.pixbuf," \ - + str(max(x0,0)) + "," + str(max(y0,0)) + ") " + str(x0) + " "\ - + str(y0) + " " + str(ancho_img) + " " + str(alto_img) - elif self.layout == "stretched": - imagen_cargada = imagen_cargada.scale_simple(self.wscreen/4, - self.hscreen/4, - gtk.gdk.INTERP_BILINEAR) - imagen_cargada.copy_area( 0, 0,self.wscreen/4, self.hscreen/4, - self.pixbuf, 0, 0) + # scale image to 1/4 its original size + # (the screen thumbnail is 1/4 of the real screen size) + readimg = readimg.scale_simple( int(imgw/4), int(imgh/4), + gtk.gdk.INTERP_BILINEAR) + + # the visible area coordinates of the image + # (if negative, the image is bigger than the screen) + x0 = int((self.screenw-imgw)/8) + y0 = int((self.screenh-imgh)/8) + + readimg.copy_area( max(-x0,0), max(-y0,0), + int(min(self.screenw/4,imgw/4)), + int(min(self.screenh/4,imgh/4)), + thumbpixbuf, max(x0,0), max(y0,0)) + + + elif self.disp == "stretched": + + # in this case, simply stretch image so that both width and height + # are the same as the screen's + readimg = readimg.scale_simple( int(self.screenw/4), + int(self.screenh/4), + gtk.gdk.INTERP_BILINEAR) + readimg.copy_area( 0, 0, int(self.screenw/4), int(self.screenh/4), + thumbpixbuf, 0, 0) + - elif self.layout == "wallpaper": - imagen_cargada = imagen_cargada.scale_simple(int(ancho_img/4), - int(alto_img/4), - gtk.gdk.INTERP_BILINEAR) + elif self.disp == "wallpaper": + + # scale image to 1/4 as in centered + readimg = readimg.scale_simple( int(imgw/4), + int(imgh/4), + gtk.gdk.INTERP_BILINEAR) + + # copy image as tiles until we fill the entire screen x0=0 - while( x0 < self.wscreen ): + while( x0 < self.screenw ): y0=0 - while( y0 < self.hscreen): - imagen_cargada.copy_area( 0, 0, - min(self.wscreen/4-x0,ancho_img/4), - min(self.hscreen/4-y0,alto_img/4), - self.pixbuf, x0, y0) - y0 += alto_img/4 - x0 += ancho_img/4 - - self.imagen.set_from_pixbuf(self.pixbuf) + while( y0 < self.screenh): + readimg.copy_area( 0, 0, + int(min(self.screenw/4-x0,imgw/4)), + int(min(self.screenh/4-y0,imgh/4)), + thumbpixbuf, x0, y0) + y0 += imgh/4 + x0 += imgw/4 + # finally draw the gtk.Image from the pixbuf + self.image.set_from_pixbuf(thumbpixbuf) - def get_screen_size(self): + # read GDM3 configuration file, and set correspondig variables + def read_config( self ): + + with open( self.conffile, 'r') as conf: + + for line in conf: + m1 = re.match(r"\s*/desktop/gnome/background/picture_filename\s+((?:\S*(?:(?<=\\)\s)*)+)", line) + m2 = re.match(r"\s*/desktop/gnome/background/picture_options\s+(\w+)", line) + + if m1: + print "Image file option read: " + m1.group(1) + self.path = m1.group(1) + + elif m2: + print "Image disposition option read: " + m2.group(1) + self.disp = m2.group(1) + + # save GDM3 options file, replacing the options with the current ones + def save_config( self, widget=None ): + + with open(self.conffile, 'r') as conf: + out = "" + + for line in conf: + m1 = re.match(r"\s*/desktop/gnome/background/picture_filename\s+((?:\S*(?:(?<=\\)\s)*)+)", line) + m2 = re.match(r"\s*/desktop/gnome/background/picture_options\s+(\w+)", line) + + # if the current line matchs the picture_filename option, replace + # it with a new one containing the current value of path + if m1: + out += "/desktop/gnome/background/picture_filename " \ + + self.path + "\n" + + # else if it macthes the picture_options option, put the + # value of disp instead + elif m2: + out += "/desktop/gnome/background/picture_options "\ + + self.disp + "\n" + + # else copy the line as-is + else: + out += line + + # save the file putting in there the value of out + with open(self.conffile, 'w') as f: + f.write(out) + print "Configuration file saved." + + # close event. don't know if or what it should do + def close(self, widget, event, data=None): + return + + # response event. should save setting if "apply", exit if "close" + def response( self, widget, response): + + if response == gtk.RESPONSE_CLOSE or response == gtk.RESPONSE_DELETE_EVENT: + gtk.main_quit() + + elif response == gtk.RESPONSE_APPLY: + self.save_config() + + # current image path changed callback. should redraw the screen thumbnail + def path_changed( self, widget, response): + + if response == gtk.RESPONSE_ACCEPT: + self.path = widget.get_filename() + self.redraw() + + # current disposition option changed callback. should redraw + def disp_changed( self, widget): + self.disp = widget.get_active_text() + self.redraw() + + # initialization function. called upon instantiating a new App object + def __init__ (self): + + # obtain the root screen width and height (status,output)=commands.getstatusoutput('xwininfo -root|grep "geometry"') m1 = re.match(r".*geometry\s([0-9]+)x([0-9]+)\+.*", output) if m1: - return (int(m1.group(1)), int(m1.group(2))) - return (-1, -1) + self.screenw = int(m1.group(1)) + self.screenh = int(m1.group(2)) + else: + print "Error obtaining screen size. Defaulting to 1024x768." + print "Verify that the xwininfo command is available in your system." + self.screenw = 1024 + self.screenh = 768 + + # read config file to set path and disp accordingly, then redraw + self.read_config() + self.redraw() - # This is a callback function. The data arguments are ignored - # in this example. More on callbacks below. - def hello(self, widget, data=None): - print "Hello World" - - def delete_event(self, widget, event, data=None): - #print "delete event occurred" - # Change FALSE to TRUE and the main window will not be destroyed - # with a "delete_event". - return False - - def destroy(self, widget, data=None): - print "destroy signal occurred" - gtk.main_quit() - - def imagen_seleccionada( self, widget, response): - if response == gtk.RESPONSE_ACCEPT: - self.ruta = widget.get_filename() - self.dibujar_imagen() - - def layout_cambiado( self, widget): - self.layout = widget.get_active_text() - self.dibujar_imagen() - - def leer_conf( self ): - with open(self.conffile, 'r') as conf: - for linea in conf: - m1 = re.match(r"\s*/desktop/gnome/background/picture_filename\s+((?:\S*(?:(?<=\\)\s)*)+)", linea) - m2 = re.match(r"\s*/desktop/gnome/background/picture_options\s+(\w+)", linea) - if m1: - print "imagen encontrada. " + m1.group(1) - self.ruta = m1.group(1) - elif m2: - print "configuración encontrada: " + m2.group(1) - self.layout = m2.group(1) - - def guardar_conf( self, widget ): - with open(self.conffile, 'r') as conf: - salida = "" - for linea in conf: - m1 = re.match(r"\s*/desktop/gnome/background/picture_filename\s+((?:\S*(?:(?<=\\)\s)*)+)", linea) - m2 = re.match(r"\s*/desktop/gnome/background/picture_options\s+(\w+)", linea) - if m1: - salida += "/desktop/gnome/background/picture_filename " + self.ruta + "\n" - elif m2: - salida += "/desktop/gnome/background/picture_options " + self.layout + "\n" - else: - salida += linea - - with open(self.conffile, 'w') as f: - f.write(salida) - print "Se ha guardado la nueva configuración." - - def __init__(self): - - (self.wscreen, self.hscreen) = self.get_screen_size() - - self.leer_conf() - - self.pixbuf = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, True, 8, - int(self.wscreen/4.0), - int(self.hscreen/4.0) ) # create a new window - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - # self.window.set_size_request(400,600) - - # The data passed to the callback - # function is NULL and is ignored in the callback function. - self.window.connect("delete_event", self.delete_event) - - # Here we connect the "destroy" event to a signal handler. - # This event occurs when we call gtk_widget_destroy() on the window, - # or if we return FALSE in the "delete_event" callback. - self.window.connect("destroy", self.destroy) - - # Sets the border width of the window. - self.window.set_border_width(10) - - self.label = gtk.Label("Elija la imagen nueva a mostrar\n\ -La imagen actualmente configurada es /home/mauro.") - self.label.set_use_markup(True) + self.window = gtk.Dialog( "Change GDM3 background", + None, + gtk.DIALOG_NO_SEPARATOR) + # add "apply" anc "close" buttons + self.window.add_buttons( gtk.STOCK_APPLY, gtk.RESPONSE_APPLY, + gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) - # Creates a new button with the label "Hello World". - self.button = gtk.Button("Hello World") - - self.button.connect("clicked", self.guardar_conf) - #self.button.connect_object("clicked", gtk.Widget.destroy, self.window) - - self.vbox = gtk.VBox(); - self.hbox = gtk.HBox(); + self.window.connect("close", self.close) + self.window.connect("response", self.response) - self.dibujar_imagen() - - self.filechooserdialog = gtk.FileChooserDialog("Elija un archivo", - self.window, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, - gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) - self.filechooserbutton = gtk.FileChooserButton(self.filechooserdialog) - self.filechooserdialog.connect("response", self.imagen_seleccionada) + # file chooser dialog and button + self.filedialog = gtk.FileChooserDialog( "Choose a file", self.window, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, + gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + self.filebutton = gtk.FileChooserButton(self.filedialog) + self.filedialog.connect( "response", self.path_changed) + # disposition selection combo self.combo = gtk.combo_box_new_text() self.combo.append_text("zoom") self.combo.append_text("centered") self.combo.append_text("stretched") self.combo.append_text("scaled") self.combo.append_text("wallpaper") - self.combo.connect("changed", self.layout_cambiado) + self.combo.connect( "changed", self.disp_changed) - self.vbox.pack_start(self.label) - self.vbox.pack_start(self.imagen) - self.vbox.pack_start(self.filechooserbutton) - self.vbox.pack_start(self.hbox) - self.hbox.pack_start(self.combo) - self.hbox.pack_start(self.button) - - self.vbox.show() - self.filechooserbutton.show() - self.hbox.show() - self.label.show() - self.imagen.show() - self.combo.show() - - self.window.add(self.vbox) + while self.combo.get_active_text() != self.disp: + self.combo.set_active( self.combo.get_active() + 1 ) + + self.filedialog.set_filename(self.path) - # The final step is to display this newly created widget. - self.button.show() - - # and the window + #self.window.set_border_width(4) + + # aux hbox + self.hbox = gtk.HBox() + self.hbox.pack_start(self.filebutton) + self.hbox.pack_end(self.combo) + self.hbox.set_border_width(5) + + # image frame + self.frame = gtk.Frame() + self.frame.set_shadow_type(gtk.SHADOW_IN) + self.frame.set_border_width(6) + self.frame.add(self.image) + + # the window vbox + self.window.vbox.pack_start(self.frame) + self.window.vbox.pack_start(self.hbox) + + self.frame.show() + self.image.show() + self.filebutton.show() + self.combo.show() + self.hbox.show() self.window.show() def main(self): @@ -250,5 +289,5 @@ La imagen actualmente configurada es /home/mauro.") gtk.main() if __name__ == "__main__": - hello = HelloWorld() - hello.main() + app = App() + app.main()