Port applications manager to win32 0.3
authorJ. Ali Harlow <ali@juiblex.co.uk>
Fri, 30 Apr 2010 19:37:08 +0000 (20:37 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Fri, 30 Apr 2010 19:37:08 +0000 (20:37 +0100)
19 files changed:
.gitignore
app-manager/Makefile.am
app-manager/app-manager.c
app-manager/app-manager.h
app-manager/app-manager.ui
app-manager/applications.c
app-manager/localmedia.c
app-manager/packagelist.c
configure.ac
plover-gtk/Makefile.am
plover-gtk/package.c
plover-gtk/packagefilestore.c
plover-gtk/packageset.c
plover-gtk/packageset.h
plover-gtk/packagestore.c
setup/Makefile.am
setup/resources.rc.in
update/Makefile.am
update/resources.rc.in

index 5f74325..ecfd2e0 100644 (file)
@@ -14,7 +14,9 @@ stamp-h1
 *.lo
 *.la
 plover/plover.pc
+plover-gtk/plover-gtk.pc
 setup/resources.rc
 setup/setup
 update/resources.rc
 update/update
+app-manager/resources.rc
index d577425..b73f511 100644 (file)
@@ -13,19 +13,41 @@ desktopdir=$(datadir)/applications
 desktop_DATA=app-manager.desktop
 scaleabledir=$(datadir)/icons/hicolor/scalable/apps
 scaleable_DATA=plover-applications.svg
+smallicondir=$(datadir)/icons/hicolor/24x24/apps
+smallicon_DATA=24x24/plover-applications.png
+bigicondir=$(datadir)/icons/hicolor/48x48/apps
+bigicon_DATA=48x48/plover-applications.png
 
 .rc.$(OBJEXT):
        $(WINDRES) $< $@
 
-resources.$(OBJEXT):   plover-applications.ico
+resources.$(OBJEXT):   app-manager.ico
 
 plover-applications%.pnm:      plover-applications.svg
        rsvg -w $* -h $* -f png $< temp.png
        pngtopnm temp.png | pnmquant 256 > $@
        $(RM) temp.png
 
-app-manager.ico:       plover-applications16.pnm \
-               plover-applications22.pnm plover-applications32.pnm
-       ppmtowinicon -output=$@ $^
+plover-applications%.pgm:      plover-applications.svg
+       rsvg -w $* -h $* -f png $< temp.png
+       pngtopnm -alpha temp.png > $@
+       $(RM) temp.png
+
+24x24/plover-applications.png: plover-applications.svg
+       mkdir -p 24x24
+       rsvg -w 24 -h 24 -f png $< $@
+
+48x48/plover-applications.png: plover-applications.svg
+       mkdir -p 48x48
+       rsvg -w 48 -h 48 -f png $< $@
+
+app-manager.ico:       plover-applications16.pnm plover-applications16.pgm \
+               plover-applications22.pnm plover-applications22.pgm \
+               plover-applications32.pnm plover-applications32.pgm \
+               plover-applications46.pnm plover-applications46.pgm
+       ppmtowinicon -andpgms -output=$@ $^
+
+clean-local:
+       -rm -rf 24x24 48x48
 
 EXTRA_DIST=app-manager.desktop app-manager.ui plover-applications.svg
index e897c89..7d42ad6 100644 (file)
 
 GtkBuilder *ui;
 GtkTreeModel *installed,*applications,*location,*local_media;
+char *prefix=NULL;
+struct razor_relocations *relocations=NULL;
+
+void show_busy_cursor(gboolean busy)
+{
+    GList *list,*link,*remaining;
+    GdkDisplay *display;
+    GdkCursor *cursor;
+    GtkWidget *w;
+    list=gtk_window_list_toplevels();
+    while(list)
+    {
+       w=GTK_WIDGET(list->data);
+       if (!w->window)
+       {
+           link=list;
+           list=g_slist_remove_link(list,link);
+           g_slist_free_1(link);
+       }
+       else
+       {
+           display=gtk_widget_get_display(w);
+           cursor=busy?gdk_cursor_new_for_display(display,GDK_WATCH):NULL;
+           remaining=NULL;
+           for(link=list;link;link=link->next)
+           {
+               w=GTK_WIDGET(link->data);
+               if (w->window)
+               {
+                   if (gtk_widget_get_display(w)==display)
+                       gdk_window_set_cursor(w->window,cursor);
+                   else
+                       remaining=g_slist_prepend(remaining,w);
+               }
+           }
+           gdk_display_flush(display);
+           if (cursor)
+               gdk_cursor_unref(cursor);
+           g_list_free(list);
+           list=remaining;
+       }
+    }
+}
+
+/*
+ * In Gtk+ 2.16.6, the default handler generates g_warnings on error.
+ * It should display an error to the user. Do it ourselves.
+ */
+
+static void show_uri(GtkLinkButton *button,const gchar *uri,gpointer data)
+{
+    GdkScreen *screen;
+    GtkWidget *dialog;
+    GError *error=NULL;
+    if (gtk_widget_has_screen(GTK_WIDGET(button)))
+       screen=gtk_widget_get_screen(GTK_WIDGET(button));
+    else
+       screen=NULL;
+    gtk_show_uri(screen,uri,GDK_CURRENT_TIME,&error);
+    if (error)
+    {
+       dialog=gtk_message_dialog_new(
+         GTK_WINDOW(gtk_builder_get_object(ui,"MainWindow")),
+         GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
+         "Unable to show '%s'",uri);
+       gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+         error->message);
+       g_error_free(error);
+       gtk_dialog_run(GTK_DIALOG(dialog));
+       gtk_widget_destroy(dialog);
+    }
+}
+
+/* Checks whether a loader for SVG files has been registered
+ * with GdkPixbuf.
+ */
+static gboolean pixbuf_supports_svg(void)
+{
+    GSList *formats;
+    GSList *tmp_list;
+    static gint found_svg=-1;
+    gchar **mime_types,**mime_type;
+    if (found_svg!=-1)
+       return found_svg;
+    formats=gdk_pixbuf_get_formats();
+    found_svg=FALSE;
+    for (tmp_list=formats;tmp_list && !found_svg;tmp_list=tmp_list->next)
+    {
+       mime_types=gdk_pixbuf_format_get_mime_types(tmp_list->data);
+       for (mime_type=mime_types;*mime_type && !found_svg;mime_type++)
+           if (!strcmp(*mime_type,"image/svg"))
+               found_svg=TRUE;
+       g_strfreev(mime_types);
+    }
+    g_slist_free(formats);
+    return found_svg;
+}
+
+static void install_icon_at_size(const char *icon_name,GtkIconSet *icon_set,
+  GtkIconSize size,const char *filename)
+{
+    int w,h;
+    GdkPixbuf *pixbuf;
+    GtkIconSource *source;
+    if (gtk_icon_size_lookup(size,&w,&h))
+    {
+       pixbuf=gdk_pixbuf_new_from_file_at_size(filename,w,h,NULL);
+       if (pixbuf)
+       {
+           source=gtk_icon_source_new();
+           gtk_icon_source_set_size_wildcarded(source,FALSE);
+           gtk_icon_source_set_size(source,size);
+           gtk_icon_source_set_pixbuf(source,pixbuf);
+           gtk_icon_set_add_source(icon_set,source);
+           gtk_icon_source_free(source);
+           g_object_unref(pixbuf);
+       }
+    }
+}
+
+static void install_icons(void)
+{
+    int w,h;
+    gchar *s;
+    GdkPixbuf *pixbuf;
+    GtkIconSource *source;
+    GtkIconSet *icon_set;
+    GtkIconFactory *factory;
+    factory=gtk_icon_factory_new();
+    icon_set=gtk_icon_set_new();
+    if (pixbuf_supports_svg())
+    {
+       source=gtk_icon_source_new();
+       s=g_build_filename(prefix?prefix:"/usr",
+         "share/icons/hicolor/scalable/apps/plover-applications.svg",NULL);
+       gtk_icon_source_set_filename(source,s);
+       g_free(s);
+       gtk_icon_set_add_source(icon_set,source);
+       gtk_icon_source_free(source);
+    }
+    else
+    {
+       s=g_build_filename(prefix?prefix:"/usr",
+         "share/icons/hicolor/24x24/apps/plover-applications.png",NULL);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_MENU,s);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_BUTTON,s);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_SMALL_TOOLBAR,s);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_LARGE_TOOLBAR,s);
+       g_free(s);
+       s=g_build_filename(prefix?prefix:"/usr",
+         "share/icons/hicolor/48x48/apps/plover-applications.png",NULL);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_DND,s);
+       install_icon_at_size(LOGO_NAME,icon_set,GTK_ICON_SIZE_DIALOG,s);
+       g_free(s);
+    }
+    gtk_icon_factory_add(factory,LOGO_NAME,icon_set);
+    gtk_icon_set_unref(icon_set);
+    icon_set=gtk_icon_factory_lookup(factory,LOGO_NAME);
+    gtk_icon_factory_add_default(factory);
+    g_object_unref(factory);
+    icon_set=gtk_icon_factory_lookup_default(LOGO_NAME);
+    gtk_window_set_default_icon_name(LOGO_NAME);
+}
 
 int main(int argc,char **argv)
 {
@@ -46,13 +209,20 @@ int main(int argc,char **argv)
        g_printerr("%s",err->message);
        exit(0);
     }
-    gtk_window_set_default_icon_name(LOGO_NAME);
+#ifdef WIN32
+    prefix=g_win32_get_package_installation_directory_of_module(NULL);
+#endif
+    install_icons();
     ui=gtk_builder_new();
     if (!g_file_get_contents("app-manager.ui",&contents,&len,&err) &&
       g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT))
     {
-       g_clear_error(&err);
+#ifdef WIN32
+       s=g_build_filename(prefix,"share","plover","app-manager.ui",NULL);
+#else
        s=g_build_filename(PLOVER_DATADIR,"app-manager.ui",NULL);
+#endif
+       g_clear_error(&err);
        (void)g_file_get_contents(s,&contents,&len,&err);
        g_free(s);
     }
@@ -66,15 +236,31 @@ int main(int argc,char **argv)
        g_error("%s",err->message);
        exit(0);
     }
+    if (prefix)
+    {
+       relocations=razor_relocations_create();
+       razor_relocations_add(relocations,"/usr",prefix);
+    }
     gtk_builder_connect_signals(ui,NULL);
+    gtk_link_button_set_uri_hook(show_uri,NULL,NULL);
     installed=GTK_TREE_MODEL(plover_package_store_new());
     set=plover_package_set_new_from_installed("",NULL);
     if (set)
+    {
        plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set);
+       if (plover_package_set_get_no_details(set))
+       {
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles"));
+           gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),TRUE);
+       }
+    }
     applications=plover_applications_model_new(installed);
     set_package_model(applications);
     gtk_main();
     g_object_unref(ui);
+    if (relocations)
+       razor_relocations_destroy(relocations);
+    g_free(prefix);
     exit(0);
 }
 
@@ -102,7 +288,11 @@ G_MODULE_EXPORT void
     if (gtk_toggle_tool_button_get_active(button))
     {
        if (!local_media)
+       {
+           show_busy_cursor(TRUE);
            local_media=plover_local_media_store_new();
+           show_busy_cursor(FALSE);
+       }
        set_package_model(local_media);
     }
 }
@@ -118,6 +308,9 @@ G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
 {
     GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
     GtkWidget *dialog;
+    GFile *file,*parent;
+    GFileInfo *fi;
+    GMount *mount;
     gchar *path,*name;
     PloverPackageSet *set;
     GSList *sets;
@@ -130,8 +323,9 @@ G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
 #endif
     if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT)
     {
+       show_busy_cursor(TRUE);
        path=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-       set=plover_package_set_new_from_repository(path,&err);
+       set=plover_package_set_new_from_repository(path,relocations,&err);
        if (set)
        {
            if (!location)
@@ -143,7 +337,34 @@ G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
            plover_package_store_add_set(PLOVER_PACKAGE_STORE(location),set);
            g_object_unref(set);
            w=GTK_WIDGET(gtk_builder_get_object(ui,"LocationButton"));
-           name=g_filename_display_basename(path);
+           file=g_file_new_for_path(path);
+           parent=g_file_get_parent(file);
+           if (parent)
+           {
+               g_object_unref(parent);
+               mount=NULL;
+           }
+           else
+               mount=g_file_find_enclosing_mount(file,NULL,NULL);
+           if (mount)
+           {
+               name=g_mount_get_name(mount);
+               g_object_unref(mount);
+           }
+           else
+           {
+               fi=g_file_query_info(file,
+                 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,NULL,NULL);
+               if (fi)
+               {
+                   name=g_strdup(g_file_info_get_display_name(fi));
+                   g_object_unref(fi);
+               }
+               else
+                   name=g_filename_display_basename(path);
+               g_object_unref(file);
+           }
            gtk_tool_button_set_label(GTK_TOOL_BUTTON(w),name);
            g_free(name);
            gtk_widget_show(w);
@@ -161,15 +382,18 @@ G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
            g_error_free(err);
        }
        g_free(path);
+       show_busy_cursor(FALSE);
     }
     gtk_widget_destroy(dialog);
 }
 
 G_MODULE_EXPORT void on_scan_local_media(GtkWidget *widget)
 {
+    show_busy_cursor(TRUE);
     if (!local_media)
        local_media=plover_local_media_store_new();
     plover_local_media_store_scan(PLOVER_LOCAL_MEDIA_STORE(local_media));
+    show_busy_cursor(FALSE);
 }
 
 G_MODULE_EXPORT void on_help_about(GtkWidget *widget)
index dca76f9..63f077e 100644 (file)
@@ -1,7 +1,9 @@
+#include <razor.h>
 #include <gtk/gtk.h>
 #include <plover-gtk/package.h>
 
 extern GtkBuilder *ui;
+extern struct razor_relocations *relocations;
 GtkTreeModel *plover_applications_model_new(GtkTreeModel *installed);
 void set_package_model(GtkTreeModel *model);
 PloverPackage *get_active_package(void);
index c6b7f6b..be45944 100644 (file)
@@ -87,7 +87,7 @@
                     <property name="visible">True</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <object class="GtkRadioMenuItem" id="menuitem2">
+                      <object class="GtkRadioMenuItem" id="ViewFiles">
                         <property name="visible">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                         <property name="tooltip_text" translatable="yes">Show a list of files owned by the selected package</property>
                         <property name="use_underline">True</property>
                         <property name="active">True</property>
                         <property name="draw_as_radio">True</property>
-                        <property name="group">menuitem2</property>
+                        <property name="group">ViewFiles</property>
                         <signal name="toggled" handler="on_view_details_toggled"/>
                       </object>
                     </child>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="orientation">vertical</property>
-            <property name="position">200</property>
+            <property name="position">215</property>
             <property name="position_set">True</property>
             <child>
               <object class="GtkAlignment" id="alignment1">
                                     <property name="tooltip_text" translatable="yes">Show installed applications</property>
                                     <property name="label" translatable="yes">_Applications</property>
                                     <property name="use_underline">True</property>
-                                    <property name="icon_name">plover-applications</property>
+                                    <property name="stock_id">plover-applications</property>
                                     <property name="active">True</property>
                                     <signal name="toggled" handler="on_applications_toggled"/>
                                   </object>
index 6b72505..ceabefc 100644 (file)
 #include "config.h"
 #include <stdlib.h>
 #include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <plover-gtk/packagestore.h>
 #include "app-manager.h"
 
+#ifdef WIN32
+static BOOL CALLBACK plover_applications_visible_callback(HMODULE module,
+  const char *type,char *name,long *param)
+{
+    gboolean *visible=(void *)param;
+    if (!IS_INTRESOURCE(name) && !strcmp(name,"MAINICON"))
+       *visible=TRUE;
+    return !*visible;
+}
+#endif
+
 static gboolean plover_applications_visible_func(GtkTreeModel *model,
   GtkTreeIter *iter,gpointer data)
 {
     /* Visible if row is non-empty and package contains a .desktop file
-     * in /usr/share/applications
+     * in /usr/share/applications (UNIX) or package contains a .exe file
+     * which has a default application icon (MS-Windows).
      */
     PloverPackage *package;
     GtkTreeModel *file_store;
     GtkTreeIter fi;
-    gchar *name,*dir;
+    gchar *name;
+#ifdef WIN32
+    HMODULE module;
+    DWORD flags=
+#ifdef LOAD_LIBRARY_AS_IMAGE_RESOURCE
+      LOAD_LIBRARY_AS_IMAGE_RESOURCE|
+#endif
+      LOAD_LIBRARY_AS_DATAFILE;
+#else
+    gchar *dir;
+#endif
     gboolean visible=FALSE;
     gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&package,-1);
     if (package)
@@ -45,11 +70,27 @@ static gboolean plover_applications_visible_func(GtkTreeModel *model,
            {
                gtk_tree_model_get(file_store,&fi,
                  PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN,&name,-1);
+#ifdef WIN32
+               if (g_str_has_suffix(name,".exe"))
+               {
+                   module=LoadLibraryExA(name,NULL,flags);
+                   if (module)
+                   {
+                       (void)EnumResourceNamesA(module,RT_ICON,
+                         plover_applications_visible_callback,&visible);
+                       if (!visible)
+                           (void)EnumResourceNamesA(module,RT_GROUP_ICON,
+                             plover_applications_visible_callback,&visible);
+                       FreeLibrary(module);
+                   }
+               }
+#else
                dir=g_path_get_dirname(name);
                if (!strcmp(dir,"/usr/share/applications") &&
                  g_str_has_suffix(name,".desktop"))
                    visible=TRUE;
                g_free(dir);
+#endif
                g_free(name);
            } while(!visible && gtk_tree_model_iter_next(file_store,&fi));
        }
@@ -62,7 +103,7 @@ GtkTreeModel *plover_applications_model_new(GtkTreeModel *installed)
 {
     GtkTreeModel *model;
     model=gtk_tree_model_filter_new(installed,NULL);
-    gtk_tree_model_filter_set_visible_func(model,
+    gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model),
       plover_applications_visible_func,NULL,NULL);
     return model;
 }
index 9f6a2d8..831bdfe 100644 (file)
 #include "config.h"
 #include <stdlib.h>
 #include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
 #include <glib.h>
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 #include <plover-gtk/packagestore.h>
+#include "app-manager.h"
 #include "localmedia.h"
 
 G_DEFINE_TYPE(PloverLocalMediaStore,plover_local_media_store,
@@ -56,12 +60,37 @@ static void local_media_scan_mount(PloverLocalMediaStore *store,GMount *mount)
 {
     GFile *root;
     gchar *path;
+#ifdef WIN32
+    gunichar2 *path2;
+    UINT type;
+#endif
     PloverPackageSet *set;
     root=g_mount_get_root(mount);
     path=g_file_get_path(root);
+#ifdef WIN32
     if (path)
     {
-       set=plover_package_set_new_from_repository(path,NULL);
+       path2=g_utf8_to_utf16(path,-1,NULL,NULL,NULL);
+       if (path2)
+       {
+           type=GetDriveTypeW(path2);
+           g_free(path2);
+       }
+       else
+           type=DRIVE_UNKNOWN;
+       if (type!=DRIVE_REMOVABLE && type!=DRIVE_CDROM)
+       {
+           gchar *name=g_mount_get_name(mount);
+           g_debug("Skipping non-local mount \"%s\"",name);
+           g_free(name);
+           g_free(path);
+           path=NULL;
+       }
+    }
+#endif
+    if (path)
+    {
+       set=plover_package_set_new_from_repository(path,relocations,NULL);
        if (set)
        {
            g_object_set_data(G_OBJECT(mount),"plover-local-media-set",set);
@@ -94,25 +123,38 @@ static void local_media_scan_drive(PloverLocalMediaStore *store,GDrive *drive)
 {
     GVolume *volume;
     GMount *mount;
-    GList *volumes,*link;
-    if (g_drive_has_media(drive))
-    {
+    GList *volumes,*mounts,*link;
+    if (!drive)
+       volumes=g_volume_monitor_get_volumes(store->monitor);
+    else if (g_drive_has_media(drive))
        volumes=g_drive_get_volumes(drive);
-       for(link=volumes;link;link=link->next)
+    else
+       volumes=NULL;
+    for(link=volumes;link;link=link->next)
+    {
+       volume=G_VOLUME(link->data);
+       mount=g_volume_get_mount(volume);
+       if (mount)
        {
-           volume=G_VOLUME(link->data);
-           mount=g_volume_get_mount(volume);
-           if (mount)
-           {
-               local_media_scan_mount(store,mount);
-               g_object_unref(mount);
-           }
-           else if (!store->implicit_scan && g_volume_can_mount(volume))
-               g_volume_mount(volume,G_MOUNT_MOUNT_NONE,NULL,NULL,
-                 local_media_mounted,store);
-           g_object_unref(volume);
+           local_media_scan_mount(store,mount);
+           g_object_unref(mount);
+       }
+       else if (!store->implicit_scan && g_volume_can_mount(volume))
+           g_volume_mount(volume,G_MOUNT_MOUNT_NONE,NULL,NULL,
+             local_media_mounted,store);
+       g_object_unref(volume);
+    }
+    g_list_free(volumes);
+    if (!drive)
+    {
+       mounts=g_volume_monitor_get_mounts(store->monitor);
+       for(link=mounts;link;link=link->next)
+       {
+           mount=G_MOUNT(link->data);
+           local_media_scan_mount(store,mount);
+           g_object_unref(mount);
        }
-       g_list_free(volumes);
+       g_list_free(mounts);
     }
 }
 
@@ -127,9 +169,15 @@ static void local_media_polled(GObject *source,GAsyncResult *res,gpointer data)
 
 void plover_local_media_store_scan(PloverLocalMediaStore *store)
 {
-    GList *drives,*link;
+    GList *sets,*drives,*link;
     GDrive *drive;
     g_return_if_fail(PLOVER_IS_LOCAL_MEDIA_STORE(store));
+    sets=
+      g_slist_copy(plover_package_store_get_sets(PLOVER_PACKAGE_STORE(store)));
+    for(link=sets;link;link=link->next)
+       plover_package_store_remove_set(PLOVER_PACKAGE_STORE(store),
+         PLOVER_PACKAGE_SET(link->data));
+    g_slist_free(sets);
     drives=g_volume_monitor_get_connected_drives(store->monitor);
     for(link=drives;link;link=link->next)
     {
@@ -149,6 +197,7 @@ void plover_local_media_store_scan(PloverLocalMediaStore *store)
        g_object_unref(drive);
     }
     g_list_free(drives);
+    local_media_scan_drive(store,NULL);
 }
 
 static void local_media_mount_added(GVolumeMonitor *volume_monitor,
index 6425f95..988c7e3 100644 (file)
@@ -75,9 +75,9 @@ void package_present(PloverPackage *package)
                if (t)
                    t+=3;
                if (t)
-                   s=strndup(t,strcspn(t,"/"));
+                   s=g_strndup(t,strcspn(t,"/"));
                else
-                   s=strdup(text);
+                   s=g_strdup(text);
                gtk_button_set_label(GTK_BUTTON(w),s);
                g_free(s);
            }
@@ -152,10 +152,11 @@ static void package_cell_data_func(GtkTreeViewColumn *column,
 {
     gchar *markup;
     gchar *summary,*name,*version;
+    g_return_if_fail(GTK_IS_TREE_MODEL(model));
     gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_SUMMARY_COLUMN,&summary,
       PLOVER_PACKAGE_STORE_NAME_COLUMN,&name,
       PLOVER_PACKAGE_STORE_VERSION_COLUMN,&version,-1);
-    markup=g_strdup_printf("<b>%s</b>\n%s %s",summary,name,version,NULL);
+    markup=g_markup_printf_escaped("<b>%s</b>\n%s %s",summary,name,version);
     g_free(summary);
     g_free(name);
     g_free(version);
index 854481e..4c1367e 100644 (file)
@@ -116,6 +116,7 @@ LIBS="$save_LIBS"
 ##################################################
 # Checks for library functions.
 ##################################################
+AC_CHECK_FUNCS_ONCE([fchdir])
 
 ##################################################
 # Checks for processor independent files.
index 4d41f41..ab6554e 100644 (file)
@@ -1,5 +1,5 @@
 AM_CFLAGS=-g $(PLOVER_GTK_CFLAGS)
-LIBS=$(PLOVER_GTK_LIBS)
+LIBS=../plover/libplover.la $(PLOVER_GTK_LIBS)
 INCLUDES=-I$(top_srcdir)
 LDFLAGS=-no-undefined -version-info $(PLOVER_GTK_LT_VERSION_INFO)
 
index e3ea09e..96c8a73 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <glib-object.h>
+#include <gtk/gtk.h>
 #include <razor.h>
 #include "plover-gtk/package.h"
 
@@ -83,7 +84,7 @@ PloverPackage *plover_package_new(struct razor_set *set,
 const char *plover_package_get_name(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *name;
+    const char *name=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_NAME,&name,
@@ -94,7 +95,7 @@ const char *plover_package_get_name(PloverPackage *package)
 const char *plover_package_get_summary(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *summary;
+    const char *summary=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_SUMMARY,&summary,
@@ -105,7 +106,7 @@ const char *plover_package_get_summary(PloverPackage *package)
 const char *plover_package_get_version(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *version;
+    const char *version=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_VERSION,&version,
@@ -116,7 +117,7 @@ const char *plover_package_get_version(PloverPackage *package)
 const char *plover_package_get_license(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *license;
+    const char *license=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_LICENSE,&license,
@@ -127,7 +128,7 @@ const char *plover_package_get_license(PloverPackage *package)
 const char *plover_package_get_arch(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *arch;
+    const char *arch=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_ARCH,&arch,
@@ -138,7 +139,7 @@ const char *plover_package_get_arch(PloverPackage *package)
 const char *plover_package_get_description(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *description;
+    const char *description=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_DESCRIPTION,
@@ -149,7 +150,7 @@ const char *plover_package_get_description(PloverPackage *package)
 const char *plover_package_get_URL(PloverPackage *package)
 {
     PloverPackagePrivate *priv;
-    const char *URL;
+    const char *URL=NULL;
     g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
     priv=PLOVER_PACKAGE_GET_PRIVATE(package);
     razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_URL,&URL,
index d119555..9250c0c 100644 (file)
@@ -230,6 +230,7 @@ PloverPackageFileStore *
   plover_package_file_store_new(struct razor_file_iterator *files)
 {
     const char *name;
+    char *s;
     GSequenceIter *si;
     GtkTreeIter ti;
     GtkTreePath *path;
@@ -243,7 +244,11 @@ PloverPackageFileStore *
     indices=gtk_tree_path_get_indices(path);
     while(razor_file_iterator_next(files,&name))
     {
-       si=g_sequence_insert_sorted(priv->seq,g_strdup(name),g_strcmp0,NULL);
+       s=g_strdup(name);
+#ifdef WIN32
+       s=g_strdelimit(s,"/",'\\');
+#endif
+       si=g_sequence_insert_sorted(priv->seq,s,g_strcmp0,NULL);
        *indices=g_sequence_iter_get_position(si);
        ti.stamp=priv->stamp;
        ti.user_data=si;
index 29b65aa..ceb009f 100644 (file)
@@ -34,6 +34,7 @@ typedef struct _PloverPackageSetPrivate {
     struct razor_root *root;
     struct razor_set *set;
     GSList *packages;
+    int no_details;
 } PloverPackageSetPrivate;
 
 #define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\
@@ -84,6 +85,9 @@ static void plover_package_set_class_init(PloverPackageSetClass *klass)
 
 static void plover_package_set_init(PloverPackageSet *set)
 {
+    PloverPackageSetPrivate *priv;
+    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+    priv->no_details=-1;
 }
 
 PloverPackageSet *plover_package_set_new(void)
@@ -118,27 +122,60 @@ PloverPackageSet *plover_package_set_new_from_installed(const char *root,
 }
 
 PloverPackageSet *plover_package_set_new_from_repository(const char *base,
-  GError **err)
+  struct razor_relocations *relocations,GError **err)
 {
+#if HAVE_FCHDIR
     int fd;
+#else
+    size_t wd_len;
+    char *wd;
+#endif
     gchar *s;
+    struct razor_set *reloc;
     PloverPackageSet *set;
     PloverPackageSetPrivate *priv;
     set=plover_package_set_new();
     priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+#if HAVE_FCHDIR
     fd=open(".",O_RDONLY);
+#else
+    wd_len=32;
+    wd=malloc(wd_len);
+    while (!getcwd(wd,wd_len) && errno==ERANGE)
+    {
+       free(wd);
+       wd_len*=2;
+       wd=malloc(wd_len);
+    }
+#endif
     s=g_build_filename(base,"repodata",NULL);
     if (chdir(s)<0)
     {
        g_set_error(err,G_FILE_ERROR,g_file_error_from_errno(errno),
          "%s: %s",s,g_strerror(errno));
        g_object_unref(set);
+#if HAVE_FCHDIR
+       close(fd);
+#else
+       free(wd);
+#endif
        return NULL;
     }
     g_free(s);
     priv->set=plover_razor_set_create_from_yum("..");
+#if HAVE_FCHDIR
     fchdir(fd);
     close(fd);
+#else
+    chdir(wd);
+    free(wd);
+#endif
+    if (priv->set && relocations)
+    {
+       reloc=plover_relocate_packages(priv->set,base,relocations);
+       razor_set_destroy(priv->set);
+       priv->set=reloc;
+    }
     if (!priv->set)
     {
        g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
@@ -169,3 +206,44 @@ GSList *plover_package_set_get_packages(PloverPackageSet *set)
     }
     return priv->packages;
 }
+
+/*
+ * Some versions of razor have a bug which causes all detail strings
+ * to be discarded. If such a version of razor is used to install or
+ * update a package, then all the detail strings for the installed
+ * set will be lost. This function tests for this condition and can
+ * be used to present something more useful than blank details.
+ */
+
+gboolean plover_package_set_get_no_details(PloverPackageSet *set)
+{
+    PloverPackageSetPrivate *priv;
+    PloverPackage *package;
+    GSList *packages,*link;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),FALSE);
+    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+    if (priv->no_details<0)
+    {
+       packages=plover_package_set_get_packages(set);
+       if (packages)
+       {
+           priv->no_details=0;
+           for(link=packages;link;link=link->next)
+           {
+               package=link->data;
+               priv->no_details+=2;
+               if (*plover_package_get_summary(package))
+                   priv->no_details--;
+               if (*plover_package_get_license(package))
+                   priv->no_details--;
+               if (*plover_package_get_description(package))
+                   priv->no_details--;
+               if (*plover_package_get_URL(package))
+                   priv->no_details--;
+           }
+           if (priv->no_details<0)     /* More than 50% of strings present */
+               priv->no_details=0;
+       }
+    }
+    return priv->no_details>0;
+}
index e3e8ecf..66c0529 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __PLOVER_PACKAGE_SET_H__
 #define __PLOVER_PACKAGE_SET_H__
 
+#include <razor.h>
 #include <glib-object.h>
 
 G_BEGIN_DECLS
@@ -36,8 +37,9 @@ PloverPackageSet *plover_package_set_new(void);
 PloverPackageSet *plover_package_set_new_from_installed(const char *root,
   GError **err);
 PloverPackageSet *plover_package_set_new_from_repository(const char *base,
-  GError **err);
+  struct razor_relocations *relocations,GError **err);
 GSList *plover_package_set_get_packages(PloverPackageSet *set);
+gboolean plover_package_set_get_no_details(PloverPackageSet *set);
 
 G_END_DECLS
 
index 408964c..1be7576 100644 (file)
@@ -137,11 +137,12 @@ static GtkTreePath *
 static void plover_package_store_get_value(GtkTreeModel *tree_model,
   GtkTreeIter *iter,gint column,GValue *value)
 {
+    char *s;
     PloverPackageStore *store=(PloverPackageStore *)tree_model;
     PloverPackage *package;
     g_return_if_fail(column>=0 && column<PLOVER_PACKAGE_STORE_NO_COLUMNS);
     g_return_if_fail(VALID_ITER(iter,store));
-    package=g_sequence_get(iter->user_data);
+    package=PLOVER_PACKAGE(g_sequence_get(iter->user_data));
     g_value_init(value,column_types[column]);
     switch((PloverPackageStoreColumn)column)
     {
@@ -160,7 +161,16 @@ static void plover_package_store_get_value(GtkTreeModel *tree_model,
            g_value_set_string(value,plover_package_get_version(package));
            break;
        case PLOVER_PACKAGE_STORE_SUMMARY_COLUMN:
-           g_value_set_string(value,plover_package_get_summary(package));
+           s=plover_package_get_summary(package);
+           if (*s)
+               g_value_set_string(value,s);
+           else
+           {
+               s=g_strconcat("The ",plover_package_get_name(package),
+                 " package",NULL);
+               g_value_set_string(value,s);
+               g_free(s);
+           }
            break;
     }
 }
index 78c729a..f1c4d68 100644 (file)
@@ -17,6 +17,6 @@ resources.$(OBJEXT): resources.rc setup.ico
        $(WINDRES) resources.rc $@
 
 setup.ico:     icon16.pnm icon22.pnm icon32.pnm
-        ppmtowinicon -output=$@ $^
+       ppmtowinicon -output=$@ $^
 
 EXTRA_DIST=icon16.png icon22.png icon32.png
index 51a31cf..895d9f7 100644 (file)
@@ -3,10 +3,10 @@
 MAINICON ICON "setup.ico"
 
 VS_VERSION_INFO VERSIONINFO
-    FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,@PLOVER_MICRO_VERS
-ION@,0
-    PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,@PLOVER_MICRO_V
-ERSION@,0
+    FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
+    PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
     FILEOS VOS__WINDOWS32
     FILETYPE VFT_APP
     {
index c39f6de..0f721c2 100644 (file)
@@ -17,6 +17,6 @@ resources.$(OBJEXT): resources.rc update.ico
        $(WINDRES) resources.rc $@
 
 update.ico:     icon16.pnm icon22.pnm icon32.pnm
-        ppmtowinicon -output=$@ $^
+       ppmtowinicon -output=$@ $^
 
 EXTRA_DIST=icon16.png icon22.png icon32.png
index ea31644..b11aecb 100644 (file)
@@ -3,10 +3,10 @@
 MAINICON ICON "update.ico"
 
 VS_VERSION_INFO VERSIONINFO
-    FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,@PLOVER_MICRO_VERS
-ION@,0
-    PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,@PLOVER_MICRO_V
-ERSION@,0
+    FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
+    PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
     FILEOS VOS__WINDOWS32
     FILETYPE VFT_APP
     {