{"id":902,"date":"2011-11-13T13:39:14","date_gmt":"2011-11-13T12:39:14","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=902"},"modified":"2011-11-13T13:39:14","modified_gmt":"2011-11-13T12:39:14","slug":"cronopete-2-1-0-pensando-en-todos","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=902","title":{"rendered":"Cronopete 2.1.0: pensando en todos"},"content":{"rendered":"<p>Acabo de lanzar la versi\u00f3n 2.1.0 de Cronopete, que a\u00f1ade una peque\u00f1a modificaci\u00f3n en el efecto zoom para intentar que vaya mejor en ordenadores lentos.<\/p>\n<p>Para entender el problema, lo primero es explicar como realic\u00e9 el efecto de zoom. Al principio quer\u00eda usar <a href=\"http:\/\/www.clutter-project.org\/\" target=\"_blank\">clutter<\/a>, porque se supone que permite hacer cosas como que una ventana se mueva en tres dimensiones y dem\u00e1s, que es justo lo que pretend\u00eda. Por desgracia, para poder meter dentro de un actor de clutter un elemento de GTK (en este caso el navegador de ficheros), ten\u00eda que trabajar con GTK3, porque en GTK2 no est\u00e1 soportado.<\/p>\n<p>Prob\u00e9 a usar ventanas aut\u00e9nticas, pero el cambio de tama\u00f1o para hacer el efecto era lent\u00edsimo, por lo que no resultaba. Despu\u00e9s de muchas pruebas, me li\u00e9 la manta a la cabeza e intent\u00e9 hacerlo de una forma radicalmente diferente. La soluci\u00f3n que encontr\u00e9 era tan \u00absimple\u00bb como usar la funci\u00f3n <a href=\"http:\/\/developer.gnome.org\/gdk\/stable\/gdk-Pixbufs.html#gdk-pixbuf-get-from-drawable\" target=\"_blank\">gdk_pixbuf_get_from_drawable<\/a> para hacer una captura de la ventana, y usar el pixmap resultante para hacer el efecto de scroll mediante <a href=\"http:\/\/cairographics.org\/\" target=\"_blank\">Cairo<\/a>. Al ser una imagen est\u00e1tica en lugar de un conjunto de widgets, el redimensionado deber\u00eda ser r\u00e1pido, incluso haci\u00e9ndolo por software.<\/p>\n<p>Pero las cosas, por desgracia, no son tan sencillas en la pr\u00e1ctica. Cada vez que hac\u00eda una captura, me sal\u00eda un pixmap negro, o con la ventana tal y como estaba <em>antes<\/em> de cualquier cambio que quisiese reflejar. El motivo es que el redibujado de una ventana en GTK es as\u00edncrono: yo puedo dar la orden de mostrar algo, de cambiar un texto, o de a\u00f1adir m\u00e1s elementos a una lista, pero hasta que no retorne al bucle principal de GTK, no se llevar\u00e1 a cabo esa acci\u00f3n.<\/p>\n<p>La primera soluci\u00f3n que encontr\u00e9 fue aprovechar el temporizador que uso para las animaciones para sacar la captura: as\u00ed, tras dar la orden de cambiar de carpeta, por ejemplo, marcaba un flag que indicaba que hab\u00eda que hacer una nueva captura, activaba el temporizador y sal\u00eda del callback, volviendo al bucle principal. En ese momento GTK repintaba toda la ventana, que quedaba lista para ser capturada en cuanto venciese el temporizador.<\/p>\n<p>Esto funcionaba en mi ordenador sin problemas, as\u00ed que publiqu\u00e9 la versi\u00f3n 2.0.0; pero m\u00e1s tarde, al tener la oportunidad de probarlo en un equipo lento, me encontr\u00e9 con que no iba bien, pues capturaba antes de tiempo. Era obvio que GTK le daba m\u00e1s prioridad a los temporizadores que al redibujado de ventanas, por lo que, en ese equipo, no le daba tiempo a repintar todo.<\/p>\n<p>Pregunt\u00e9 en los foros si GTK emit\u00eda alguna se\u00f1al cuando terminaba de redibujar una ventana, pero nadie respondi\u00f3, as\u00ed que decid\u00ed probar yo mismo todas las se\u00f1ales que emite un widget, a ver cual me pod\u00eda ser \u00fatil. Prob\u00e9 con <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-damage-event\" target=\"_blank\">damage-event<\/a>, <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-composited-changed\" target=\"_blank\">composited-changed<\/a>, <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-expose-event\" target=\"_blank\">expose-event<\/a>, <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-realize\" target=\"_blank\">realize<\/a>, <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-screen-changed\" target=\"_blank\">screen-changed<\/a> y <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-show\" target=\"_blank\">show<\/a>, antes de encontrar la que parec\u00eda la soluci\u00f3n a mis problemas: <a href=\"http:\/\/developer.gnome.org\/gtk\/2.24\/GtkWidget.html#GtkWidget-map-event\" target=\"_blank\">map-event<\/a>. Pero aunque en el c\u00f3digo de ejemplo que hice funcionaba, cuando la prob\u00e9 en el c\u00f3digo de cron\u00f3pete tambi\u00e9n fall\u00f3.<\/p>\n<p>Hasta que, al final, revisando otras funciones, encontr\u00e9 la soluci\u00f3n en las <a href=\"http:\/\/developer.gnome.org\/gtk-tutorial\/stable\/x1790.html\" target=\"_blank\">funciones idle<\/a>. Estas se ejecutan cuando no queda ninguna tarea por hacer en el bucle principal, as\u00ed que la soluci\u00f3n fue tan sencilla como a\u00f1adir una funci\u00f3n idle que haga la captura: \u00e9sta no ser\u00e1 llamada hasta que la cola est\u00e9 vac\u00eda, lo que ser\u00e1 cuando se hayan procesado todos los eventos de repintado de widgets dentro de la ventana que queremos capturar, o sea, cuando \u00e9sta ya est\u00e9 completamente lista.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Acabo de lanzar la versi\u00f3n 2.1.0 de Cronopete, que a\u00f1ade una peque\u00f1a modificaci\u00f3n en el efecto zoom para intentar que vaya mejor en ordenadores lentos. Para entender el problema, lo primero es explicar como realic\u00e9 el efecto de zoom. Al principio quer\u00eda usar clutter, porque se supone que permite hacer cosas como que una ventana &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=902\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">Cronopete 2.1.0: pensando en todos<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,6,7],"tags":[],"class_list":["post-902","post","type-post","status-publish","format-standard","hentry","category-nueva-version","category-trucos","category-tutoriales"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=902"}],"version-history":[{"count":0,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/902\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}