Nova Ligero, incrementando la socio-adaptabilidad de la Distribución Cubana de GNU/Linux

Share Embed


Descripción

NOVA LIGERO, INCREMENTANDO LA SOCIO-ADAPTABILIDAD DE LA DISTRIBUCIÓN CUBANA DE GNU/LINUX. Ing. Miguel Albalat Aguila, Ing. Abel Fírvida Donéstevez, Dairelys García Rivas, Ing. Jorge Luis Machín Castillo Universidad de las Ciencias Informáticas (UCI), La Habana, Cuba. [email protected]

RESUMEN Uno de los mayores impedimentos que se encuentra a su paso la informatización de la sociedad cubana y con ella el proceso de migración a aplicaciones libres y de código abierto es la obsolescencia del parque tecnológico desplegado en la isla. Nova, el sistema operativo cubano, como punta de lanza en dicho proceso se ha dado a la tarea de crear una línea que alargue la vida de estas computadoras, que ya sea por sus bajas prestaciones o por el tiempo que llevan prestando servicio, no permiten el correcto funcionamiento de un sistema operativo convencional. La presente investigación describe parte del proceso de desarrollo de Guano, una alternativa criolla para combatir la obsolescencia. Palabras clave: Nova, Migración, Software Libre, obsolescencia. NOVA LIGHT, INCREASING SOCIAL - FITNESS FOR THE CUBAN GNU / LINUX DISTRIBUTION. ABSTRACT One of the biggest impediments that has found in its way the computerization of Cuban society and with it the migration process to free and open source software is the obsolescence of deployed technology park on the island. Nova, Cuban operating system, as a spearhead in this process has been given the task of creating a line that extends life of these computers, which either by their low performance or how long they have served, do not allow the proper functioning of a conventional operating system. This research describes part of the development of Guano, a native alternative to combat obsolescence. Keywords: Nova, Migration, Free Software obsolescence. INTRODUCCIÓN A finales del año 2011 con la investigación “CONCEPTUALIZACIÓN Y REESTRUCTURACIÓN ESTRATÉGICA DE LA DISTRIBUCIÓN CUBANA DE GNU/LINUX “NOVA”” del entonces ingeniero Allan Pierra Fuentes el equipo de Nova, la distribución cubana de GNU/Linux 1, concretó cuatro directivas – conocidas como las 4S de Pierra - para el uso y desarrollo de las Tecnologías de la Información y las Comunicaciones (TIC) en los Órganos y Organismos de la Administración Central del Estado (OOACE). Ellas son:

1. Seguridad: El modelo de desarrollo colaborativo que nos propone el movimiento de software libre, el acceso al código fuente y el exhaustivo proceso de revisión y auditoría de código garantizará un sistema seguro de ataques y sin puertas traseras. 2.

Soberanía: La Soberanía Tecnológica es la capacidad de un País para desarrollarse en dicho campo en forma autónoma. No supone autarquía (independencia absoluta) sino capacidad decisional sobre su uso y desarrollo. (Troyano, 2010)

3.

Socio-adaptabilidad: Las bases tecnológicas para la informatización de cuba, deben ser hechas por cubanos y para los cubanos, logrando inigualable adaptabilidad a las condiciones de nuestro País.

4.

Sostenibilidad: La constante asimilación e investigación de las nuevas tecnologías, la planificación, los modelos novedosos de comercialización y el uso racional de los recursos humanos, materiales y naturales,

1 Es uno de los términos empleados para referirse a la combinación del núcleo similar a Unix denominado Linux, que es usado con herramientas del sistema GNU.

garantizará a nuestras soluciones, vigencia y sostenibilidad a largo plazo. Nova Ligero, proyecto creado desde el año 2009, se apropió, como ninguna otra rama del sistema operativo cubano, del principio Socio-adaptabilidad, en lo adelante cada versión de este producto tendrá como meta lograr los más altos niveles de este indicador, sin descuidar los demás por supuesto. ¿QUE CARACTERÍSTICAS PRESENTA EL ENTORNO INFORMÁTICO EN CUBA? El entorno informático en Cuba se caracteriza por una predominación de S.O. de tipo Windows (alrededor de un 93%), ya sea desde versiones de Windows 95, hasta los actuales Windows 7 incluidas las versiones de Windows Server; debido principalmente a la importación de ordenadores preinstalados con este SO. Esta característica ha hecho que los usuarios informáticos en Cuba hayan experimentado sus primeros pasos en la materia utilizando Windows, por lo que al comenzar la política de migración a tecnologías libres y de código abierto era previsible un gran rechazo por parte de los mismos, ya que se enfrenta a un S.O. completamente distinto, tanto desde el tipo de visto vista funcional como estético. Se suma el hecho de que un 95% del hardware que se encuentra en poder de la OOACE se considera obsoleto o de bajas prestaciones debido al fenómeno de la obsolescencia programada 2. Esto conlleva a que en este las últimas versiones de los S.O. convencionales no funcionen correctamente. ¿QUE ES NOVA LIGERO? En pos de maximizar los niveles de las 4S de Pierra el equipo de Nova se avocó al desarrollo de una versión que: 1.

Funcione correctamente en computadoras obsoletas.

2.

Presente una interfaz que amortigüe la resistencia al cambio en el proceso de migración.

A esta se le llamó Nova Ligero y para su desarrollo se reutilizaron algunos componentes ya existentes, ellos en su unión e integración conforman el DE Guano: •

PcmanFM: manejador de ficheros con una mínima cantidad de dependencias, poco consumidor y construido usando la librería gráfica de Gtk-2.0.



Openbox: Gestor de ventanas ligero, concebido para ser bajo consumidor sacrificando algunas funcionalidades comunes en este tipo de aplicaciones: bordes de ventanas redondeados, barra de menú, lista de aplicaciones en ejecución, entre otras.



Panel de LXDE: Panel del proyecto XFCE. Contiene gran cantidad de plugins 3 como: lanzadores de aplicaciones, listas de las ventanas, el reloj, el área de notificación, menú de aplicaciones, etc...

Sumados a estos se llegó a la necesidad de implementar los demás componentes restantes, los cuales no se pudieron reutilizar: •

Guano-session: Script4 que determina las aplicaciones que se corren al inicio de sesión y sus configuraciones iniciales.

• 2 3 4

Guano-logout: Aplicación que se encarga de gestionar la salida de la sesión. Permite además gestionar el

Se considera a la determinación, la planificación o programación del fin de la vida útil de un producto o servicio de modo que -tras un período de tiempo calculado de antemano, por el fabricante o por la empresa de servicios, durante la fase de diseño de dicho producto o servicio- éste se torne obsoleto, no funcional, inútil o inservible. En computación, un plug-in (o plug-in) es un conjunto de componentes de software que añade capacidades específicas para una aplicación de software más grande. Si es compatible, plug-ins permiten la personalización de la funcionalidad de una aplicación. Fichero de texto que contiene código perteneciente a un lenguaje interpretado el cual puede ser ejecutado.

apagado del ordenador utilizando cualquier modalidad5. •

Plugins del panel de LXDE: Conjunto de plugins para el panel de los cuales se incluyó: plugin del menú de aplicaciones, plugin de selección de idioma de teclado, plugin de selección de aplicaciones al inicio de sesión, etc...

¿QUE INSUFICIENCIAS PRESENTA EL ESCRITORIO DE NOVA LIGERO? En su primera versión se logró integrar todos los componentes antes mencionados, estabilizar su funcionamiento y se añadieron algunas funcionalidades a los componentes. No obstante se identificaron un conjunto de fallos en un proceso de revisión de calidad realizado por la empresa CaliSOFT 6. Estas no conformidades se traducirían a requerimientos funcionales y no funcionales a los cuales les brindó solución el equipo de desarrollo de Nova ligero. NO CONFORMIDAD #1: EL SISTEMA NO REALIZA EL PROCESO DE HIBERNAR O SUSPENDER Se plantea que en algunos tipos específicos de hardware el SO no posee la capacidad de hibernar o suspender cuando el usuario selecciona las opciones. Para que un ordenador con un SO GNU/Linux pueda hibernar, debe comprobar que la memoria RAM usada más la memoria SWAP7 usada, puedan ser ambas almacenadas en la memoria SWAP disponible. Este procedimiento protege la información para que cuando el usuario entre de nuevo al equipo no haya pérdida de datos. Si la suma descrita es un número superior a la capacidad total de la memoria SWAP, entonces la computadora no será capaz de hibernar o suspenderse. Mediante el uso del lenguaje de programación C, es posible acceder a los ficheros de configuración, y especificar una condición que sea capaz de calcular esta suma y restársela a la capacidad total de la SWAP. Si esta resta fuera menor que 0, entonces las opciones de hibernar o suspender no le serían visibles al usuario, indicándole que está haciendo uso de una cantidad elevada de memoria RAM, o que no tiene suficiente capacidad asignada en la memoria SWAP. Otra posible solución se hallaría teniendo al alcance de la mano uno de estos hardware para poder probar las trazas del código directamente cuando dan los problemas. Esta solución no es fácil de comprobar, puesto que el sistema operativo se concibe para un estándar, y estos casos serían la excepción, y no la regla. --- guano-session-0.9.10.orig/src/main.c +++ guano-session-0.9.10/src/main.c @@ -270,13 +270,63 @@ xfsm_shutdown_helper_hal_send ( LogoutAc #endif } +/* + * Determines if there is enought space in the swap + * to hibernate the system. Comparing the total memory + * size with the swap size. +* + * Returns: 1 if there is enought space, +* 0 if there is not. + */ + +static int isEnougthSwapToHibern() { + FILE *f = fopen("/proc/meminfo", "r"); + char buff[255]; + char var[100]; 5 6

7

Las modalidades del apagado de una ordenador son: hibernado, suspendido y apagado total. Dirección de calidad de software en la UCI encargada de que la liberación de productos informáticos sean libres de errores y con la calidad requerida. Memoria de intercambio que constituye un porción de disco duro destinado a guardar imágenes de procesos que no se mantienen en la memoria RAM.

+ long value; + long ram_total, ram_libre, swap_total, swap_libre; + + + while (fgets(buff, 255, f) != NULL) { + sscanf(buff, "%s %ld", var, &value); + if (strcmp(var, "MemTotal:") == 0) { + ram_total = value; + continue; + } + if (strcmp(var, "MemFree:") == 0) { + ram_libre = value; + continue; + } + if (strcmp(var, "SwapTotal:") == 0) { + swap_total = value; + continue; + } + if (strcmp(var, "SwapFree:") == 0) { + swap_libre = value; + continue; + } + } + + long total_used = (ram_total - ram_libre) + (swap_total - swap_libre); + if (total_used > swap_total) + return 0; + else + return 1; +} + static void check_available_actions() { /* check if we can use HAL to shutdown the computer */ use_hal = xfsm_shutdown_helper_hal_check (); if( use_hal ) /* check if hal is available */ { available_actions = LOGOUT_ACTION_SHUTDOWN | LOGOUT_ACTION_REBOOT | LOGOUT_ACTION_SUSPEND | LOGOUT_ACTION_HIBERNATE; + /* Check if the swap have enought space for SUSPEND OR HIBERNATE */ + if (isEnougthSwapToHibern() ) + available_actions = LOGOUT_ACTION_SHUTDOWN | LOGOUT_ACTION_REBOOT | LOGOUT_ACTION_SUSPEND | LOGOUT_ACTION_HIBERNATE; + else + available_actions = LOGOUT_ACTION_SHUTDOWN | LOGOUT_ACTION_REBOOT ;

Figura 1. Ejemplo de parche de código fuente.

NO CONFORMIDAD #2: VIOLACIÓN DE SEGMENTO EN APLICACIÓN PCMANFM El programa presentaba problemas a la hora de montar dispositivos de almacenamiento como CDs y dispositivos de almacenamiento por la red (ftp, sftp, samba, etc...). Debido a que el mismo no presentaba la funcionalidad de acceder a los dispositivo de red, así como de visualizarlos, se le añadieron las siguientes funcionalidades: •

Montar dispositivos de almacenamiento por la red(ftp, sftp, samba, etc...) mediante el uso de Url.



Visualizar dispositivos de almacenamiento por la red en el panel izquierdo.

Estas funcionalidades añadidas trajeron consigo el siguiente error: •

Cuando se montaba un dispositivo de red el programa lo ejecutaba sin problema alguno, lo añadía al panel izquierdo junto a los demás dispositivos para su mejor acceso por parte del usuario; además de brindar la posibilidad de desmontar mediante la acción de clic sobre un triángulo en el mismo. En los casos donde se añadía un volumen o dispositivo removible (cd, dvd, stick memory, etc...), el PCManFM se cerraba sin previo aviso después de haber inicializado varias instancias.

El PcmanFm es una aplicación que se encuentra compuesta por una librería Libfm, a partir de su versión 0.5 en adelante; donde Libfm encierra las principales funcionalidades que debe tener un gestor de archivos genérico y PcmanFm contiene el código que construye solamente la interfaz de usuario (GUI por sus siglas en inglés). Esta característica hace que el trabajo de mantener esta aplicación sea mejor, ya que si se le quieren adicionar nuevas funcionalidades basta con sólo modificar Libfm; en este caso fue la operación que se realizó. ADICIONANDO FUNCIONALIDAD DE MONTAR DISPOSITIVOS DE RED En el código fuente de Libfm, se encuentra la carpeta src/gtk, dentro se encuentran los componentes que manejan la interfaz o tienen algún componente visual en la librería. Lo archivos donde se crea el componente visual situado en la izquierda, donde se almacenan los dispositivos que han sido montados o reconocidos, se encuentran en: •

fm-places-model.h, fm-places-model.c



fm-places-view.h, fm-places-view.c



fm-gtk-utils.h, fm-gtk-utils.c

El código que se encuentra en los ficheros con el prefijo fm-places-model es el encargado de construir el componente GtkListStore8 (contenedor de los dispositivos). Aquí es donde se adicionará la mayor cantidad de código ya que es aquí donde se definen todas características de los dispositivos montados así como su localización. El código que se encuentra en los ficheros con el prefijo fm-places-view es el encargado de construir el componente GtkTreeView9 (interfaz del contenedor de dispositivos), este componente define la forma en que serán accedidos los dispositivos visualmente: cómo se mostrarán, acceder, desmontar los dispositivos al usuario. El código que se encuentra en los ficheros con el prefijo fm-gtk-utils contiene las funciones primarías utilizadas por los ficheros anteriormente mencionados: •

Montar una dirección URL.



Montar, desmontar y expulsar un Volumen (dispositivo de almacenamiento removible).



Montar y desmontar un Mount (dispositivo de red virtual).



Operaciones de copiar y mover archivos.



Manejo de la papelera de reciclaje.



Creación y manejo de ventanas de diálogos de errores o preguntas al usuario.

ADICIONANDO CÓDIGO A LIBFM Lo primero a modificar son las funciones almacenadas en fm-gtk-utils.c. En este archivo se modifica la estructura de datos que contiene los tipos de montajes que la aplicación puede manejar, esto se encuentran en la estructura MountAction. Además, se modifica la función fm_do_mount agregándole la manera de manejar cada uno de los tipos de dispositivos previamente adicionados en MountAction. --- /tmp/libfm-36dfad2/src/gtk/fm-gtk-utils.c

2011-02-08 10:39:01.000000000 -0500

8 Estructura de datos en forma de Lista que puede ser usada junto al componente de almacenamiento GtkTreeView. 9 Componente de la librería Gtk-2.0 el cual se encarga de mostrar estructuras tanto listas como árboles.

+++ libfm-0.1.15+git20110210nova1/src/gtk/fm-gtk-utils.c @@ -301,7 +301,8 @@ MOUNT_GFILE, UMOUNT_MOUNT, EJECT_MOUNT, - EJECT_VOLUME + EJECT_VOLUME, + MOUNT_MOUNT }MountAction;

2011-02-23 14:50:35.000000000 -0500

struct MountData @@ -364,6 +365,9 @@ case MOUNT_VOLUME: g_volume_mount(G_VOLUME(obj), 0, op, cancellable, on_mount_action_finished, data); break; + case MOUNT_MOUNT: + //g_volume_mount(G_VOLUME(obj), 0, op, cancellable, on_mount_action_finished, data); + break; case MOUNT_GFILE: g_file_mount_enclosing_volume(G_FILE(obj), 0, op, cancellable, on_mount_action_finished, data); break; @@ -454,6 +458,11 @@ return fm_do_mount(parent, G_OBJECT(vol), MOUNT_VOLUME, interactive); } +gboolean fm_mount_mount(GtkWindow* parent, GMount* mount, gboolean interactive) +{ + return fm_do_mount(parent, G_OBJECT(mount), MOUNT_MOUNT, interactive); +} + gboolean fm_unmount_mount(GtkWindow* parent, GMount* mount, gboolean interactive) { return fm_do_mount(parent, G_OBJECT(mount), UMOUNT_MOUNT, interactive);

Figura 2. Ejemplo de parche de código fuente.

El próximo paso es incorporar al contenedor de los dispositivos una manera de manejar los mismos. Estas modificaciones se deben realizar a los archivos fm-places-model.h y fm-places-model.c. En el archivo fm-placesmodel.h se adiciona a la estructura FmPlaceItem un objeto de tipo GMount solamente para manejar los dispositivos de almacenamiento por la red, debido a que ya existe la funcionalidad de reconocer los volúmenes o dispositivos extraíbles de almacenamiento; a esto se le adiciona al enumerativo FmPlaceType el tipo de dispositivo añadido antes en FmPlaceItem. --- /tmp/libfm-36dfad2/src/gtk/fm-places-model.h 2011-02-08 10:39:01.000000000 -0500 +++ libfm-0.1.15+git20110210nova1/src/gtk/fm-places-model.h 2011-02-23 14:50:35.000000000 -0500 @@ -62,6 +62,7 @@ FM_PLACES_ITEM_NONE, FM_PLACES_ITEM_PATH, FM_PLACES_ITEM_VOL, + FM_PLACES_ITEM_MOUNT }FmPlaceType; typedef struct _FmPlaceItem @@ -72,6 +73,7 @@ union { GVolume* vol; + GMount* mount; FmBookmarkItem* bm_item; }; }FmPlaceItem;

Figura 3. Ejemplo de parche de código fuente.

En el archivo fm-places-model.c se implementan las funciones add_mount, on_mount_removed: encargadas de adicionar y borrar un dispositivo de almacenamiento por la red respectivamente. Se modifican las funciones place_item_free encargada de eliminar las instancias de los contenedores; update_vol encargada de actualizar el contenedor en materia de información de icono nombre del dispositivo, etc...; add_vol se encarga de añadir un volumen; find_vol se encarga de localizar un volumen en un componente GtkTreeView; on_mount_added se ejecuta

cuando se monta un dispositivo de almacenamiento por la red y llama la función add_vol; fm_places_model_init se encarga de inicializar el componente GtkListStore. --- /tmp/libfm-36dfad2/src/gtk/fm-places-model.c 2011-02-08 10:39:01.000000000 -0500 +++ libfm-0.1.15+git20110210nova1/src/gtk/fm-places-model.c 2012-01-16 01:21:53.000000000 -0500 @@ -41,6 +41,9 @@ case FM_PLACES_ITEM_VOL: g_object_unref(item->vol); break; + case FM_PLACES_ITEM_MOUNT: + g_object_unref(item->mount); + break; } fm_file_info_unref(item->fi); g_slice_free(FmPlaceItem, item); @@ -92,8 +95,8 @@ { fm_file_info_unref(item->fi); item->fi = fm_file_info_ref(fi); /* remove the file from list to speed up further loading. * This won't cause problem since nobody else if using the list. */ + /* remove the file from list to speed up further loading. */ + /* This won't cause problem since nobody else if using the list. */ fm_list_delete_link(job->file_infos, l); break; } @@ -111,30 +114,47 @@ GdkPixbuf* pix; GMount* mount; FmPath* path; - name = g_volume_get_name(item->vol); - if(item->fi->icon) fm_icon_unref(item->fi->icon); - gicon = g_volume_get_icon(item->vol); - icon = fm_icon_from_gicon(gicon); - item->fi->icon = icon; - g_object_unref(gicon); - mount = g_volume_get_mount(item->vol); - if(mount) - { GFile* gf = g_mount_get_root(mount); path = fm_path_new_for_gfile(gf); g_object_unref(gf); g_object_unref(mount); item->vol_mounted = TRUE; - } - else - { path = NULL; item->vol_mounted = FALSE; - } + + if (G_IS_VOLUME(item->vol) && (item->vol != NULL)){ + name = g_volume_get_name(item->vol); + if(item->fi->icon) + fm_icon_unref(item->fi->icon); + gicon = g_volume_get_icon(item->vol); + icon = fm_icon_from_gicon(gicon); + item->fi->icon = icon; + g_object_unref(gicon); + + mount = g_volume_get_mount(item->vol); + if(mount) + { + GFile* gf = g_mount_get_root(mount); + path = fm_path_new_for_gfile(gf); + g_object_unref(gf); + g_object_unref(mount); + item->vol_mounted = TRUE; + } + else + { + path = NULL; + item->vol_mounted = FALSE;

+ + + + + + + + + + + + + + + + + +

} } if (G_IS_MOUNT(item->mount) && (item->mount != NULL)){ name = g_mount_get_name(item->mount); if(item->fi->icon) fm_icon_unref(item->fi->icon); gicon = g_mount_get_icon(item->mount); icon = fm_icon_from_gicon(gicon); item->fi->icon = icon; g_object_unref(gicon); GFile* gf = g_mount_get_root(item->mount); path = fm_path_new_for_gfile(gf); g_object_unref(gf); item->vol_mounted = TRUE;

} if(!fm_path_equal(item->fi->path, path)) { fm_file_info_set_path(item->fi, path); @@ -164,18 +184,40 @@ GtkTreeIter it; FmPlaceItem* item; item = g_slice_new0(FmPlaceItem); - item->fi = fm_file_info_new(); - item->type = FM_PLACES_ITEM_VOL; - item->vol = (GVolume*)g_object_ref(vol); - gtk_list_store_insert_before(GTK_LIST_STORE(model), &it, &model->sep_it); - gtk_list_store_set(GTK_LIST_STORE(model), &it, FM_PLACES_MODEL_COL_INFO, item, -1); - update_vol(model, item, &it, job); + item->fi = fm_file_info_new(); + item->type = FM_PLACES_ITEM_VOL; + item->mount = NULL; + item->vol = (GVolume*)g_object_ref(vol); + gtk_list_store_insert_before(GTK_LIST_STORE(model), &it, &model->sep_it); + gtk_list_store_set(GTK_LIST_STORE(model), &it, FM_PLACES_MODEL_COL_INFO, item, -1); + update_vol(model, item, &it, job); +} + +static void add_mount(FmPlacesModel* model, GMount* mount, FmFileInfoJob* job) +{ + GtkTreeIter it; + FmPlaceItem* item; + item = g_slice_new0(FmPlaceItem); + item->fi = fm_file_info_new(); + item->type = FM_PLACES_ITEM_MOUNT; + item->vol = NULL; + item->mount = (GMount*)g_object_ref(mount); + gtk_list_store_insert_before(GTK_LIST_STORE(model), &it, &model->sep_it); + gtk_list_store_set(GTK_LIST_STORE(model), &it, FM_PLACES_MODEL_COL_INFO, item, -1); + update_vol(model, item, &it, job); } -static FmPlaceItem* find_vol(FmPlacesModel* model, GVolume* vol, GtkTreeIter* _it) +static FmPlaceItem* find_vol(FmPlacesModel* model, GObject* vol, GtkTreeIter* _it) { GtkTreeIter it; FmPlaceItem* item; + GVolume* volume = NULL; + GMount* mount = NULL; + if (G_IS_VOLUME(vol) && vol != NULL) + volume = (GVolume *)g_object_ref(vol); + else if (G_IS_MOUNT(vol) && vol != NULL) + mount = (GMount *)g_object_ref(vol); + /* FIXME: don't need to find from the first iter */ if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &it)) { @@ -183,14 +225,27 @@ { FmPlaceItem* item; gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1); if(item && item->type == FM_PLACES_ITEM_VOL && item->vol == vol) { *_it = it; return item;

+ + + + + + + + + + + + + + + +

if (volume != NULL){ if(item && item->type == FM_PLACES_ITEM_VOL && \ (item->vol != NULL && G_IS_VOLUME(item->vol)) && item->vol == volume) { *_it = it; return item; } } if (mount != NULL){ if((item && item->type == FM_PLACES_ITEM_MOUNT) && \ (item->mount != NULL && G_IS_MOUNT(item->mount)) && item->mount == mount) { *_it = it; return item; } } }while(it.user_data != model->sep_it.user_data && gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &it));

} + g_object_unref(volume); + g_object_unref(mount); return NULL; } @@ -207,7 +262,7 @@ FmPlacesModel* model = FM_PLACES_MODEL(user_data); FmPlaceItem* item; GtkTreeIter it; - item = find_vol(model, vol, &it); + item = find_vol(model, (GObject*) vol, &it); /* g_debug("remove vol: %p, uuid: %s, udi: %s", vol, g_volume_get_identifier(vol, "uuid"), g_volume_get_identifier(vol, "hal-udi")); */ if(item) { @@ -217,13 +272,28 @@ } } +void on_mount_removed(GVolumeMonitor* vm, GMount* mount, gpointer user_data) +{ + FmPlacesModel* model = FM_PLACES_MODEL(user_data); + FmPlaceItem* item; + GtkTreeIter it; + item = find_vol(model, (GObject*) mount, &it); + g_debug("remove mount: %s, root: %s", g_mount_get_name(mount), g_mount_get_uuid(mount)); + if(item) + { + gtk_list_store_remove(GTK_LIST_STORE(model), &it); + place_item_free(item); + update_sep_tp(model); + } +} + void on_vol_changed(GVolumeMonitor* vm, GVolume* vol, gpointer user_data) { FmPlacesModel* model = FM_PLACES_MODEL(user_data); FmPlaceItem* item; GtkTreeIter it; g_debug("vol-changed"); - item = find_vol(model, vol, &it); + item = find_vol(model,(GObject*) vol, &it); if(item) update_vol(model, item, &it, NULL); } @@ -231,15 +301,15 @@ void on_mount_added(GVolumeMonitor* vm, GMount* mount, gpointer user_data) { FmPlacesModel* model = FM_PLACES_MODEL(user_data); + FmPlaceItem *item; + GtkTreeIter it; + GtkTreePath* tp; GVolume* vol = g_mount_get_volume(mount); if(vol) { FmPlaceItem *item; GtkTreeIter it; item = find_vol(model, vol, &it); + item = find_vol(model,(GObject*) vol, &it); if(item && item->type == FM_PLACES_ITEM_VOL && !item->fi->path)

{ -

GtkTreePath* tp; GFile* gf = g_mount_get_root(mount); FmPath* path = fm_path_new_for_gfile(gf); g_debug("mount path: %s", path->name); @@ -256,6 +326,33 @@ } g_object_unref(vol); } + else + { + /* If not volume then it's a mount added */ + /* Find it first if exists */ + item = find_vol(model,(GObject*) mount, &it); + if (!item) + { + /* Adding mount */ + add_mount(GTK_TREE_MODEL(model), (GMount *)mount, NULL); + } + else if(item && item->type == FM_PLACES_ITEM_MOUNT && !item->fi->path) + { + GFile* gf = g_mount_get_root(mount); + FmPath* path = fm_path_new_for_gfile(gf); + g_debug("mount path: %s", path->name); + g_object_unref(gf); + fm_file_info_set_path(item->fi, path); + if(path) + fm_path_unref(path); + item->vol_mounted = TRUE; + + /* inform the view to update mount indicator */ + tp = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &it); + gtk_tree_model_row_changed(GTK_TREE_MODEL(model), tp, &it); + gtk_tree_path_free(tp); + } + } } static void add_bookmarks(FmPlacesModel* model, FmFileInfoJob* job) @@ -462,7 +559,9 @@ GtkTreeIter it; GtkTreePath* tp; FmPlaceItem* item; - GList *vols, *l; + GList *vols = NULL, *l = NULL, *mounts = NULL, *all = NULL; + GVolume *volume; + GMount * mount; GIcon* gicon; FmIcon* icon; GFile* gf; @@ -531,19 +630,58 @@ g_signal_connect(self->vol_mon, "volume-removed", G_CALLBACK(on_vol_removed), self); g_signal_connect(self->vol_mon, "volume-changed", G_CALLBACK(on_vol_changed), self); g_signal_connect(self->vol_mon, "mount-added", G_CALLBACK(on_mount_added), self); + g_signal_connect(self->vol_mon, "mount-removed", G_CALLBACK(on_mount_removed), self); /* separator */ gtk_list_store_append(model, &self->sep_it); - /* add volumes to side-pane */ + /* Colects volumes */ vols = g_volume_monitor_get_volumes(self->vol_mon); for(l=vols;l;l=l->next) { GVolume* vol = G_VOLUME(l->data); add_vol(self, vol, job); + all = g_list_append(all, vol); + /* add_vol(self, vol, job); */ g_object_unref(vol); } g_list_free(vols); + + /* Supports smb, sftp, ftp... */ + /* Colects mounts */ + mounts = g_volume_monitor_get_mounts (self->vol_mon); + for (l=mounts;l;l=l->next) + { + mount = G_MOUNT(l->data);

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

if (mount) { volume = g_mount_get_volume (mount); if (volume) { g_object_unref (volume); continue; } all = g_list_append(all, mount); g_object_unref (mount); } } g_list_free(mounts); /* Adds all drives to side panel */ for (l=all;l;l=l->next) { if (G_IS_VOLUME(l->data)) { GVolume* vol1 = G_VOLUME(l->data); add_vol(self, vol1, job); g_object_unref (vol1); } if (G_IS_MOUNT(l->data)) { GMount* mount1 = G_MOUNT(l->data); add_mount(self, mount1, job); g_object_unref (mount1); } } /* get the path of separator */ self->sep_tp = gtk_tree_model_get_path(GTK_TREE_MODEL(self), &self->sep_it);

Figura 4. Ejemplo de parche de código fuente.

El próximo paso es modificar e incorporar las funcionalidades necesarias al componente visual que se encarga de mostrar los dispositivos. Estas modificaciones se deben realizar a los archivos fm-places-view.h y fm-places-view.c. Se modifica la función activate_row encargada de gestionar las acciones que se pueden realizar con un dispositivo; se modifica on_button_release que se encarga de localizar qué fue activado en cuando se realiza un clic sobre el componente, debido a que el mismo componente contiene la funcionalidad de acceder y desmontar en el evento on_click; se modifica place_item_get_menu encargada de crear el menú de funcionalidades a realizar sobre los dispositivos: ya sea montarlos, desmontarlos o expulsar; se modifica además on_umount encargada de realizar la función de montaje cuando se selecciona la misma en el menú de acciones a realizar. if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &it, tree_path)) { FmPlaceItem* item; FmPath* path; + FmPath* path = NULL; + GFile* gf; + GMount* mnt = NULL; gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1); if(!item) return; @@ -447,38 +449,50 @@ case FM_PLACES_ITEM_PATH: path = fm_path_ref(item->fi->path); break; + case FM_PLACES_ITEM_MOUNT: + { + if ((item->mount != NULL) && G_IS_MOUNT(item->mount)){ + mnt = (GMount*)g_object_ref(item->mount); + } + } + break; case FM_PLACES_ITEM_VOL: { GFile* gf; GMount* mnt = g_volume_get_mount(item->vol); + if ((item->vol != NULL) && G_IS_VOLUME(item->vol)){

+ +

mnt = g_volume_get_mount(item->vol); } if(!mnt) {

+ GtkWindow* parent = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); if(!fm_mount_volume(parent, item->vol, TRUE)) return; mnt = g_volume_get_mount(item->vol); if(!mnt) { g_debug("GMount is invalid after successful g_volume_mount().\nThis is quite possibly a gvfs bug.\nSee https://bugzilla.gnome.org/show_bug.cgi?id=552168"); return; + if ((item->vol != NULL) && G_IS_VOLUME(item->vol)){ + if(!fm_mount_volume(parent, item->vol, TRUE)) + return; + mnt = g_volume_get_mount(item->vol); + if(!mnt) + { + g_debug("GMount is invalid after successful g_volume_mount().\nThis is quite possibly a gvfs bug.\nSee https://bugzilla.gnome.org/show_bug.cgi?id=552168"); + return; + } } } gf = g_mount_get_root(mnt); g_object_unref(mnt); if(gf) { path = fm_path_new_for_gfile(gf); g_object_unref(gf); } else path = NULL; break; } + } + } + break; default: return; } if(path) + if (!path){ + gf = g_mount_get_root(mnt); + g_object_unref(mnt); + if(gf) + { + path = fm_path_new_for_gfile(gf); + g_object_unref(gf); + } + else + path = NULL; + } + if (path) { g_signal_emit(view, signals[CHDIR], 0, button, path); fm_path_unref(path); @@ -526,18 +540,27 @@ if(item && item->vol_mounted) { GtkWidget* toplevel = gtk_widget_get_toplevel(view); /* eject the volume */ if(g_volume_can_eject(item->vol)) fm_eject_volume(toplevel, item->vol, TRUE); else /* not ejectable, do unmount */ { GMount* mnt = g_volume_get_mount(item->vol); if(mnt) { fm_unmount_mount(toplevel, mnt, TRUE); g_object_unref(mnt); } } + + if ((item->vol != NULL) && G_IS_VOLUME(item->vol)){

+ + + + + + + + + + + +

/* eject the volume */ if(g_volume_can_eject(item->vol)) fm_eject_volume(toplevel, item->vol, TRUE); else /* not ejectable, do unmount */ { GMount* mnt = g_volume_get_mount(item->vol); if(mnt) { fm_unmount_mount(toplevel, mnt, TRUE); g_object_unref(mnt); } } } else if ((item->mount != NULL) && G_IS_MOUNT(item->mount)){ GMount* mnt = (GVolume*)g_object_ref(item->vol); fm_unmount_mount(toplevel, mnt, TRUE); }

+ gtk_tree_path_free(tp); gtk_tree_path_free(view->clicked_row); @@ -587,8 +610,12 @@ GMount* mnt; gtk_action_group_add_actions(act_grp, vol_menu_actions, G_N_ELEMENTS(vol_menu_actions), item); gtk_ui_manager_add_ui_from_string(ui, vol_menu_xml, -1, NULL); mnt = g_volume_get_mount(item->vol); + + if ((item->vol != NULL) && G_IS_VOLUME(item->vol)) + mnt = g_volume_get_mount(item->vol); + else if ((item->vol != NULL) && G_IS_VOLUME(item->mount)) + mnt = item->mount; + if(mnt) /* mounted */ { g_object_unref(mnt); @@ -607,6 +634,25 @@ act = gtk_action_group_get_action(act_grp, "Eject"); gtk_action_set_visible(act, FALSE); } + else if(item->type == FM_PLACES_ITEM_MOUNT) + { + GtkAction* act; + GMount* mnt; + gtk_action_group_add_actions(act_grp, vol_menu_actions, G_N_ELEMENTS(vol_menu_actions), item); + gtk_ui_manager_add_ui_from_string(ui, vol_menu_xml, -1, NULL); + + if ((item->mount != NULL) && G_IS_MOUNT(item->mount)) + mnt = (GMount*)g_object_ref(item->mount); + + if(mnt) /* mounted */ + { + g_object_unref(mnt); + act = gtk_action_group_get_action(act_grp, "Mount"); + gtk_action_set_visible(act, FALSE); + act = gtk_action_group_get_action(act_grp, "Eject"); + gtk_action_set_visible(act, FALSE); + } + } else goto _out; gtk_ui_manager_insert_action_group(ui, act_grp, 0); @@ -681,8 +727,13 @@ void on_umount(GtkAction* act, gpointer user_data) { + GMount* mnt; FmPlaceItem* item = (FmPlaceItem*)user_data; - GMount* mnt = g_volume_get_mount(item->vol); + if ((item != NULL) && (G_IS_VOLUME(item->vol)) && item->type == FM_PLACES_ITEM_VOL) + mnt = g_volume_get_mount(item->vol); + else if ((item != NULL) && (G_IS_MOUNT(item->mount)) && item->type == FM_PLACES_ITEM_MOUNT) + mnt = (GMount*)g_object_ref(item->mount); + if(mnt) { fm_unmount_mount(NULL, mnt, TRUE);

Figura 5. Ejemplo de parche de código fuente.

NO CONFORMIDAD #3: PÉRDIDA DE LA CONFIGURACIÓN DE LA RESOLUCIÓN DE PANTALLA DE CADA USUARIO. Al apagar el sistema, este no almacena la configuración de pantalla que se le definió manualmente, siempre se inicia la sesión con la resolución 800x600 para cada usuario. Existe una aplicación que gestiona las resoluciones de pantalla del sistema, escrita en lenguaje BASH pero no resuelve el problema. Se le agrega a la misma una línea de código que agregue el comando xrandr con la resolución seleccionada a la lista de las aplicaciones de inicio. Esta solución resolvería el problema para todas las resoluciones posteriores, en caso de usarse una variable para guardar los valores seleccionados. La variante más adecuada es crear el soporte a la aplicación ya instalada para que cree en los archivos de configuración del DE que se encuentran para cada usuario en ~/.config un segmento de configuración que almacene la resolución de pantalla seleccionada. En el código fuente de la aplicación guano-session, encargada de instalar la aplicación que maneja la resolución del escritorio se modifica el archivo data/utils/gutil-box. Archivo que contiene el código fuente de una aplicación desarrollada en BASH; la cual según el parámetro con que se ejecute se inicializa una interfaz distinta. Esto es posible utilizando la tecnología gtkdialog10 muy utilizada por el proyecto Zlitaz11. --- guano-session-0.9.11/data/utils/gutil-box 2010-05-31 12:53:00.000000000 -0400 +++ guano-session-0.9.12/data/utils/gutil-box 2011-11-30 01:33:39.000000000 -0500 @@ -126,7 +126,7 @@ xrandr -s $RANDR + xrandr -s $RANDR && $BIN set_randr @@ -140,6 +140,16 @@ done ; } +set_randr() +{ + if [ -z "$(grep ^xrandr $AUTOSTART_SCRIPT)" ]; + then + echo xrandr -s $RANDR >> $AUTOSTART_SCRIPT + else + sed -i s/^xrandr.*/xrandr\ -s\ $RANDR/g $AUTOSTART_SCRIPT + fi +} + case $1 in randr) gtkdialog --center --program=RANDR_WIN ;

Figura 7. Ejemplo de parche de código fuente.

NO CONFORMIDAD #4: CARENCIA DE APLICACIÓN PARA CONFIGURAR IDIOMA DE TECLADO El panel del proyecto LXDE, presenta un conjunto de plugins para brindarle otras funcionales al mismo, una de ellas es un plugin para el manejo de los idiomas y los tipos de teclados existentes. Esta aplicación no funciona adecuadamente (obsoleta, utiliza funciones ya deprecadas de xkb 12), no logra configurar el teclado según los idiomas existentes al no encontrarlos en el SO. 10 Es una pequeña utilidad para la creación de interfaz gráfica de usuario fácil y rápido. Se puede utilizar para crear cuadros de diálogo para casi todos los programas interpretados y compilados. 11 Distribución minimalista de GNU/Linux francesa que se caracteriza por lograr un SO muy pequeño de tan solo 30Mb. 12 X keyboard extension o XKB por sus siglas en inglés habilita un control del teclado más allá de lo que realiza el nucle del sistema de ventanas X.

Por lo que se decide implementar una nueva aplicación para la configuración del teclado: lxkb-config, basándose en otras aplicaciones existentes y cumpliendo con el estándar dictado por la Freedesktop.org13. CONCLUSIONES Se ha podido observar en el transcurso del trabajo, las diferentes tecnologías que componen Nova ligero 2011, así como el proceso de corrección de errores de aplicaciones críticas en el SO como lo conforma en DE. Información considerada de material instructivo para que la comunidad de Nova se integre al desarrollo de aplicaciones para el mismo; debido a que Nova Ligero se ha convertido en el producto de mayor difusión en nuestro País, producto a sus características de ligereza y su interfaz simple. Con el estudio del presente documento la comunidad de desarrolladores tiene una potente herramienta que ayudará a comprender tanto la concepción de escritorio ligero cubano, como las interioridades de su funcionamiento. REFERENCIAS

1. The top 20 strongholds for desktop Linux. 2011. http://royal.pingdom.com/2011/05/12/the-top-20-strongholdsfor-desktop-linux/

2. Diez distribuciones Linux ligeras para uso en netbooks, equipos poco potentes y obsoletos. 2011. http://www.sahw.com/wp/archivos/2011/01/17/diez-distribuciones-linux-ligeras-para-uso-en-netbooksequipos-poco-potentes-yo-obsoletos-revision-enero-2011/

3. Sistemas operativos ligeros para ordenadores viejos. 2011. http://www.omicrono.com/2011/04/sistemasoperativos-ligeros-para-ordenadores-viejos/

4. Servidor X, 2009. http://gersoft.wordpress.com/2009/02/18/servidor-x/ 5. Ecumenix. 2011. http://www.nova.cu/?q=node/162 6. Capoeira. 2011. http://www.nova.cu/?q=node/161 7. 2011. http://freedesktop.org/ 8. 2011. http://www.alsa-project.org 9. Larabel ,Michael. Power & Memory Usage Of GNOME, KDE, LXDE & Xfce. 2010. http://www.phoronix.com/scan.php?page=article&item=linux_desktop_vitals&num=1

10. 2011. http://linux.pte.hu/~pipas/gtkdialog/ 11. Pierra, Allan. Conceptualización y reestructuración estratégica de la distribución cubana de GNU/Linux “Nova”. Universidad de las Ciencias Informáticas. La Habana, 2011.

13 Proyecto que trabaja por la interoperatibilidad y la compartición de la tecnología base de los DE para X Windows System (X11), tanto en GNU/Linux como en otros SO de tipo Unix.

Lihat lebih banyak...

Comentarios

Copyright © 2017 DATOSPDF Inc.