Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP5:Update
gnome-packagekit.6609
gnome-packagekit-fix-logout-button-not-working....
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gnome-packagekit-fix-logout-button-not-working.patch of Package gnome-packagekit.6609
From ecb2afe33e70b66af8e95d79afc6470e5ad3ce16 Mon Sep 17 00:00:00 2001 From: Jonathan Kang <jonathan121537@gmail.com> Date: Wed, 3 Aug 2016 15:17:18 +0800 Subject: [PATCH] Revert "Move the D-Bus interface to gnome-software" and "Remove unused functionality" This reverts commit 0780f7987f0dc9a0021207ea22e9b032be6b27e1 and 52b1ece4d58f407436bd74aceeca9da607c701eb --- configure.ac | 5 + data/Makefile.am | 9 + data/gpk-dbus-service.desktop.in | 10 + data/org.freedesktop.PackageKit.service.in | 4 + docs/Makefile.am | 1 + docs/dbus/.gitignore | 3 + docs/dbus/Makefile.am | 17 + docs/dbus/dbus-introspect-docs.dtd | 32 + docs/dbus/spec-to-docbook.xsl | 436 ++++ man/Makefile.am | 4 + man/gpk-dbus-service.sgml | 77 + man/gpk-install-local-file.sgml | 77 + po/POTFILES.in | 7 + src/Makefile.am | 97 + src/gpk-animated-icon.c | 307 +++ src/gpk-animated-icon.h | 72 + src/gpk-application.c | 6 +- src/gpk-common.c | 47 + src/gpk-common.h | 5 + src/gpk-dbus-service.c | 184 ++ src/gpk-dbus-task.c | 3273 ++++++++++++++++++++++++++++ src/gpk-dbus-task.h | 161 ++ src/gpk-dbus.c | 590 +++++ src/gpk-dbus.h | 124 ++ src/gpk-enum.c | 139 +- src/gpk-enum.h | 8 + src/gpk-error.c | 2 +- src/gpk-error.h | 5 + src/gpk-gnome.c | 49 + src/gpk-gnome.h | 33 + src/gpk-helper-chooser.c | 348 +++ src/gpk-helper-chooser.h | 65 + src/gpk-helper-run.c | 392 ++++ src/gpk-helper-run.h | 61 + src/gpk-install-local-file.c | 139 ++ src/gpk-language.c | 196 ++ src/gpk-language.h | 60 + src/gpk-log.c | 1 + src/gpk-marshal.list | 3 + src/gpk-modal-dialog.c | 861 ++++++++ src/gpk-modal-dialog.h | 127 ++ src/gpk-prefs.c | 1 + src/gpk-self-test.c | 219 ++ src/gpk-session.c | 361 +++ src/gpk-session.h | 69 + src/gpk-task.c | 1 + src/gpk-update-viewer.c | 12 +- src/gpk-vendor.c | 159 ++ src/gpk-vendor.h | 70 + src/gpk-x11.c | 250 +++ src/gpk-x11.h | 63 + src/org.freedesktop.PackageKit.xml | 506 +++++ 53 files changed, 9754 insertions(+), 4 deletions(-) create mode 100644 data/gpk-dbus-service.desktop.in create mode 100644 data/org.freedesktop.PackageKit.service.in create mode 100644 docs/dbus/.gitignore create mode 100644 docs/dbus/Makefile.am create mode 100644 docs/dbus/dbus-introspect-docs.dtd create mode 100644 docs/dbus/spec-to-docbook.xsl create mode 100644 man/gpk-dbus-service.sgml create mode 100644 man/gpk-install-local-file.sgml create mode 100644 src/gpk-animated-icon.c create mode 100644 src/gpk-animated-icon.h create mode 100644 src/gpk-dbus-service.c create mode 100644 src/gpk-dbus-task.c create mode 100644 src/gpk-dbus-task.h create mode 100644 src/gpk-dbus.c create mode 100644 src/gpk-dbus.h create mode 100644 src/gpk-gnome.c create mode 100644 src/gpk-gnome.h create mode 100644 src/gpk-helper-chooser.c create mode 100644 src/gpk-helper-chooser.h create mode 100644 src/gpk-helper-run.c create mode 100644 src/gpk-helper-run.h create mode 100644 src/gpk-install-local-file.c create mode 100644 src/gpk-language.c create mode 100644 src/gpk-language.h create mode 100644 src/gpk-marshal.list create mode 100644 src/gpk-modal-dialog.c create mode 100644 src/gpk-modal-dialog.h create mode 100644 src/gpk-session.c create mode 100644 src/gpk-session.h create mode 100644 src/gpk-vendor.c create mode 100644 src/gpk-vendor.h create mode 100644 src/gpk-x11.c create mode 100644 src/gpk-x11.h create mode 100644 src/org.freedesktop.PackageKit.xml Index: gnome-packagekit-3.20.0/configure.ac =================================================================== --- gnome-packagekit-3.20.0.orig/configure.ac +++ gnome-packagekit-3.20.0/configure.ac @@ -92,6 +92,10 @@ PKG_CHECK_MODULES(GLIB, \ gobject-2.0 gio-2.0 >= 2.25.9 gio-unix-2.0) +PKG_CHECK_MODULES(DBUS, \ + dbus-glib-1 >= 0.73 \ + dbus-1 >= 1.1.2 \ + gthread-2.0) PKG_CHECK_MODULES(GTK, \ gtk+-3.0 >= 3.15.3 gdk-3.0 fontconfig) PKG_CHECK_MODULES(CANBERRA, libcanberra-gtk3 >= 0.10) @@ -203,6 +207,7 @@ po/Makefile.in data/Makefile data/appdata/Makefile docs/Makefile +docs/dbus/Makefile data/icons/Makefile data/icons/16x16/Makefile data/icons/22x22/Makefile Index: gnome-packagekit-3.20.0/data/Makefile.am =================================================================== --- gnome-packagekit-3.20.0.orig/data/Makefile.am +++ gnome-packagekit-3.20.0/data/Makefile.am @@ -9,6 +9,7 @@ dist_migration_DATA = org.gnome.packagek desktopdir = $(datadir)/applications desktop_in_files = \ gpk-install-local-file.desktop.in \ + gpk-dbus-service.desktop.in \ gpk-prefs.desktop.in \ gpk-application.desktop.in \ gpk-update-viewer.desktop.in \ @@ -30,6 +31,13 @@ pkgdata_DATA = \ gpk-client.ui \ $(NULL) +servicedir = $(datadir)/dbus-1/services +service_in_files = org.freedesktop.PackageKit.service.in +service_DATA = $(service_in_files:.service.in=.service) + +$(service_DATA): $(service_in_files) Makefile + @sed -e "s|\@servicedir\@|$(bindir)|" $< > $@ + @GSETTINGS_RULES@ gsettings_SCHEMAS = org.gnome.packagekit.gschema.xml @@ -48,6 +56,7 @@ DISTCLEANFILES = \ gpk-prefs.desktop \ gpk-update-viewer.desktop \ gpk-install-local-file.desktop \ + gpk-dbus-service.desktop \ gpk-log.desktop \ gpk-application.desktop \ org.freedesktop.PackageKit.service \ Index: gnome-packagekit-3.20.0/data/gpk-dbus-service.desktop.in =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/data/gpk-dbus-service.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +_Name=Software Install +_Comment=Install selected software on the system +Categories=System; +Exec=gpk-dbus-service +Terminal=false +Type=Application +Icon=system-software-install +StartupNotify=true +NoDisplay=true Index: gnome-packagekit-3.20.0/data/org.freedesktop.PackageKit.service.in =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/data/org.freedesktop.PackageKit.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.PackageKit +Exec=@servicedir@/gpk-dbus-service + Index: gnome-packagekit-3.20.0/docs/Makefile.am =================================================================== --- gnome-packagekit-3.20.0.orig/docs/Makefile.am +++ gnome-packagekit-3.20.0/docs/Makefile.am @@ -1 +1,2 @@ +SUBDIRS = dbus Index: gnome-packagekit-3.20.0/docs/dbus/.gitignore =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/docs/dbus/.gitignore @@ -0,0 +1,3 @@ +*.ref.xml +*.html + Index: gnome-packagekit-3.20.0/docs/dbus/Makefile.am =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/docs/dbus/Makefile.am @@ -0,0 +1,17 @@ + +if ENABLE_GTK_DOC + +all : org.freedesktop.PackageKit.ref.xml + +org.freedesktop.PackageKit.ref.xml : $(top_srcdir)/src/org.freedesktop.PackageKit.xml $(top_srcdir)/docs/dbus/spec-to-docbook.xsl + echo "<?xml version=\"1.0\"?>""<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">" > $@ + $(XSLTPROC) $(top_srcdir)/docs/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@ + +#$(top_srcdir)/docs/dbus/spec-to-docbook $(top_srcdir)/src/org.freedesktop.PackageKit.xml + +endif + +EXTRA_DIST = spec-to-docbook.xsl dbus-introspect-docs.dtd + +clean-local : + rm -f *~ *.ref.xml Index: gnome-packagekit-3.20.0/docs/dbus/dbus-introspect-docs.dtd =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/docs/dbus/dbus-introspect-docs.dtd @@ -0,0 +1,32 @@ +<!-- DTD for D-Bus Introspection Documentation --> + +<!ELEMENT doc (summary?,description?,errors?,permission?,since?,deprecated,seealso?)> + +<!ELEMENT summary (#PCDATA|ref)*> +<!ELEMENT description (#PCDATA|para|example)*> +<!ELEMENT errors (error)*> +<!ELEMENT permission (#PCDATA|ref|para)*> +<!ELEMENT since EMPTY> +<!ATTLIST since version CDATA #REQUIRED> +<!ELEMENT deprecated (#PCDATA|ref)> +<!ATTLIST deprecated version CDATA #REQUIRED> +<!ATTLIST deprecated instead CDATA #REQUIRED> +<!ELEMENT seealso (ref+)> + +<!ELEMENT error (#PCDATA|para)*> +<!ATTLIST error name CDATA #REQUIRED> +<!ELEMENT para (#PCDATA|example|code|list|ref)*> +<!ELEMENT example (#PCDATA|para|code|ref)*> +<!ATTLIST language (c|glib|python|shell) #REQUIRED> +<!ATTLIST title CDATA #IMPLIED> +<!ELEMENT list (listheader?, item*)> +<!ATTLIST list type (bullet|number|table) #REQUIRED> +<!ELEMENT item (term|definition)*> +<!ELEMENT term (#PCDATA|ref)*> +<!ELEMENT definition (#PCDATA|para)*> + +<!ELEMENT code (#PCDATA)> +<!ATTLIST code lang CDATA #IMPLIED> +<!ELEMENT ref CDATA> +<!ATTLIST ref type (parameter|arg|signal|method|interface) #REQUIRED> +<!ATTLIST ref to CDATA #REQUIRED> Index: gnome-packagekit-3.20.0/docs/dbus/spec-to-docbook.xsl =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/docs/dbus/spec-to-docbook.xsl @@ -0,0 +1,436 @@ +<?xml version='1.0'?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd" + exclude-result-prefixes="doc"> +<!-- + Convert D-Bus Glib xml into DocBook refentries + Copyright (C) 2007 William Jon McCann + License: GPL +--> +<xsl:output method="xml" indent="yes" encoding="UTF-8"/> + +<xsl:template match="/"> + +<xsl:variable name="interface" select="//interface/@name"/> +<xsl:variable name="basename"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="$interface"/> + </xsl:call-template> +</xsl:variable> + +<refentry><xsl:attribute name="id"><xsl:value-of select="$basename"/></xsl:attribute> + <refmeta> + <refentrytitle role="top_of_page"><xsl:value-of select="//interface/@name"/></refentrytitle> + </refmeta> + + <refnamediv> + <refname><xsl:value-of select="//interface/@name"/></refname> + <refpurpose><xsl:value-of select="$basename"/> interface</refpurpose> + </refnamediv> + + <refsynopsisdiv role="synopsis"> + <title role="synopsis.title">Methods</title> + <synopsis> + <xsl:call-template name="methods-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsynopsisdiv> + + <refsect1 role="signal_proto"> + <title role="signal_proto.title">Signals</title> + <synopsis> + <xsl:call-template name="signals-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsect1> + + <refsect1 role="impl_interfaces"> + <title role="impl_interfaces.title">Implemented Interfaces</title> + <para> + <xsl:value-of select="$interface"/> implements + org.freedesktop.DBus.Introspectable, + org.freedesktop.DBus.Properties + </para> + </refsect1> + + <refsect1 role="properties"> + <title role="properties.title">Properties</title> + <synopsis> + <xsl:call-template name="properties-synopsis"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </synopsis> + </refsect1> + + <refsect1 role="desc"> + <title role="desc.title">Description</title> + <para> + <xsl:apply-templates select="//interface/doc:doc"/> + </para> + </refsect1> + + <refsect1 role="details"> + <title role="details.title">Details</title> + <xsl:call-template name="method-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + + <refsect1 role="signals"> + <title role="signals.title">Signal Details</title> + <xsl:call-template name="signal-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + + <refsect1 role="property_details"> + <title role="property_details.title">Property Details</title> + <xsl:call-template name="property-details"> + <xsl:with-param name="basename" select="$basename"/> + </xsl:call-template> + </refsect1> + +</refentry> +</xsl:template> + + +<xsl:template name="property-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + <xsl:apply-templates select="doc:doc/doc:permission"/> + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + + +<xsl:template name="property-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///property"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting>'<xsl:value-of select="@name"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="2"/></xsl:call-template> +<xsl:call-template name="property-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/></xsl:call-template></programlisting> + </refsect2> + + <xsl:call-template name="property-doc"/> + + </xsl:for-each> +</xsl:template> + +<xsl:template name="signal-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + <xsl:apply-templates select="doc:doc/doc:permission"/> + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + +<xsl:template name="signal-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///signal"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> + </refsect2> + + <xsl:call-template name="signal-doc"/> + + </xsl:for-each> +</xsl:template> + +<xsl:template match="doc:code"> +<programlisting> +<xsl:apply-templates /> +</programlisting> +</xsl:template> + +<xsl:template match="doc:summary"> +<!-- by default don't display --> +</xsl:template> + +<xsl:template match="doc:example"> +<informalexample> +<xsl:apply-templates /> +</informalexample> +</xsl:template> + +<xsl:template match="doc:para"> +<para> +<xsl:apply-templates /> +</para> +</xsl:template> + +<xsl:template match="doc:description"> +<xsl:apply-templates /> +</xsl:template> + +<xsl:template match="doc:since"> +<para role="since">Since <xsl:value-of select="@version"/> +</para> +</xsl:template> + +<xsl:template match="doc:deprecated"> + <xsl:variable name="name" select="../../@name"/> + <xsl:variable name="parent"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="../../../@name"/>/> + </xsl:call-template> + </xsl:variable> + + <xsl:variable name="type" select="name(../..)"/> + + <para role="deprecated"> + <warning><para><literal><xsl:value-of select="$name"/></literal> is deprecated since version <xsl:value-of select="@version"/> and should not be used in newly-written code. Use + + <xsl:variable name="to"> + <xsl:choose> + <xsl:when test="contains($type,'property')"> + <xsl:value-of select="$parent"/>:<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'signal')"> + <xsl:value-of select="$parent"/>::<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'method')"> + <xsl:value-of select="$parent"/>.<xsl:value-of select="@instead"/> + </xsl:when> + <xsl:when test="contains($type,'interface')"> + <xsl:value-of select="@instead"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@instead"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:call-template name="create-link"> + <xsl:with-param name="type" select="$type"/> + <xsl:with-param name="to" select="$to"/> + <xsl:with-param name="val" select="@instead"/> + </xsl:call-template> +instead.</para></warning> +</para> +</xsl:template> + +<xsl:template match="doc:permission"> +<para role="permission"> +<xsl:apply-templates /> +</para> +</xsl:template> + +<xsl:template match="doc:seealso"> +<para> +See also: +<xsl:apply-templates /> + +</para> +</xsl:template> + +<xsl:template name="create-link"> + <xsl:param name="type"/> + <xsl:param name="to"/> + <xsl:param name="val"/> + + <xsl:choose> + <xsl:when test="contains($type,'property')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> + </xsl:when> + <xsl:when test="contains($type,'signal')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link> + </xsl:when> + <xsl:when test="contains($type,'method')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><function><xsl:value-of select="$val"/></function></link> + </xsl:when> + <xsl:when test="contains($type,'interface')"> + <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link> + </xsl:when> + </xsl:choose> +</xsl:template> + +<xsl:template match="doc:ref"> + <xsl:call-template name="create-link"> + <xsl:with-param name="type" select="@type"/> + <xsl:with-param name="to" select="@to"/> + <xsl:with-param name="val" select="."/> + </xsl:call-template> +</xsl:template> + +<xsl:template name="method-doc"> + <xsl:apply-templates select="doc:doc/doc:description"/> + + <variablelist role="params"> + <xsl:for-each select="arg"> +<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term> +<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem> +</varlistentry> + </xsl:for-each> + </variablelist> + + <xsl:apply-templates select="doc:doc/doc:since"/> + <xsl:apply-templates select="doc:doc/doc:deprecated"/> + <xsl:apply-templates select="doc:doc/doc:permission"/> + <xsl:apply-templates select="doc:doc/doc:seealso"/> +</xsl:template> + +<xsl:template name="method-details"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///method"> + <refsect2> + <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> ()</title> +<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm> +<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="method-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting> + </refsect2> + + <xsl:call-template name="method-doc"/> + + </xsl:for-each> +</xsl:template> + + +<xsl:template name="properties-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///property/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///property"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute>'<xsl:value-of select="@name"/>'</link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="$longest + 2"/></xsl:call-template> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="signals-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///signal/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///signal"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///signal"/></xsl:call-template>) +</xsl:for-each> +</xsl:template> + + +<xsl:template name="methods-synopsis"> + <xsl:param name="basename"/> + <xsl:variable name="longest"> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="///method/@name"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="///method"> +<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="method-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///method"/></xsl:call-template>) +</xsl:for-each> +</xsl:template> + + +<xsl:template name="method-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg"><xsl:value-of select="@direction"/> +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="4 - string-length(@direction)"/></xsl:call-template>'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> +<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="signal-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg">'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template> +<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">, +<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if> +</xsl:for-each> +</xsl:template> + + +<xsl:template name="property-args"><xsl:param name="indent"/> +<xsl:value-of select="@access"/><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="9 - string-length(@access) + 1"/></xsl:call-template>'<xsl:value-of select="@type"/>' +</xsl:template> + + +<xsl:template name="pad-spaces"> + <xsl:param name="width"/> + <xsl:variable name="spaces" xml:space="preserve"> </xsl:variable> + <xsl:value-of select="substring($spaces,1,$width)"/> +</xsl:template> + + +<xsl:template name="find-longest"> + <xsl:param name="set"/> + <xsl:param name="index" select="1"/> + <xsl:param name="longest" select="0"/> + + <xsl:choose> + <xsl:when test="$index > count($set)"> + <!--finished looking--> + <xsl:value-of select="$longest"/> + </xsl:when> + <xsl:when test="string-length($set[$index])>$longest"> + <!--found new longest--> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="$set"/> + <xsl:with-param name="index" select="$index + 1"/> + <xsl:with-param name="longest" select="string-length($set[$index])"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!--this isn't any longer--> + <xsl:call-template name="find-longest"> + <xsl:with-param name="set" select="$set"/> + <xsl:with-param name="index" select="$index + 1"/> + <xsl:with-param name="longest" select="$longest"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + + +<xsl:template name="interface-basename"> + <xsl:param name="str"/> + <xsl:choose> + <xsl:when test="contains($str,'.')"> + <xsl:call-template name="interface-basename"> + <xsl:with-param name="str" select="substring-after($str,'.')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$str"/> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +</xsl:stylesheet> Index: gnome-packagekit-3.20.0/man/Makefile.am =================================================================== --- gnome-packagekit-3.20.0.orig/man/Makefile.am +++ gnome-packagekit-3.20.0/man/Makefile.am @@ -1,5 +1,7 @@ EXTRA_DIST = \ gpk-application.sgml \ + gpk-dbus-service.sgml \ + gpk-install-local-file.sgml \ gpk-log.sgml \ gpk-prefs.sgml \ gpk-update-viewer.sgml @@ -7,6 +9,8 @@ EXTRA_DIST = \ if HAVE_DOCBOOK2MAN man_MANS = \ gpk-application.1 \ + gpk-dbus-service.1 \ + gpk-install-local-file.1 \ gpk-log.1 \ gpk-prefs.1 \ gpk-update-viewer.1 Index: gnome-packagekit-3.20.0/man/gpk-dbus-service.sgml =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/man/gpk-dbus-service.sgml @@ -0,0 +1,77 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY date "<date>11 April,2008</date>"> + <!ENTITY package "gpk-dbus-service"> + <!ENTITY gnu "<acronym>GNU</acronym>"> + <!ENTITY gpl "&gnu; <acronym>GPL</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + <email>richard@hughsie.com</email>; + </address> + <author> + <firstname>Richard</firstname> + <surname>Hughes</surname> + </author> + <copyright> + <year>2008-2013</year> + <holder>Richard Hughes</holder> + </copyright> + &date; + </refentryinfo> + <refmeta> + <refentrytitle>gpk-dbus-service</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + <refnamediv> + <refname>&package;</refname> + <refpurpose>GNOME PackageKit Session Service</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&package;</command> + <arg><option>--verbose</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + <para> + This manual page documents briefly the <command>&package;</command> command. + </para> + <para> + <command>&package;</command> provides the PackageKit D-Bus session API in GNOME. + </para> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + <para>gpk-update-viewer (1).</para> + <para>gpk-application (2).</para> + <para>gpk-log (3).</para> + <para>gpk-install-catalog (4).</para> + </refsect1> + <refsect1> + <title>AUTHOR</title> + <para>This manual page was written by Richard Hughes <email>richard@hughsie.com</email>. + </para> + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> + Index: gnome-packagekit-3.20.0/man/gpk-install-local-file.sgml =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/man/gpk-install-local-file.sgml @@ -0,0 +1,77 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY date "<date>11 April,2008</date>"> + <!ENTITY package "gpk-install-local-file"> + <!ENTITY gnu "<acronym>GNU</acronym>"> + <!ENTITY gpl "&gnu; <acronym>GPL</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + <email>richard@hughsie.com</email>; + </address> + <author> + <firstname>Richard</firstname> + <surname>Hughes</surname> + </author> + <copyright> + <year>2008-2013</year> + <holder>Richard Hughes</holder> + </copyright> + &date; + </refentryinfo> + <refmeta> + <refentrytitle>gpk-install-local-file</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + <refnamediv> + <refname>&package;</refname> + <refpurpose>GNOME PackageKit Local File Helper</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&package;</command> + <arg><option>--verbose</option></arg> + <arg><option>filename</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + <para> + This manual page documents briefly the <command>&package;</command> command. + </para> + <para> + <command>&package;</command> allows you to install a local package file such as an + rpm or deb file. + </para> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + <para>gpk-install-package-name (1).</para> + <para>gpk-install-provide-file (2).</para> + </refsect1> + <refsect1> + <title>AUTHOR</title> + <para>This manual page was written by Richard Hughes <email>richard@hughsie.com</email>. + </para> + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> + Index: gnome-packagekit-3.20.0/po/POTFILES.in =================================================================== --- gnome-packagekit-3.20.0.orig/po/POTFILES.in +++ gnome-packagekit-3.20.0/po/POTFILES.in @@ -6,6 +6,7 @@ data/appdata/gpk-update-viewer.appdata.x data/gpk-application.desktop.in [type: gettext/glade]data/gpk-application.ui [type: gettext/glade]data/gpk-client.ui +data/gpk-dbus-service.desktop.in [type: gettext/glade]data/gpk-error.ui [type: gettext/glade]data/gpk-eula.ui data/gpk-install-local-file.desktop.in @@ -19,11 +20,17 @@ data/gpk-update-viewer.desktop.in data/org.gnome.packagekit.gschema.xml src/gpk-application.c src/gpk-common.c +src/gpk-dbus-service.c +src/gpk-dbus-task.c src/gpk-debug.c src/gpk-dialog.c src/gpk-enum.c src/gpk-error.c +src/gpk-helper-chooser.c +src/gpk-helper-run.c +src/gpk-install-local-file.c src/gpk-log.c +src/gpk-modal-dialog.c src/gpk-prefs.c src/gpk-task.c src/gpk-update-viewer.c Index: gnome-packagekit-3.20.0/src/Makefile.am =================================================================== --- gnome-packagekit-3.20.0.orig/src/Makefile.am +++ gnome-packagekit-3.20.0/src/Makefile.am @@ -7,6 +7,7 @@ AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \ $(GTK_CFLAGS) \ + $(DBUS_CFLAGS) \ $(NOTIFY_CFLAGS) \ $(PACKAGEKIT_CFLAGS) \ $(GUDEV_CFLAGS) \ @@ -30,8 +31,10 @@ AM_CPPFLAGS = \ bin_PROGRAMS = \ gpk-application \ gpk-prefs \ + gpk-install-local-file \ gpk-update-viewer \ gpk-log \ + gpk-dbus-service \ $(NULL) noinst_LIBRARIES = libgpkshared.a @@ -44,8 +47,28 @@ libgpkshared_a_SOURCES = \ gpk-debug.h \ gpk-enum.c \ gpk-enum.h \ + gpk-x11.c \ + gpk-x11.h \ + gpk-session.c \ + gpk-session.h \ gpk-dialog.c \ gpk-dialog.h \ + gpk-marshal.c \ + gpk-marshal.h \ + gpk-animated-icon.c \ + gpk-animated-icon.h \ + gpk-vendor.c \ + gpk-vendor.h \ + gpk-language.c \ + gpk-language.h \ + gpk-modal-dialog.c \ + gpk-modal-dialog.h \ + gpk-helper-run.c \ + gpk-helper-run.h \ + gpk-helper-chooser.c \ + gpk-helper-chooser.h \ + gpk-gnome.c \ + gpk-gnome.h \ gpk-common.c \ gpk-common.h \ gpk-task.c \ @@ -63,6 +86,7 @@ endif shared_LIBS = \ $(GLIB_LIBS) \ $(GIO_LIBS) \ + $(DBUS_LIBS) \ $(GTK_LIBS) \ $(GUDEV_LIBS) \ $(NOTIFY_LIBS) \ @@ -70,6 +94,29 @@ shared_LIBS = \ $(PACKAGEKIT_LIBS) \ $(GNOME_MENUS_LIBS) \ $(CANBERRA_LIBS) \ + $(X11_LIBS) \ + $(NULL) + +gpk_install_local_file_SOURCES = \ + gpk-install-local-file.c \ + $(NULL) + +gpk_install_local_file_LDADD = \ + libgpkshared.a \ + $(shared_LIBS) \ + $(NULL) + +gpk_dbus_service_SOURCES = \ + gpk-dbus-service.c \ + gpk-dbus.c \ + gpk-dbus.h \ + gpk-dbus-task.c \ + gpk-dbus-task.h \ + $(NULL) + +gpk_dbus_service_LDADD = \ + libgpkshared.a \ + $(shared_LIBS) \ $(NULL) gpk_application_SOURCES = \ @@ -84,6 +131,8 @@ gpk_application_LDADD = \ gpk_prefs_SOURCES = \ gpk-debug.h \ gpk-debug.c \ + gpk-animated-icon.c \ + gpk-animated-icon.h \ gpk-enum.c \ gpk-enum.h \ gpk-common.c \ @@ -122,6 +171,26 @@ gpk_log_LDADD = \ $(shared_LIBS) \ $(NULL) +BUILT_SOURCES = \ + gpk-marshal.c \ + gpk-marshal.h \ + org.freedesktop.PackageKit.h \ + $(NULL) + +gpk-marshal.c: gpk-marshal.list + echo "#include \"gpk-marshal.h\"" > $@ && \ + glib-genmarshal $< --prefix=gpk_marshal --body >> $@ + +gpk-marshal.h: gpk-marshal.list + glib-genmarshal $< --prefix=gpk_marshal --header > $@ + +org.freedesktop.PackageKit.h: org.freedesktop.PackageKit.xml + $(LIBTOOL) --mode=execute dbus-binding-tool \ + --prefix=gpk_dbus \ + --mode=glib-server \ + --output=org.freedesktop.PackageKit.h \ + $(srcdir)/org.freedesktop.PackageKit.xml + if EGG_BUILD_TESTS check_PROGRAMS = \ @@ -144,8 +213,30 @@ gpk_self_test_SOURCES = \ gpk-common.h \ gpk-error.c \ gpk-error.h \ + gpk-dbus.c \ + gpk-dbus.h \ + gpk-dbus-task.c \ + gpk-dbus-task.h \ + gpk-x11.c \ + gpk-x11.h \ gpk-task.c \ gpk-task.h \ + gpk-language.c \ + gpk-language.h \ + gpk-modal-dialog.c \ + gpk-modal-dialog.h \ + gpk-animated-icon.c \ + gpk-animated-icon.h \ + gpk-gnome.c \ + gpk-gnome.h \ + gpk-vendor.c \ + gpk-vendor.h \ + gpk-helper-run.c \ + gpk-helper-run.h \ + gpk-helper-chooser.c \ + gpk-helper-chooser.h \ + gpk-marshal.c \ + gpk-marshal.h \ gpk-dialog.c \ gpk-dialog.h \ $(NULL) @@ -160,8 +251,14 @@ gpk_self_test_CFLAGS = $(AM_CFLAGS) TESTS = gpk-self-test endif +EXTRA_DIST = \ + gpk-marshal.list \ + org.freedesktop.PackageKit.xml \ + $(NULL) + clean-local: rm -f *~ + rm -f gpk-marshal.c gpk-marshal.h rm -f *.out rm -f *.gcda rm -f *.gcno Index: gnome-packagekit-3.20.0/src/gpk-animated-icon.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-animated-icon.c @@ -0,0 +1,307 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <packagekit-glib2/packagekit.h> + +#include "egg-string.h" + +#include "gpk-animated-icon.h" + +G_DEFINE_TYPE (GpkAnimatedIcon, gpk_animated_icon, GTK_TYPE_IMAGE) + +static gpointer parent_class = NULL; + +/** + * gpk_animated_icon_free_pixbufs: + **/ +static gboolean +gpk_animated_icon_free_pixbufs (GpkAnimatedIcon *icon) +{ + guint i; + + g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE); + + /* none loaded */ + if (icon->frames == NULL) { + g_debug ("nothing to free"); + return FALSE; + } + + /* free each frame */ + for (i=0; i<icon->number_frames; i++) + g_object_unref (icon->frames[i]); + g_free (icon->frames); + icon->frames = NULL; + return TRUE; +} + +/** + * gpk_animated_icon_set_icon_name: + **/ +gboolean +gpk_animated_icon_set_icon_name (GpkAnimatedIcon *icon, GtkIconSize size, const gchar *name) +{ + g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + /* stop existing animation */ + gpk_animated_icon_enable_animation (icon, FALSE); + + /* set static image */ + gtk_image_set_from_icon_name (GTK_IMAGE (icon), name, size); + return TRUE; +} + +/** + * gpk_animated_icon_set_filename_tile: + **/ +gboolean +gpk_animated_icon_set_filename_tile (GpkAnimatedIcon *icon, GtkIconSize size, const gchar *name) +{ + gboolean ret; + gint w, h; + gint rows, cols; + gint r, c, i; + GdkPixbuf *pixbuf; + + g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + /* have we already set the same icon */ + if (g_strcmp0 (icon->filename, name) == 0) { + g_debug ("already set the same icon name %s, ignoring", name); + return FALSE; + } + + /* stop existing animation */ + gpk_animated_icon_enable_animation (icon, FALSE); + + /* save new value */ + g_free (icon->filename); + icon->filename = g_strdup (name); + + /* do we need to unload */ + if (icon->frames != NULL) { + gpk_animated_icon_free_pixbufs (icon); + } + + g_debug ("loading from %s", name); + ret = gtk_icon_size_lookup (size, &w, &h); + if (!ret) { + g_warning ("Can't get icon size info"); + return FALSE; + } + + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), name, w, 0, NULL); + /* can't load from gnome-icon-theme */ + if (pixbuf == NULL) { + g_debug ("can't load animation %s", name); + return FALSE; + } + + /* silly hack until we get some metadata */ + if (g_strcmp0 (name, "process-working") == 0) { + w = gdk_pixbuf_get_width (pixbuf) / 8; + h = gdk_pixbuf_get_height (pixbuf) / 4; + } + + /* we failed to get a valid pixbuf */ + if (w == 0 || h == 0) { + g_object_unref (pixbuf); + return FALSE; + } + + cols = gdk_pixbuf_get_width (pixbuf) / w; + rows = gdk_pixbuf_get_height (pixbuf) / h; + + icon->frame_counter = 0; + icon->number_frames = rows * cols; + icon->frames = g_new (GdkPixbuf*, icon->number_frames); + + for (i = 0, r = 0; r < rows; r++) + for (c = 0; c < cols; c++, i++) { + icon->frames[i] = gdk_pixbuf_new_subpixbuf (pixbuf, c * w, r * h, w, h); + } + + g_object_unref (pixbuf); + + /* enable new animation */ + gpk_animated_icon_enable_animation (icon, TRUE); + + return TRUE; +} + +/** + * gpk_animated_icon_visible_notify_cb: + **/ +static void +gpk_animated_icon_visible_notify_cb (GObject *object, GParamSpec *param, GpkAnimatedIcon *icon) +{ + gboolean ret; + g_object_get (object, "visible", &ret, NULL); + if (!ret && icon->animation_id != 0) { + g_debug ("disabling animation as hidden"); + gpk_animated_icon_enable_animation (icon, FALSE); + } +} + +/** + * gpk_animated_icon_update: + **/ +static gboolean +gpk_animated_icon_update (GpkAnimatedIcon *icon) +{ + static guint rate_limit = 0; + + /* debug so we can catch polling */ + if (rate_limit++ % 20 == 0) + g_debug ("polling check"); + + /* have we loaded a file */ + if (icon->frames == NULL) { + g_warning ("no frames to process"); + icon->animation_id = 0; + return FALSE; + } + + /* set new */ + gtk_image_set_from_pixbuf (GTK_IMAGE (icon), icon->frames[icon->frame_counter]); + + /* advance counter, wrapping around */ + icon->frame_counter = (icon->frame_counter + 1) % icon->number_frames; + + return TRUE; +} + +/** + * gpk_animated_icon_set_frame_delay: + **/ +gboolean +gpk_animated_icon_set_frame_delay (GpkAnimatedIcon *icon, guint delay_ms) +{ + g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE); + + g_debug ("frame delay set to %ims", delay_ms); + icon->frame_delay = delay_ms; + + /* do we have to change a running icon? */ + if (icon->animation_id != 0) { + g_source_remove (icon->animation_id); + icon->animation_id = g_timeout_add (icon->frame_delay, (GSourceFunc) gpk_animated_icon_update, icon); + g_source_set_name_by_id (icon->animation_id, "[GpkAnimatedIcon] update from delay change"); + } + + return TRUE; +} + +/** + * gpk_animated_icon_enable_animation: + **/ +gboolean +gpk_animated_icon_enable_animation (GpkAnimatedIcon *icon, gboolean enabled) +{ + g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE); + + if (!enabled) { + if (icon->animation_id == 0) { + g_debug ("ignoring stop on stopped icon"); + return FALSE; + } + + g_source_remove (icon->animation_id); + icon->animation_id = 0; + return TRUE; + } + + /* don't double queue */ + if (icon->animation_id != 0) { + g_debug ("ignoring start on started icon"); + return FALSE; + } + + /* start */ + icon->frame_counter = 0; + icon->animation_id = g_timeout_add (icon->frame_delay, (GSourceFunc) gpk_animated_icon_update, icon); + g_source_set_name_by_id (icon->animation_id, "[GpkAnimatedIcon] start update"); + gpk_animated_icon_update (icon); + return TRUE; +} + +/** + * gpk_animated_icon_destroy: + * @object: The object to destroy + **/ +static void +gpk_animated_icon_destroy (GtkWidget *object) +{ + GpkAnimatedIcon *icon; + icon = GPK_ANIMATED_ICON (object); + + /* avoid going pop after unref when spinning */ + if (icon->animation_id != 0) { + g_source_remove (icon->animation_id); + } + g_free (icon->filename); + icon->filename = NULL; + gpk_animated_icon_free_pixbufs (icon); + + GTK_WIDGET_CLASS (parent_class)->destroy (object); +} + +static void +gpk_animated_icon_class_init (GpkAnimatedIconClass *class) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + widget_class->destroy = gpk_animated_icon_destroy; + parent_class = g_type_class_peek_parent (class); +} + +/** + * gpk_animated_icon_init: + **/ +static void +gpk_animated_icon_init (GpkAnimatedIcon *icon) +{ + g_return_if_fail (GPK_IS_ANIMATED_ICON (icon)); + icon->frames = NULL; + icon->filename = NULL; + icon->animation_id = 0; + icon->frame_counter = 0; + icon->number_frames = 0; + icon->frame_delay = 200; + + /* disable polling if we are hidden */ + g_signal_connect (GTK_WIDGET (icon), "notify::visible", G_CALLBACK (gpk_animated_icon_visible_notify_cb), icon); +} + +/** + * gpk_animated_icon_new: + **/ +GtkWidget * +gpk_animated_icon_new (void) +{ + return g_object_new (GPK_TYPE_ANIMATED_ICON, NULL); +} Index: gnome-packagekit-3.20.0/src/gpk-animated-icon.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-animated-icon.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef GPK_ANIMATED_ICON_H +#define GPK_ANIMATED_ICON_H + +#include <glib-object.h> +#include <gtk/gtk.h> + +#define GPK_TYPE_ANIMATED_ICON (gpk_animated_icon_get_type()) +#define GPK_ANIMATED_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIcon)) +#define GPK_ANIMATED_ICON_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIconClass)) +#define GPK_IS_ANIMATED_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GPK_TYPE_ANIMATED_ICON)) +#define GPK_IS_ANIMATED_ICON_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), GPK_TYPE_ANIMATED_ICON)) +#define GPK_ANIMATED_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIconClass)) + +G_BEGIN_DECLS + +typedef struct _GpkAnimatedIcon GpkAnimatedIcon; +typedef struct _GpkAnimatedIconClass GpkAnimatedIconClass; + +struct _GpkAnimatedIcon +{ + GtkImage parent; + gchar *filename; + guint animation_id; + guint frame_counter; + guint number_frames; + guint frame_delay; + GdkPixbuf **frames; +}; + +struct _GpkAnimatedIconClass +{ + GtkImageClass parent_class; +}; + +GType gpk_animated_icon_get_type (void); +GtkWidget *gpk_animated_icon_new (void); +gboolean gpk_animated_icon_set_filename_tile (GpkAnimatedIcon *icon, + GtkIconSize size, + const gchar *name); +gboolean gpk_animated_icon_set_icon_name (GpkAnimatedIcon *icon, + GtkIconSize size, + const gchar *name); +gboolean gpk_animated_icon_set_frame_delay (GpkAnimatedIcon *icon, + guint delay_ms); +gboolean gpk_animated_icon_enable_animation (GpkAnimatedIcon *icon, + gboolean enabled); + +G_END_DECLS + +#endif /* GPK_ANIMATED_ICON_H */ + Index: gnome-packagekit-3.20.0/src/gpk-application.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-application.c +++ gnome-packagekit-3.20.0/src/gpk-application.c @@ -21,6 +21,7 @@ #include "config.h" +#include <dbus/dbus-glib.h> #include <errno.h> #include <gdk/gdkkeysyms.h> #include <gdk/gdkx.h> @@ -42,6 +43,8 @@ #include "gpk-dialog.h" #include "gpk-enum.h" #include "gpk-error.h" +#include "gpk-gnome.h" +#include "gpk-helper-run.h" #include "gpk-task.h" #include "gpk-debug.h" @@ -505,7 +508,7 @@ out: static void gpk_application_menu_homepage_cb (GtkAction *action, GpkApplicationPrivate *priv) { - gtk_show_uri (NULL, priv->homepage_url, GDK_CURRENT_TIME, NULL); + gpk_gnome_open (priv->homepage_url); } /** @@ -3433,6 +3436,7 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); + dbus_g_thread_init (); gtk_init (&argc, &argv); context = g_option_context_new (NULL); Index: gnome-packagekit-3.20.0/src/gpk-common.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-common.c +++ gnome-packagekit-3.20.0/src/gpk-common.c @@ -49,6 +49,21 @@ /* static, so local to process */ static gboolean small_form_factor_mode = FALSE; +gchar ** +pk_package_array_to_strv (GPtrArray *array) +{ + PkPackage *item; + gchar **results; + guint i; + + results = g_new0 (gchar *, array->len+1); + for (i=0; i<array->len; i++) { + item = g_ptr_array_index (array, i); + results[i] = g_strdup (pk_package_get_id (item)); + } + return results; +} + /** * pk_strv_to_ptr_array: * @array: the gchar** array of strings @@ -320,6 +335,38 @@ out: } /** + * gpk_set_animated_icon_from_status: + **/ +gboolean +gpk_set_animated_icon_from_status (GpkAnimatedIcon *icon, PkStatusEnum status, GtkIconSize size) +{ + const gchar *name = NULL; + guint delay = 0; + + /* see if there is an animation */ + name = gpk_status_enum_to_animation (status); + + /* get the timing */ + if (g_str_has_prefix (name, "pk-action-")) + delay = 150; + else if (g_str_has_prefix (name, "process-working")) + delay = 50; + + /* animate or set static */ + if (delay != 0) { + gpk_animated_icon_set_frame_delay (icon, delay); + gpk_animated_icon_set_filename_tile (icon, size, name); + } else { + gpk_animated_icon_set_icon_name (icon, size, name); + } + + /* stop spinning */ + if (status == PK_STATUS_ENUM_FINISHED) + gpk_animated_icon_enable_animation (icon, FALSE); + return TRUE; +} + +/** * gpk_time_to_imprecise_string: * @time_secs: The time value to convert in seconds * Index: gnome-packagekit-3.20.0/src/gpk-common.h =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-common.h +++ gnome-packagekit-3.20.0/src/gpk-common.h @@ -26,6 +26,7 @@ #include <gtk/gtk.h> #include <packagekit-glib2/packagekit.h> +#include "gpk-animated-icon.h" #include "gpk-enum.h" G_BEGIN_DECLS @@ -69,6 +70,9 @@ gchar *gpk_time_to_localised_string (g gchar *gpk_time_to_imprecise_string (guint time_secs); gboolean gpk_check_privileged_user (const gchar *application_name, gboolean show_ui); +gboolean gpk_set_animated_icon_from_status (GpkAnimatedIcon *icon, + PkStatusEnum status, + GtkIconSize size); gchar *gpk_strv_join_locale (gchar **array); GtkEntryCompletion *gpk_package_entry_completion_new (void); gboolean gpk_window_set_size_request (GtkWindow *window, @@ -78,6 +82,7 @@ gboolean gpk_window_set_parent_xid (Gt guint32 xid); GPtrArray *pk_strv_to_ptr_array (gchar **array) G_GNUC_WARN_UNUSED_RESULT; +gchar **pk_package_array_to_strv (GPtrArray *array); G_END_DECLS Index: gnome-packagekit-3.20.0/src/gpk-dbus-service.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-dbus-service.c @@ -0,0 +1,184 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2007-2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <dbus/dbus-glib.h> +#include <gtk/gtk.h> +#include <locale.h> +#include <libnotify/notify.h> +#include <packagekit-glib2/packagekit.h> + +#include "gpk-common.h" +#include "gpk-dbus.h" +#include "gpk-debug.h" + +#include "org.freedesktop.PackageKit.h" + +static GMainLoop *loop = NULL; + +#define GPK_SESSION_IDLE_EXIT 60 /* seconds */ + +/** + * gpk_dbus_service_object_register: + * @connection: What we want to register to + * @object: The GObject we want to register + * + * Return value: success + **/ +static gboolean +gpk_dbus_service_object_register (DBusGConnection *connection, GObject *object) +{ + DBusGProxy *bus_proxy = NULL; + GError *error = NULL; + guint request_name_result; + gboolean ret; + + /* connect to the bus */ + bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); + + /* get our name */ + ret = dbus_g_proxy_call (bus_proxy, "RequestName", &error, + G_TYPE_STRING, PK_DBUS_SERVICE, + G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT | + DBUS_NAME_FLAG_REPLACE_EXISTING | + DBUS_NAME_FLAG_DO_NOT_QUEUE, + G_TYPE_INVALID, + G_TYPE_UINT, &request_name_result, + G_TYPE_INVALID); + if (!ret) { + /* abort as the D-Bus method failed */ + g_warning ("RequestName failed: %s", error->message); + g_error_free (error); + return FALSE; + } + + /* free the bus_proxy */ + g_object_unref (G_OBJECT (bus_proxy)); + + /* already running */ + if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + return FALSE; + + dbus_g_object_type_install_info (GPK_TYPE_DBUS, &dbus_glib_gpk_dbus_object_info); + dbus_g_error_domain_register (GPK_DBUS_ERROR, NULL, GPK_DBUS_TYPE_ERROR); + dbus_g_connection_register_g_object (connection, PK_DBUS_PATH, object); + + return TRUE; +} + +/** + * gpk_dbus_service_check_idle_cb: + **/ +static gboolean +gpk_dbus_service_check_idle_cb (GpkDbus *dbus) +{ + guint idle; + + /* get the idle time */ + idle = gpk_dbus_get_idle_time (dbus); + if (idle > GPK_SESSION_IDLE_EXIT) { + g_debug ("exiting loop as idle"); + g_main_loop_quit (loop); + return FALSE; + } + /* continue to poll */ + return TRUE; +} + +/** + * main: + **/ +int +main (int argc, char *argv[]) +{ + gboolean no_timed_exit = FALSE; + GpkDbus *dbus = NULL; + GOptionContext *context; + GError *error = NULL; + gboolean ret; + guint retval = 0; + DBusGConnection *connection; + guint timer_id = 0; + + const GOptionEntry options[] = { + { "no-timed-exit", '\0', 0, G_OPTION_ARG_NONE, &no_timed_exit, + _("Do not exit after the request has been processed"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + dbus_g_thread_init (); + notify_init (_("Software Install")); + + /* TRANSLATORS: program name, a session wide daemon to watch for updates and changing system state */ + g_set_application_name (_("Software Install")); + context = g_option_context_new (NULL); + g_option_context_set_summary (context, _("Session D-Bus service for PackageKit")); + g_option_context_add_main_entries (context, options, NULL); + g_option_context_add_group (context, gpk_debug_get_option_group ()); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + gtk_init (&argc, &argv); + + /* create new objects */ + dbus = gpk_dbus_new (); + loop = g_main_loop_new (NULL, FALSE); + + /* get the bus */ + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + retval = 1; + goto out; + } + + /* try to register */ + ret = gpk_dbus_service_object_register (connection, G_OBJECT (dbus)); + if (!ret) { + g_warning ("failed to replace running instance."); + retval = 1; + goto out; + } + + /* only timeout if we have specified iton the command line */ + if (!no_timed_exit) { + timer_id = g_timeout_add_seconds (5, (GSourceFunc) gpk_dbus_service_check_idle_cb, dbus); + g_source_set_name_by_id (timer_id, "[GpkDbusService] timed exit"); + } + + /* wait */ + g_main_loop_run (loop); +out: + g_main_loop_unref (loop); + g_object_unref (dbus); + return retval; +} Index: gnome-packagekit-3.20.0/src/gpk-dbus-task.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-dbus-task.c @@ -0,0 +1,3273 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <unistd.h> +#include <string.h> +#include <glib/gi18n.h> +#include <glib/gprintf.h> +#include <glib/gstdio.h> +#include <gio/gio.h> + +#include <fontconfig/fontconfig.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <libnotify/notify.h> +#include <packagekit-glib2/packagekit.h> + +#include "egg-string.h" + +#include "gpk-common.h" +#include "gpk-dbus.h" +#include "gpk-dbus-task.h" +#include "gpk-dialog.h" +#include "gpk-enum.h" +#include "gpk-error.h" +#include "gpk-gnome.h" +#include "gpk-helper-chooser.h" +#include "gpk-helper-run.h" +#include "gpk-language.h" +#include "gpk-modal-dialog.h" +#include "gpk-task.h" +#include "gpk-vendor.h" +#include "gpk-x11.h" + +static void gpk_dbus_task_finalize (GObject *object); +static void gpk_dbus_task_progress_cb (PkProgress *progress, PkProgressType type, GpkDbusTask *dtask); + +#define GPK_DBUS_TASK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskPrivate)) +#define GPK_DBUS_TASK_FINISHED_AUTOCLOSE_DELAY 10 /* seconds */ + +/** + * GpkDbusTaskPrivate: + * + * Private #GpkDbusTask data + **/ +struct _GpkDbusTaskPrivate +{ + GdkWindow *parent_window; + GSettings *settings; + PkTask *task; + PkControl *control; + PkExitEnum exit; + PkBitfield roles; + GpkLanguage *language; + GpkModalDialog *dialog; + GpkVendor *vendor; + gboolean show_confirm_search; + gboolean show_confirm_deps; + gboolean show_confirm_install; + gboolean show_progress; + gboolean show_finished; + gboolean show_warning; + guint timestamp; + gchar *parent_title; + gchar *parent_icon_name; + gchar *exec; + PkError *cached_error_code; + gint timeout; + GpkHelperRun *helper_run; + GpkHelperChooser *helper_chooser; + DBusGMethodInvocation *context; + gchar **package_ids; + gchar **files; + GCancellable *cancellable; + GpkDbusTaskFinishedCb finished_cb; + gpointer finished_userdata; +}; + +G_DEFINE_TYPE (GpkDbusTask, gpk_dbus_task, G_TYPE_OBJECT) + +/** + * gpk_dbus_task_set_interaction: + **/ +gboolean +gpk_dbus_task_set_interaction (GpkDbusTask *dtask, PkBitfield interact) +{ + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + + dtask->priv->show_confirm_search = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH); + dtask->priv->show_confirm_deps = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS); + dtask->priv->show_confirm_install = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL); + dtask->priv->show_progress = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_PROGRESS); + dtask->priv->show_finished = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_FINISHED); + dtask->priv->show_warning = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_WARNING); + + /* debug */ + g_debug ("confirm_search:%i, confirm_deps:%i, confirm_install:%i, progress:%i, finished:%i, warning:%i", + dtask->priv->show_confirm_search, dtask->priv->show_confirm_deps, + dtask->priv->show_confirm_install, dtask->priv->show_progress, + dtask->priv->show_finished, dtask->priv->show_warning); + + return TRUE; +} + +/** + * gpk_dbus_task_set_context: + **/ +gboolean +gpk_dbus_task_set_context (GpkDbusTask *dtask, DBusGMethodInvocation *context) +{ + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + g_return_val_if_fail (context != NULL, FALSE); + + dtask->priv->context = context; + return TRUE; +} + +/** + * gpk_dbus_task_set_xid: + **/ +gboolean +gpk_dbus_task_set_xid (GpkDbusTask *dtask, guint32 xid) +{ + GdkDisplay *display; + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + + display = gdk_display_get_default (); + dtask->priv->parent_window = gdk_x11_window_foreign_new_for_display (display, xid); + g_debug ("parent_window=%p", dtask->priv->parent_window); + gpk_modal_dialog_set_parent (dtask->priv->dialog, dtask->priv->parent_window); + return TRUE; +} + +/** + * gpk_dbus_task_set_timestamp: + **/ +gboolean +gpk_dbus_task_set_timestamp (GpkDbusTask *dtask, guint32 timestamp) +{ + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + dtask->priv->timestamp = timestamp; + return TRUE; +} + +static void gpk_dbus_task_install_package_ids (GpkDbusTask *dtask); + +/** + * gpk_dbus_task_dbus_return_error: + **/ +static void +gpk_dbus_task_dbus_return_error (GpkDbusTask *dtask, const GError *error) +{ + g_return_if_fail (error != NULL); + + /* already sent or never setup */ + if (dtask->priv->context == NULL) { + g_error ("context does not exist, cannot return: %s", error->message); + goto out; + } + + /* send error */ + g_debug ("sending async return error in response to %p: %s", dtask->priv->context, error->message); + dbus_g_method_return_error (dtask->priv->context, error); + + /* set context NULL just in case we try to repeat */ + dtask->priv->context = NULL; + + /* do the finish callback */ + if (dtask->priv->finished_cb) + dtask->priv->finished_cb (dtask, dtask->priv->finished_userdata); +out: + /* we can't touch dtask now, as it might have been unreffed in the finished callback */ + return; +} + +/** + * gpk_dbus_task_dbus_return_value: + **/ +static void +gpk_dbus_task_dbus_return_value (GpkDbusTask *dtask, gboolean ret) +{ + /* already sent or never setup */ + if (dtask->priv->context == NULL) { + g_error ("context does not exist, cannot return %i", ret); + goto out; + } + + /* send error */ + g_debug ("sending async return in response to %p: %i", dtask->priv->context, ret); + dbus_g_method_return (dtask->priv->context, ret); + + /* set context NULL just in case we try to repeat */ + dtask->priv->context = NULL; + + /* do the finish callback */ + if (dtask->priv->finished_cb) + dtask->priv->finished_cb (dtask, dtask->priv->finished_userdata); +out: + /* we can't touch dtask now, as it might have been unreffed in the finished callback */ + return; +} + +/** + * gpk_dbus_task_chooser_event_cb: + **/ +static void +gpk_dbus_task_chooser_event_cb (GpkHelperChooser *helper_chooser, GtkResponseType type, const gchar *package_id, GpkDbusTask *dtask) +{ + GError *error_dbus = NULL; + + /* selected nothing */ + if (type != GTK_RESPONSE_YES || package_id == NULL) { + + /* failed */ + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not choose anything to install"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + + if (dtask->priv->show_warning) { + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: we failed to install */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install software")); + /* TRANSLATORS: we didn't select any applications that were returned */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("No applications were chosen to be installed")); + gpk_modal_dialog_present (dtask->priv->dialog); + gpk_modal_dialog_run (dtask->priv->dialog); + } + goto out; + } + + /* install this specific package */ + dtask->priv->package_ids = pk_package_ids_from_id (package_id); + + /* install these packages with deps */ + gpk_dbus_task_install_package_ids (dtask); +out: + return; +} + +/** + * gpk_dbus_task_libnotify_cb: + **/ +static void +gpk_dbus_task_libnotify_cb (NotifyNotification *notification, gchar *action, gpointer data) +{ + GpkDbusTask *task = GPK_DBUS_TASK (data); + gchar *details; + + if (task->priv->cached_error_code == NULL) { + g_warning ("called show error with no error!"); + return; + } + if (g_strcmp0 (action, "show-error-details") == 0) { + details = g_markup_escape_text (pk_error_get_details (task->priv->cached_error_code), -1); + /* TRANSLATORS: detailed text about the error */ + gpk_error_dialog (_("Error details"), _("Package Manager error details"), details); + g_free (details); + } else { + g_warning ("unknown action id: %s", action); + } +} + +/** + * gpk_dbus_task_error_msg: + **/ +static void +gpk_dbus_task_error_msg (GpkDbusTask *dtask, const gchar *title, GError *error) +{ + GtkWindow *window; + /* TRANSLATORS: default fallback error -- this should never happen */ + const gchar *message = _("Unknown error. Please refer to the detailed report and report in your distribution bug tracker."); + const gchar *details = NULL; + + if (!dtask->priv->show_warning) + return; + + /* setup UI */ + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + + /* print a proper error if we have it */ + if (error != NULL) { + if (error->domain == GPK_DBUS_ERROR) { + message = gpk_error_enum_to_localised_message (error->code); + } + } + + /* it's a normal UI, not a backtrace so keep in the UI */ + if (details == NULL) { + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + gpk_modal_dialog_run (dtask->priv->dialog); + return; + } + + /* hide the main window */ + window = gpk_modal_dialog_get_window (dtask->priv->dialog); + gpk_error_dialog_modal_with_time (window, title, message, details, dtask->priv->timestamp); +} + +/** + * gpk_dbus_task_handle_error: + **/ +static void +gpk_dbus_task_handle_error (GpkDbusTask *dtask, PkError *error_code) +{ + gboolean ret; + GError *error = NULL; + const gchar *title; + const gchar *message; + NotifyNotification *notification; + GtkWidget *widget; + + /* ignore some errors */ + if (pk_error_get_code (error_code) == PK_ERROR_ENUM_NO_LICENSE_AGREEMENT || + pk_error_get_code (error_code) == PK_ERROR_ENUM_PROCESS_KILL || + pk_error_get_code (error_code) == PK_ERROR_ENUM_TRANSACTION_CANCELLED) { + g_warning ("ignoring %s", pk_error_enum_to_string (pk_error_get_code (error_code))); + } + + g_debug ("code was %s", pk_error_enum_to_string (pk_error_get_code (error_code))); + + /* use a modal dialog if showing progress, else use libnotify */ + title = gpk_error_enum_to_localised_text (pk_error_get_code (error_code)); + message = gpk_error_enum_to_localised_message (pk_error_get_code (error_code)); + if (dtask->priv->show_progress) { + widget = GTK_WIDGET (gpk_modal_dialog_get_window (dtask->priv->dialog)); + gpk_error_dialog_modal (GTK_WINDOW (widget), title, message, pk_error_get_details (error_code)); + return; + } + + /* save this globally */ + if (dtask->priv->cached_error_code != NULL) + g_object_unref (dtask->priv->cached_error_code); + dtask->priv->cached_error_code = g_object_ref (error_code); + + /* do the bubble */ + notification = notify_notification_new (title, message, NULL); + notify_notification_set_hint_string (notification, "desktop-entry", "gpk-application"); + notify_notification_set_timeout (notification, 15000); + notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); + notify_notification_add_action (notification, "show-error-details", + /* TRANSLATORS: button: show details about the error */ + _("Show details"), gpk_dbus_task_libnotify_cb, dtask, NULL); + ret = notify_notification_show (notification, &error); + if (!ret) { + g_warning ("error: %s", error->message); + g_error_free (error); + } +} + +/** + * gpk_dbus_task_get_code_from_gerror: + **/ +static gint +gpk_dbus_task_get_code_from_gerror (const GError *error) +{ + gint code = PK_ERROR_ENUM_INTERNAL_ERROR; + + /* already correct */ + if (error->domain == GPK_DBUS_ERROR) { + code = error->code; + goto out; + } + + /* not recognized */ + if (error->domain != PK_CLIENT_ERROR) { + g_warning ("Not a PkClientError error code"); + goto out; + } + + /* PkError codes */ + if (error->code > 0xff) { + code = error->code - 0xff; + goto out; + } + + /* map return codes to PkError codes */ + switch (error->code) { + case PK_CLIENT_ERROR_NO_TID: + case PK_CLIENT_ERROR_ALREADY_TID: + case PK_CLIENT_ERROR_ROLE_UNKNOWN: + case PK_CLIENT_ERROR_CANNOT_START_DAEMON: + case PK_CLIENT_ERROR_NOT_SUPPORTED: + code = PK_ERROR_ENUM_INTERNAL_ERROR; + break; + case PK_CLIENT_ERROR_INVALID_INPUT: + case PK_CLIENT_ERROR_INVALID_FILE: + case PK_CLIENT_ERROR_FAILED: + code = PK_ERROR_ENUM_UNKNOWN; + break; + case PK_CLIENT_ERROR_DECLINED_SIMULATION: + code = PK_ERROR_ENUM_TRANSACTION_CANCELLED; + break; + case PK_CLIENT_ERROR_FAILED_AUTH: + code = PK_ERROR_ENUM_NOT_AUTHORIZED; + break; + default: + break; + } +out: + return code; +} + +/** + * gpk_dbus_task_get_code_from_pkerror: + **/ +static gint +gpk_dbus_task_get_code_from_pkerror (PkError *error_code) +{ + gint code = PK_ERROR_ENUM_UNKNOWN; + + switch (pk_error_get_code (error_code)) { + case PK_ERROR_ENUM_TRANSACTION_CANCELLED: + code = PK_ERROR_ENUM_TRANSACTION_CANCELLED; + break; + default: + break; + } + return code; +} + +/** + * gpk_dbus_task_install_packages_cb: + **/ +static void +gpk_dbus_task_install_packages_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + PkError *error_code = NULL; + + /* get the results */ + results = pk_task_generic_finish (task, res, &error); + if (results == NULL) { + /* TRANSLATORS: error: failed to install, detailed error follows */ + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "%s", error->message); + gpk_dbus_task_error_msg (dtask, _("Failed to install software"), error_dbus); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + g_warning ("failed to install package: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "%s", pk_error_get_details (error_code)); + gpk_dbus_task_handle_error (dtask, error_code); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* we're done */ + gpk_dbus_task_dbus_return_value (dtask, TRUE); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_package_ids: + * @task: a valid #GpkDbusTask instance + **/ +static void +gpk_dbus_task_install_package_ids (GpkDbusTask *dtask) +{ + GtkWindow *window; + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING); + /* TRANSLATORS: title: installing packages */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Installing packages")); + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* ensure parent is set */ + window = gpk_modal_dialog_get_window (dtask->priv->dialog); + gpk_task_set_parent_window (GPK_TASK (dtask->priv->task), window); + + /* install async */ + pk_task_install_packages_async (dtask->priv->task, dtask->priv->package_ids, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_install_packages_cb, dtask); +} + +/** + * gpk_dbus_task_set_status: + **/ +static gboolean +gpk_dbus_task_set_status (GpkDbusTask *dtask, PkStatusEnum status) +{ + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + + /* do we force progress? */ + if (!dtask->priv->show_progress) { + if (status == PK_STATUS_ENUM_DOWNLOAD_REPOSITORY || + status == PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST || + status == PK_STATUS_ENUM_DOWNLOAD_FILELIST || + status == PK_STATUS_ENUM_DOWNLOAD_CHANGELOG || + status == PK_STATUS_ENUM_DOWNLOAD_GROUP || + status == PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO || + status == PK_STATUS_ENUM_REFRESH_CACHE) { + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, 0); + } + } + + /* ignore */ + if (!dtask->priv->show_progress) { + g_warning ("not showing progress"); + return FALSE; + } + + /* set icon */ + gpk_modal_dialog_set_image_status (dtask->priv->dialog, status); + + /* set label */ + gpk_modal_dialog_set_title (dtask->priv->dialog, gpk_status_enum_to_localised_text (status)); + + /* spin */ + if (status == PK_STATUS_ENUM_WAIT) + gpk_modal_dialog_set_percentage (dtask->priv->dialog, -1); + + /* do visual stuff when finished */ + if (status == PK_STATUS_ENUM_FINISHED) { + /* make insensitive */ + gpk_modal_dialog_set_allow_cancel (dtask->priv->dialog, FALSE); + + /* stop spinning */ + gpk_modal_dialog_set_percentage (dtask->priv->dialog, 100); + } + return TRUE; +} + +/** + * gpk_dbus_task_button_close_cb: + **/ +static void +gpk_dbus_task_button_close_cb (GtkWidget *widget, GpkDbusTask *dtask) +{ + /* close, don't abort */ + gpk_modal_dialog_close (dtask->priv->dialog); +} + +/** + * gpk_dbus_task_button_cancel_cb: + **/ +static void +gpk_dbus_task_button_cancel_cb (GtkWidget *widget, GpkDbusTask *dtask) +{ + /* we might have a transaction running */ + g_cancellable_cancel (dtask->priv->cancellable); +} + +/** + * gpk_dbus_task_install_files_cb: + **/ +static void +gpk_dbus_task_install_files_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + guint length; + const gchar *title; + PkError *error_code = NULL; + + /* get the results */ + results = pk_task_generic_finish (task, res, &error); + if (results == NULL) { + /* TRANSLATORS: error: failed to install, detailed error follows */ + length = g_strv_length (dtask->priv->files); + title = ngettext ("Failed to install file", "Failed to install files", length); + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "%s", error->message); + gpk_dbus_task_error_msg (dtask, title, error_dbus); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + g_warning ("failed to install file: %s, %s", + pk_error_enum_to_string (pk_error_get_code (error_code)), + pk_error_get_details (error_code)); + gpk_dbus_task_handle_error (dtask, error_code); + error_dbus = g_error_new (GPK_DBUS_ERROR, + gpk_dbus_task_get_code_from_pkerror (error_code), + "failed to install file: %s", + pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* we're done */ + gpk_dbus_task_dbus_return_value (dtask, TRUE); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_ptr_array_to_bullets: + * + * splits the strings up nicely + * + * Return value: a newly allocated string + **/ +static gchar * +gpk_dbus_task_ptr_array_to_bullets (GPtrArray *array, const gchar *prefix) +{ + GString *string; + guint i; + gchar *text; + + /* don't use a bullet for one item */ + if (array->len == 1) { + if (prefix != NULL) + return g_strdup_printf ("%s\n\n%s", prefix, (const gchar *) g_ptr_array_index (array, 0)); + else + return g_strdup (g_ptr_array_index (array, 0)); + } + + string = g_string_new (prefix); + if (prefix != NULL) + g_string_append (string, "\n\n"); + + /* prefix with bullet and suffix with newline */ + for (i=0; i<array->len; i++) { + text = (gchar *) g_ptr_array_index (array, i); + g_string_append_printf (string, "• %s\n", text); + } + + /* remove last \n */ + g_string_set_size (string, string->len - 1); + + text = g_string_free (string, FALSE); + return text; +} + +/** + * gpk_dbus_task_install_package_files_verify: + * + * Allow the user to confirm the action + * + * Return value: %TRUE if the method succeeded + **/ +static gboolean +gpk_dbus_task_install_package_files_verify (GpkDbusTask *dtask, GPtrArray *array, GError **error) +{ + GtkResponseType button; + const gchar *title; + gchar *message; + gboolean ret = TRUE; + + /* TRANSLATORS: title: confirm the user want's to install a local file */ + title = ngettext ("Do you want to install this file?", + "Do you want to install these files?", array->len); + message = gpk_dbus_task_ptr_array_to_bullets (array, NULL); + + /* show UI */ + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + /* TRANSLATORS: title: installing local files */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install")); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + g_free (message); + + /* did we click no or exit the window? */ + if (button != GTK_RESPONSE_OK) { + g_set_error_literal (error, GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "Aborted"); + ret = FALSE; + goto out; + } +out: + return ret; +} + +/** + * gpk_dbus_task_confirm_action: + * @task: a valid #GpkDbusTask instance + **/ +static gboolean +gpk_dbus_task_confirm_action (GpkDbusTask *dtask, const gchar *title, const gchar *message, const gchar *action) +{ + GtkResponseType button; + + /* check the user wanted to call this method */ + if (!dtask->priv->show_confirm_search) + return TRUE; + + /* setup UI */ + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0); + gpk_modal_dialog_set_action (dtask->priv->dialog, action); + + /* set icon */ + if (dtask->priv->parent_icon_name != NULL) + gpk_modal_dialog_set_image (dtask->priv->dialog, dtask->priv->parent_icon_name); + else + gpk_modal_dialog_set_image (dtask->priv->dialog, "emblem-system"); + + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + + /* close, we're going to fail the method */ + if (button != GTK_RESPONSE_OK) { + gpk_modal_dialog_close (dtask->priv->dialog); + return FALSE; + } + + return TRUE; +} + +/** + * gpk_dbus_task_progress_cb: + **/ +static void +gpk_dbus_task_progress_cb (PkProgress *progress, PkProgressType type, GpkDbusTask *dtask) +{ + gboolean allow_cancel; + gint percentage; + guint remaining_time; + PkStatusEnum status; + gchar *package_id = NULL; + gchar *text; + + /* optimise */ + if (!dtask->priv->show_progress) + goto out; + + g_object_get (progress, + "allow-cancel", &allow_cancel, + "percentage", &percentage, + "remaining-time", &remaining_time, + "status", &status, + "package-id", &package_id, + NULL); + + if (type == PK_PROGRESS_TYPE_PACKAGE_ID) { + g_debug ("_package"); + } else if (type == PK_PROGRESS_TYPE_PERCENTAGE) { + gpk_modal_dialog_set_percentage (dtask->priv->dialog, percentage); + } else if (type == PK_PROGRESS_TYPE_ALLOW_CANCEL) { + gpk_modal_dialog_set_allow_cancel (dtask->priv->dialog, allow_cancel); + } else if (type == PK_PROGRESS_TYPE_STATUS) { + gpk_dbus_task_set_status (dtask, status); + + if (status == PK_STATUS_ENUM_FINISHED) { + /* stop spinning */ + gpk_modal_dialog_set_percentage (dtask->priv->dialog, 100); + } + } else if (type == PK_PROGRESS_TYPE_REMAINING_TIME) { + gpk_modal_dialog_set_remaining (dtask->priv->dialog, remaining_time); + } else if (type == PK_PROGRESS_TYPE_PACKAGE_ID) { + text = gpk_package_id_format_twoline (NULL, package_id, NULL); //TODO: need summary + gpk_modal_dialog_set_message (dtask->priv->dialog, text); + g_free (text); + } +out: + g_free (package_id); +} + +/** + * gpk_dbus_task_is_installed_resolve_cb: + **/ +static void +gpk_dbus_task_is_installed_resolve_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + gboolean ret; + PkError *error_code = NULL; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_warning ("failed to resolve: %s", error->message); + g_error_free (error); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + g_warning ("failed to resolve: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + ret = (array->len > 0); + gpk_dbus_task_dbus_return_value (dtask, ret); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_is_installed: + **/ +void +gpk_dbus_task_is_installed (GpkDbusTask *dtask, const gchar *package_name, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gchar **package_names = NULL; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (package_name != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* get the package list for the installed packages */ + package_names = g_strsplit (package_name, "|", 1); + pk_client_resolve_async (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_names, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_is_installed_resolve_cb, dtask); + g_strfreev (package_names); +} + +/** + * gpk_dbus_task_search_file_search_file_cb: + **/ +static void +gpk_dbus_task_search_file_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + gchar **split = NULL; + PkPackage *item; + PkInfoEnum info; + gchar *package_id = NULL; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search file: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_warning ("failed to resolve: %s", error->message); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + g_warning ("failed to resolve: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search file: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + if (array->len == 0) { + g_warning ("no packages"); + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "failed to find any packages"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get first item */ + item = g_ptr_array_index (array, 0); + g_object_get (item, + "info", &info, + "package-id", &package_id, + NULL); + split = pk_package_id_split (package_id); + + /* send error */ + g_debug ("sending async return in response to %p", dtask->priv->context); + dbus_g_method_return (dtask->priv->context, (info == PK_INFO_ENUM_INSTALLED), split[PK_PACKAGE_ID_NAME]); + + /* set context NULL just in case we try to repeat */ + dtask->priv->context = NULL; +out: + g_free (package_id); + g_strfreev (split); + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_search_file: + **/ +void +gpk_dbus_task_search_file (GpkDbusTask *dtask, const gchar *search_file, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gchar **values = NULL; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (search_file != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* get the package list for the installed packages */ + g_debug ("package_name=%s", search_file); + values = g_strsplit (search_file, "&", -1); + pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_NEWEST), values, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_search_file_search_file_cb, dtask); + g_strfreev (values); +} + +/** + * gpk_dbus_task_install_package_files: + * @task: a valid #GpkDbusTask instance + * @file_rel: a file such as <literal>./hal-devel-0.10.0.rpm</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a file locally, and get the deps from the repositories. + * This is useful for double clicking on a .rpm or .deb file. + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_package_files (GpkDbusTask *dtask, gchar **files_rel, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + GError *error = NULL; + GError *error_dbus = NULL; + gboolean ret; + GPtrArray *array_basename; + GPtrArray *array; + guint len; + guint i; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (files_rel != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* only show the basenames */ + array = g_ptr_array_new_with_free_func (g_free); + array_basename = g_ptr_array_new_with_free_func (g_free); + for (i = 0; files_rel[i] != NULL; i++) { + g_ptr_array_add (array, g_strdup (files_rel[i])); + g_ptr_array_add (array_basename, g_path_get_basename (files_rel[i])); + } + + /* check the user wanted to call this method */ + if (dtask->priv->show_confirm_search) { + ret = gpk_dbus_task_install_package_files_verify (dtask, array_basename, &error); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to verify files: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + } + + /* check for deps */ + dtask->priv->files = pk_ptr_array_to_strv (array); + + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + len = g_strv_length (dtask->priv->files); + /* TRANSLATORS: title: installing a local file */ + gpk_modal_dialog_set_title (dtask->priv->dialog, ngettext ("Install local file", "Install local files", len)); + if (dtask->priv->show_progress) + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + + /* install async */ + pk_task_install_files_async (dtask->priv->task, dtask->priv->files, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_install_files_cb, dtask); + + /* wait for async reply */ +out: + g_ptr_array_unref (array); + g_ptr_array_unref (array_basename); +} + +/** + * gpk_dbus_task_install_package_names_resolve_cb: + **/ +static void +gpk_dbus_task_install_package_names_resolve_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + gchar *package_id = NULL; + gchar *title; + gchar *info_url; + PkPackage *item; + GtkResponseType button; + guint i; + gboolean already_installed = FALSE; + PkInfoEnum info; + gchar *package_id_tmp = NULL; + + /* get the results */ + results = pk_task_generic_finish (task, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* found nothing? */ + array = pk_results_get_package_array (results); + if (array->len == 0) { + if (!dtask->priv->show_warning) { + /* TRANSLATORS: couldn't resolve name to package */ + title = g_strdup_printf (_("Could not find packages")); + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + /* TRANSLATORS: message: could not find */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("The packages could not be found in any package source")); + /* TRANSLATORS: button: a link to the help file */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + g_free (title); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no package found"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* see what we've got already */ + for (i=0; i<array->len; i++) { + item = g_ptr_array_index (array, i); + g_object_get (item, + "info", &info, + "package-id", &package_id_tmp, + NULL); + if (info == PK_INFO_ENUM_INSTALLED) { + already_installed = TRUE; + } else if (info == PK_INFO_ENUM_AVAILABLE) { + g_debug ("package '%s' resolved", package_id_tmp); + package_id = g_strdup (package_id_tmp); + //TODO: we need to list these in a gpk-dbus_task-chooser + } + g_free (package_id_tmp); + } + + /* already installed? */ + if (already_installed) { + if (dtask->priv->show_warning) { + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_FINISHED, 0); + /* TRANSLATORS: title: package is already installed */ + gpk_modal_dialog_set_title (dtask->priv->dialog, + ngettext ("The package is already installed", + "The packages are already installed", + g_strv_length (dtask->priv->package_ids))); + /* TRANSLATORS: message: package is already installed */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("Nothing to do.")); + gpk_modal_dialog_present (dtask->priv->dialog); + gpk_modal_dialog_run (dtask->priv->dialog); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "package already found"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* got junk? */ + if (package_id == NULL) { + if (dtask->priv->show_warning) { + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: failed to install, shouldn't be shown */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install package")); + /* TRANSLATORS: the search gave us the wrong result. internal error. barf. */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("Incorrect response from search")); + gpk_modal_dialog_present (dtask->priv->dialog); + gpk_modal_dialog_run (dtask->priv->dialog); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "incorrect response from search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* convert to data */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + + /* install these packages with deps */ + gpk_dbus_task_install_package_ids (dtask); +out: + g_free (package_id); + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_package_names: + * @task: a valid #GpkDbusTask instance + * @package: a pakage name such as <literal>hal-info</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a package of the newest and most correct version. + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_package_names (GpkDbusTask *dtask, gchar **packages, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret; + GError *error_dbus = NULL; + gchar *message; + gchar *text; + guint len; + guint i; + GString *string; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (packages != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* optional */ + if (!dtask->priv->show_confirm_install) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + string = g_string_new (""); + len = g_strv_length (packages); + if (len == 0) { + gpk_dbus_task_dbus_return_value (dtask, TRUE); + goto out; + } + + /* don't use a bullet for one item */ + if (len == 1) { + g_string_append_printf (string, "%s\n", packages[0]); + } else { + for (i=0; i<len; i++) + g_string_append_printf (string, "• %s\n", packages[i]); + } + /* display messagebox */ + text = g_string_free (string, FALSE); + + /* check user wanted operation */ + message = g_strdup_printf ("%s\n\n%s\n%s", + /* TRANSLATORS: a program needs a package, for instance openoffice-clipart */ + ngettext ("An additional package is required:", "Additional packages are required:", len), + text, + /* TRANSLATORS: ask the user if it's okay to search */ + ngettext ("Do you want to search for and install this package now?", "Do you want to search for and install these packages now?", len)); + g_free (text); + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + /* TRANSLATORS: string is a program name, e.g. "Movie Player" */ + text = g_strdup_printf (ngettext ("%s wants to install a package", "%s wants to install packages", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something */ + text = g_strdup (ngettext ("A program wants to install a package", "A program wants to install packages", len)); + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Install")); + g_free (text); + g_free (message); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + /* TRANSLATORS: title, searching */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for packages")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* find out if we can find a package */ + pk_client_resolve_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), packages, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_install_package_names_resolve_cb, dtask); + + /* wait for async reply */ +out: + return; +} + +/** + * gpk_dbus_task_install_provide_files_search_file_cb: + **/ +static void +gpk_dbus_task_install_provide_files_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + gchar *info_url; + PkPackage *item; + GtkResponseType button; + guint i; + gboolean already_installed = FALSE; + gchar *text; + gchar **split; + PkInfoEnum info; + gchar *package_id = NULL; + gchar *package_id_tmp = NULL; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: failed to fild the package for thefile */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find package")); + /* TRANSLATORS: nothing found */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("The file could not be found in any packages")); + /* TRANSLATORS: button: show the user a button to get more help finding stuff */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no files found"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* see what we've got already */ + for (i=0; i<array->len; i++) { + item = g_ptr_array_index (array, i); + g_object_get (item, + "info", &info, + "package-id", &package_id_tmp, + NULL); + if (info == PK_INFO_ENUM_INSTALLED) { + already_installed = TRUE; + package_id = g_strdup (package_id_tmp); + } else if (info == PK_INFO_ENUM_AVAILABLE) { + g_debug ("package '%s' resolved to:", package_id_tmp); + package_id = g_strdup (package_id_tmp); + } + g_free (package_id_tmp); + } + + /* already installed? */ + if (already_installed) { + if (dtask->priv->show_warning) { + split = pk_package_id_split (package_id); + /* TRANSLATORS: we've already got a package that provides this file */ + text = g_strdup_printf (_("The %s package already provides this file"), split[PK_PACKAGE_ID_NAME]); + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: title */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install file")); + gpk_modal_dialog_set_message (dtask->priv->dialog, text); + gpk_modal_dialog_present (dtask->priv->dialog); + gpk_modal_dialog_run (dtask->priv->dialog); + g_free (text); + g_strfreev (split); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "already provided"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* convert to data */ + dtask->priv->package_ids = pk_package_ids_from_id (package_id); + + /* install these packages with deps */ + gpk_dbus_task_install_package_ids (dtask); +out: + g_free (package_id); + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_provide_files: + * @task: a valid #GpkDbusTask instance + * @full_path: a file path name such as <literal>/usr/sbin/packagekitd</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a package which provides a file on the system. + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_provide_files (GpkDbusTask *dtask, gchar **full_paths, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret; + GError *error_dbus = NULL; + guint len; + guint i; + gchar *text; + gchar *message; + GString *string; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (full_paths != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + string = g_string_new (""); + len = g_strv_length (full_paths); + + /* don't use a bullet for one item */ + if (len == 1) { + g_string_append_printf (string, "%s\n", full_paths[0]); + } else { + for (i=0; i<len; i++) + g_string_append_printf (string, "• %s\n", full_paths[i]); + } + /* display messagebox */ + text = g_string_free (string, FALSE); + + /* check user wanted operation */ + message = g_strdup_printf ("%s\n\n%s\n\n%s", + /* TRANSLATORS: a program wants to install a file, e.g. /lib/moo.so */ + ngettext ("The following file is required:", "The following files are required:", len), + text, + /* TRANSLATORS: confirm with the user */ + ngettext ("Do you want to search for this file now?", "Do you want to search for these files now?", len)); + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + /* TRANSLATORS: string is a program name, e.g. "Movie Player" */ + text = g_strdup_printf (ngettext ("%s wants to install a file", "%s wants to install files", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something */ + text = g_strdup (ngettext ("A program wants to install a file", "A program wants to install files", len)); + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Install")); + g_free (text); + g_free (message); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + /* TRANSLATORS: searching for the package that provides the file */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* do search */ + pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), full_paths, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_install_provide_files_search_file_cb, dtask); + + /* wait for async reply */ +out: + return; +} + +/** + * gpk_dbus_task_install_gstreamer_resources_confirm: + **/ +static gboolean +gpk_dbus_task_install_gstreamer_resources_confirm (GpkDbusTask *dtask, gchar **codec_names) +{ + guint i; + guint len; + const gchar *text; + gchar **parts; + gboolean ret; + GString *string; + gchar *title; + gchar *message; + gboolean is_decoder = FALSE; + gboolean is_encoder = FALSE; + + len = g_strv_length (codec_names); + + /* find out what type of request this is */ + for (i=0; i<len; i++) { + parts = g_strsplit (codec_names[i], "|", 2); + if (g_strstr_len (parts[1], -1, "(decoder") != NULL) + is_decoder = TRUE; + if (g_strstr_len (parts[1], -1, "(encoder") != NULL) + is_encoder = TRUE; + g_strfreev (parts); + } + + /* TRANSLATORS: we are listing the plugins in a box */ + text = ngettext ("The following plugin is required:", "The following plugins are required:", len); + string = g_string_new (""); + g_string_append_printf (string, "%s\n\n", text); + + /* don't use a bullet for one item */ + if (len == 1) { + parts = g_strsplit (codec_names[0], "|", 2); + g_string_append_printf (string, "%s\n", parts[0]); + g_strfreev (parts); + } else { + for (i=0; i<len; i++) { + parts = g_strsplit (codec_names[i], "|", 2); + g_string_append_printf (string, "• %s\n", parts[0]); + g_strfreev (parts); + } + } + + /* TRANSLATORS: ask for confirmation */ + message = ngettext ("Do you want to search for this now?", "Do you want to search for these now?", len); + g_string_append_printf (string, "\n%s\n", message); + + /* remove last \n */ + g_string_set_size (string, string->len - 1); + + /* display messagebox */ + message = g_string_free (string, FALSE); + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + if (is_decoder && !is_encoder) { + /* TRANSLATORS: a program wants to decode something (unknown) -- string is a program name, e.g. "Movie Player" */ + title = g_strdup_printf (ngettext ("%s requires an additional plugin to decode this file", + "%s requires additional plugins to decode this file", len), dtask->priv->parent_title); + } else if (!is_decoder && is_encoder) { + /* TRANSLATORS: a program wants to encode something (unknown) -- string is a program name, e.g. "Movie Player" */ + title = g_strdup_printf (ngettext ("%s requires an additional plugin to encode this file", + "%s requires additional plugins to encode this file", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a program wants to do something (unknown) -- string is a program name, e.g. "Movie Player" */ + title = g_strdup_printf (ngettext ("%s requires an additional plugin for this operation", + "%s requires additional plugins for this operation", len), dtask->priv->parent_title); + } + } else { + if (is_decoder && !is_encoder) { + /* TRANSLATORS: a random program which we can't get the name wants to decode something */ + title = g_strdup (ngettext ("A program requires an additional plugin to decode this file", + "A program requires additional plugins to decode this file", len)); + } else if (!is_decoder && is_encoder) { + /* TRANSLATORS: a random program which we can't get the name wants to encode something */ + title = g_strdup (ngettext ("A program requires an additional plugin to encode this file", + "A program requires additional plugins to encode this file", len)); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something (unknown) */ + title = g_strdup (ngettext ("A program requires an additional plugin for this operation", + "A program requires additional plugins for this operation", len)); + } + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, title, message, _("Search")); + g_free (title); + g_free (message); + + return ret; +} + +/** + * gpk_dbus_task_codec_what_provides_cb: + **/ +static void +gpk_dbus_task_codec_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + GtkResponseType button; + gchar *info_url; + const gchar *title; + const gchar *message; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_CODEC); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: failed to search for codec */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to search for plugin")); + /* TRANSLATORS: no package sources have the wanted codec */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("Could not find plugin in any configured package source")); + + /* TRANSLATORS: button text */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find codec"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_install) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks2; + } + + title = ngettext ("Install the following plugin", "Install the following plugins", array->len); + message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len); + + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST); + gpk_modal_dialog_set_package_list (dtask->priv->dialog, array); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information"); + /* TRANSLATORS: button: install codecs */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install")); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + + /* close, we're going to fail the method */ + if (button != GTK_RESPONSE_OK) { + gpk_modal_dialog_close (dtask->priv->dialog); + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks2: + /* install with deps */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + gpk_dbus_task_install_package_ids (dtask); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_gstreamer_resources: + * @task: a valid #GpkDbusTask instance + * @codecs: a codec_type such as <literal>application/text</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a application to handle a gstreamer request + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_gstreamer_resources (GpkDbusTask *dtask, gchar **codec_names, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret = TRUE; + GError *error_dbus = NULL; + gchar **parts = NULL; + gchar *message = NULL; + GPtrArray *array_title = NULL; + GPtrArray *array_search = NULL; + gchar **search = NULL; + gchar **title = NULL; + gchar *title_str = NULL; + guint i; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (codec_names != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* check it's not session wide banned */ + ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_CODEC_HELPER); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_CODEC_HELPER); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + /* confirm */ + ret = gpk_dbus_task_install_gstreamer_resources_confirm (dtask, codec_names); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING); + /* TRANSLATORS: search for codec */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for plugins")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* setup the UI */ + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* get the request */ + array_title = g_ptr_array_new_with_free_func (g_free); + array_search = g_ptr_array_new_with_free_func (g_free); + for (i=0; codec_names[i] != NULL; i++) { + parts = g_strsplit (codec_names[i], "|", 2); + g_ptr_array_add (array_title, g_strdup (parts[0])); + g_ptr_array_add (array_search, g_strdup (parts[1])); + g_strfreev (parts); + } + + /* TRANSLATORS: title, searching for codecs */ + title = pk_ptr_array_to_strv (array_title); + title_str = g_strjoinv (", ", title); + message = g_strdup_printf (_("Searching for plugin: %s"), title_str); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + + /* get codec packages */ + search = pk_ptr_array_to_strv (array_search); + pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), +#if PK_CHECK_VERSION(0,9,0) + search, NULL, +#else + PK_PROVIDES_ENUM_CODEC, search, NULL, +#endif + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_codec_what_provides_cb, dtask); +out: + if (array_title != NULL) + g_ptr_array_unref (array_title); + if (array_search != NULL) + g_ptr_array_unref (array_search); + g_strfreev (search); + g_strfreev (title); + g_free (message); + g_free (title_str); +} + +/** + * gpk_dbus_task_mime_what_provides_cb: + **/ +static void +gpk_dbus_task_mime_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + gchar *info_url; + GtkResponseType button; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + /* TRANSLATORS: we failed to find the package, this shouldn't happen */ + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search for provides: %s", error->message); + gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), error_dbus); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search for provides: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_MIME); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: title */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find software")); + /* TRANSLATORS: nothing found in the package sources that helps */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("No new applications can be found to handle this type of file")); + /* TRANSLATORS: button: show the user a button to get more help finding stuff */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "nothing was found to handle mime type"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* populate a chooser and wait for response */ + gpk_helper_chooser_show (dtask->priv->helper_chooser, array); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_mime_types: + * @task: a valid #GpkDbusTask instance + * @mime_type: a mime_type such as <literal>application/text</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a application to handle a mime type + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_mime_types (GpkDbusTask *dtask, gchar **mime_types, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret; + GError *error_dbus = NULL; + guint len; + gchar *message = NULL; + gchar *text = NULL; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (mime_types != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* check it's not session wide banned */ + ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_MIME_TYPE_HELPER); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_MIME_TYPE_HELPER); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + /* make sure the user wants to do action */ + message = g_strdup_printf ("%s\n\n%s\n\n%s", + /* TRANSLATORS: message: mime type opener required */ + _("An additional program is required to open this type of file:"), + mime_types[0], + /* TRANSLATORS: message: confirm with the user */ + _("Do you want to search for a program to open this file type now?")); + + /* hardcode for now as we only support one mime type at a time */ + len = 1; + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + /* TRANSLATORS: string is a program name, e.g. "Movie Player" */ + text = g_strdup_printf (ngettext ("%s requires a new mime type", "%s requires new mime types", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something */ + text = g_strdup (ngettext ("A program requires a new mime type", "A program requires new mime types", len)); + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Search")); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + /* TRANSLATORS: title: searching for mime type handlers */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file handlers")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* setup the UI */ + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* action */ + pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), +#if PK_CHECK_VERSION(0,9,0) + mime_types, NULL, +#else + PK_PROVIDES_ENUM_MIMETYPE, mime_types, NULL, +#endif + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_mime_what_provides_cb, dtask); + /* wait for async reply */ +out: + g_free (text); + g_free (message); +} + +/** + * gpk_dbus_task_font_tag_to_lang: + **/ +gchar * +gpk_dbus_task_font_tag_to_lang (const gchar *tag) +{ + gchar *lang = NULL; +#if 0 + *** We do not yet enable this code due to a few bugs in fontconfig *** + http://bugs.freedesktop.org/show_bug.cgi?id=18846 and + http://bugs.freedesktop.org/show_bug.cgi?id=18847 + + FcPattern *pat = NULL; + FcChar8 *fclang; + FcResult res; + + /* parse the tag */ + pat = FcNameParse ((FcChar8 *) tag); + if (pat == NULL) { + g_warning ("cannot parse: '%s'", tag); + goto out; + } + FcPatternPrint (pat); + res = FcPatternGetString (pat, FC_LANG, 0, &fclang); + if (res != FcResultMatch) { + g_warning ("failed to get string for: '%s': %i", tag, res); + goto out; + } + lang = g_strdup ((gchar *) fclang); +out: + if (pat != NULL) + FcPatternDestroy (pat); +#else + guint len; + + /* verify we have enough to remove prefix */ + len = strlen (tag); + if (len < 7) + goto out; + /* this is a bodge */ + lang = g_strdup (&tag[6]); +out: +#endif + return lang; +} + +/** + * gpk_dbus_task_font_tag_to_localised_name: + **/ +gchar * +gpk_dbus_task_font_tag_to_localised_name (GpkDbusTask *dtask, const gchar *tag) +{ + gchar *lang; + gchar *language = NULL; + gchar *name; + + /* use fontconfig to get the language code */ + lang = gpk_dbus_task_font_tag_to_lang (tag); + if (lang == NULL) { + /* TRANSLATORS: we could not parse the ISO639 code from the fontconfig tag name */ + name = g_strdup_printf ("%s: %s", _("Language tag not parsed"), tag); + goto out; + } + + /* convert to localisable name */ + language = gpk_language_iso639_to_language (dtask->priv->language, lang); + if (language == NULL) { + /* TRANSLATORS: we could not find en_US string for ISO639 code */ + name = g_strdup_printf ("%s: %s", _("Language code not matched"), lang); + goto out; + } + + /* get translation, or return untranslated string */ + name = g_strdup (dgettext("iso_639", language)); + if (name == NULL) + name = g_strdup (language); +out: + g_free (lang); + g_free (language); + return name; +} + +/** + * gpk_dbus_task_fontconfig_what_provides_cb: + **/ +static void +gpk_dbus_task_fontconfig_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + gchar *title; + gchar *info_url; + GtkResponseType button; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + /* TRANSLATORS: we failed to find the package, this shouldn't happen */ + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search for provides: %s", error->message); +// gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), error_dbus); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + /* TRANSLATORS: we failed to find the package, this shouldn't happen */ +// gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), pk_error_get_details (error_code)); + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search for provides: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_FONT); + /* TRANSLATORS: title: cannot find in sources */ + title = ngettext ("Failed to find font", "Failed to find fonts", array->len); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + /* TRANSLATORS: message: tell the user we suck */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("No new fonts can be found for this document")); + /* TRANSLATORS: button: show the user a button to get more help finding stuff */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find font"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_install) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + /* TRANSLATORS: title: show a list of fonts */ + title = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len); + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST); + gpk_modal_dialog_set_package_list (dtask->priv->dialog, array); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, title); + gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information"); + /* TRANSLATORS: button: install a font */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install")); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + + /* close, we're going to fail the method */ + if (button != GTK_RESPONSE_OK) { + gpk_modal_dialog_close (dtask->priv->dialog); + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + /* convert to list of package id's */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + gpk_dbus_task_install_package_ids (dtask); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_check_exec_ignored: + * + * Returns %FALSE if the executed program is in the ignored list. + **/ +static gboolean +gpk_dbus_task_install_check_exec_ignored (GpkDbusTask *dtask) +{ + gchar *ignored_str; + gchar **ignored = NULL; + gboolean ret = TRUE; + guint i; + + /* check it's not session wide banned */ + ignored_str = g_settings_get_string (dtask->priv->settings, GPK_SETTINGS_IGNORED_DBUS_REQUESTS); + if (ignored_str == NULL) + goto out; + + /* check each one */ + ignored = g_strsplit (ignored_str, ",", -1); + for (i=0; ignored[i] != NULL; i++) { + if (g_strcmp0 (dtask->priv->exec, ignored[i]) == 0) { + ret = FALSE; + break; + } + } +out: + g_free (ignored_str); + g_strfreev (ignored); + return ret; +} + +/** + * gpk_dbus_task_install_fontconfig_resources: + * @task: a valid #GpkDbusTask instance + * @fonts: font description such as <literal>lang:fr</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a application to handle a mime type + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *dtask, gchar **fonts, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret; + GPtrArray *array = NULL; +// GtkResponseType button; +// gchar *info_url; + GError *error_dbus = NULL; + guint i; + guint len; + guint size; + gchar *text; + gchar *message; + const gchar *title; + const gchar *title_part; + GString *string; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (fonts != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* if this program banned? */ + ret = gpk_dbus_task_install_check_exec_ignored (dtask); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "skipping ignored program: %s", dtask->priv->exec); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get number of fonts to install */ + len = g_strv_length (fonts); + + /* check it's not session wide banned */ + ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_FONT_HELPER); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_FONT_HELPER); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + /* check we got valid data */ + for (i=0; i<len; i++) { + /* correct prefix */ + if (!g_str_has_prefix (fonts[i], ":lang=")) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "not recognized prefix: '%s'", fonts[i]); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + /* no lang code */ + size = strlen (fonts[i]); + if (size < 7 || size > 20) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "lang tag malformed: '%s'", fonts[i]); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + } + + string = g_string_new (""); + + /* don't use a bullet for one item */ + if (len == 1) { + text = gpk_dbus_task_font_tag_to_localised_name (dtask, fonts[0]); + g_string_append_printf (string, "%s\n", text); + g_free (text); + } else { + for (i=0; i<len; i++) { + text = gpk_dbus_task_font_tag_to_localised_name (dtask, fonts[i]); + g_string_append_printf (string, "• %s\n", text); + g_free (text); + } + } + /* display messagebox */ + text = g_string_free (string, FALSE); + + /* TRANSLATORS: we need to download a new font package to display a document */ + title = ngettext ("An additional font is required to view this document correctly.", + "Additional fonts are required to view this document correctly.", len); + + /* TRANSLATORS: we need to download a new font package to display a document */ + title_part = ngettext ("Do you want to search for a suitable package now?", + "Do you want to search for suitable packages now?", len); + + /* check user wanted operation */ + message = g_strdup_printf ("%s\n\n%s\n%s", title, text, title_part); + g_free (text); + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + /* TRANSLATORS: string is a program name, e.g. "Movie Player" */ + text = g_strdup_printf (ngettext ("%s wants to install a font", "%s wants to install fonts", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something */ + text = g_strdup (ngettext ("A program wants to install a font", "A program wants to install fonts", len)); + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Search")); + g_free (text); + g_free (message); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + /* TRANSLATORS: title to show when searching for font files */ + title = ngettext ("Searching for font", "Searching for fonts", len); + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* setup the UI */ + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* do each one */ + pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), +#if PK_CHECK_VERSION(0,9,0) + fonts, NULL, +#else + PK_PROVIDES_ENUM_FONT, fonts, NULL, +#endif + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_fontconfig_what_provides_cb, dtask); +out: + if (array != NULL) + g_ptr_array_unref (array); +} + +/** + * gpk_dbus_task_install_plasma_resources_confirm: + **/ +static gboolean +gpk_dbus_task_install_plasma_resources_confirm (GpkDbusTask *dtask, gchar **service_names) +{ + guint i; + guint len; + const gchar *text; + gboolean ret; + GString *string; + gchar *title; + gchar *message; + + len = g_strv_length (service_names); + + /* TRANSLATORS: we are listing the services in a box */ + text = ngettext ("The following service is required:", "The following services are required:", len); + string = g_string_new (""); + g_string_append_printf (string, "%s\n\n", text); + + /* don't use a bullet for one item */ + if (len == 1) + g_string_append_printf (string, "%s\n", service_names[0]); + else + for (i=0; i<len; i++) + g_string_append_printf (string, "• %s\n", service_names[i]); + + /* TRANSLATORS: ask for confirmation */ + message = ngettext ("Do you want to search for this now?", "Do you want to search for these now?", len); + g_string_append_printf (string, "\n%s\n", message); + + /* remove last \n */ + g_string_set_size (string, string->len - 1); + + /* display messagebox */ + message = g_string_free (string, FALSE); + title = g_strdup (ngettext ("Plasma requires an additional service for this operation", + "Plasma requires additional services for this operation", len)); + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, title, message, _("Search")); + g_free (title); + g_free (message); + + return ret; +} + +/** + * gpk_dbus_task_plasma_service_what_provides_cb: + **/ +static void +gpk_dbus_task_plasma_service_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + GtkResponseType button; + gchar *info_url; + const gchar *title; + const gchar *message; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT); + /* only show the "more info" button if there is a valid link */ + if (info_url != NULL) + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION); + else + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to search for Plasma service")); + /* TRANSLATORS: no package sources have the wanted Plasma service */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("Could not find service in any configured package source")); + + /* TRANSLATORS: button text */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information")); + gpk_modal_dialog_present (dtask->priv->dialog); + button = gpk_modal_dialog_run (dtask->priv->dialog); + if (button == GTK_RESPONSE_OK) + gpk_gnome_open (info_url); + g_free (info_url); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find Plasma service"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_install) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks2; + } + + title = ngettext ("Install the following plugin", "Install the following plugins", array->len); + message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len); + + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST); + gpk_modal_dialog_set_package_list (dtask->priv->dialog, array); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information"); + /* TRANSLATORS: button: install Plasma services */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install")); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + + /* close, we're going to fail the method */ + if (button != GTK_RESPONSE_OK) { + gpk_modal_dialog_close (dtask->priv->dialog); + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks2: + /* install with deps */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + gpk_dbus_task_install_package_ids (dtask); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_plasma_resources: + * @task: a valid #GpkDbusTask instance + * @service_names: a service type such as <literal>dataengine-weather</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a service to handle a Plasma request + * + * Return value: %TRUE if the method succeeded + **/ +static void +gpk_dbus_task_install_plasma_resources (GpkDbusTask *dtask, gchar **service_names, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret = TRUE; + GError *error_dbus = NULL; + gchar *message = NULL; + GPtrArray *array_title = NULL; + GPtrArray *array_search = NULL; + gchar **search = NULL; + gchar **title = NULL; + gchar *title_str = NULL; + guint i; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (service_names != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + /* confirm */ + ret = gpk_dbus_task_install_plasma_resources_confirm (dtask, service_names); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING); + /* TRANSLATORS: search for Plasma services */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for services")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* setup the UI */ + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* get the request */ + array_title = g_ptr_array_new_with_free_func (g_free); + array_search = g_ptr_array_new_with_free_func (g_free); + for (i=0; service_names[i] != NULL; i++) { + g_ptr_array_add (array_title, g_strdup (service_names[i])); + g_ptr_array_add (array_search, g_strdup (service_names[i])); + } + + /* TRANSLATORS: title, searching for Plasma services */ + title = pk_ptr_array_to_strv (array_title); + title_str = g_strjoinv (", ", title); + message = g_strdup_printf (_("Searching for service: %s"), title_str); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + + /* get service packages */ + search = pk_ptr_array_to_strv (array_search); + pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), +#if PK_CHECK_VERSION(0,9,0) + search, NULL, +#else + PK_PROVIDES_ENUM_PLASMA_SERVICE, search, NULL, +#endif + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_plasma_service_what_provides_cb, dtask); +out: + if (array_title != NULL) + g_ptr_array_unref (array_title); + if (array_search != NULL) + g_ptr_array_unref (array_search); + g_strfreev (search); + g_strfreev (title); + g_free (message); + g_free (title_str); +} + +/** + * gpk_dbus_task_install_resources: + * @task: a valid #GpkDbusTask instance + * @type: type of the resource + * @resources: a list of resources + * @error: a %GError to put the error code and message in, or %NULL + * + * Install a resource of the given type + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_resources (GpkDbusTask *dtask, gchar **resources, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gpk_dbus_task_install_plasma_resources (dtask, resources, finished_cb, userdata); +} + +/** + * gpk_dbus_task_remove_packages_cb: + **/ +static void +gpk_dbus_task_remove_packages_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + PkError *error_code = NULL; + + /* get the results */ + results = pk_task_generic_finish (task, res, &error); + if (results == NULL) { + /* TRANSLATORS: error: failed to remove, detailed error follows */ + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to remove package: %s", error->message); + gpk_dbus_task_error_msg (dtask, _("Failed to remove package"), error_dbus); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to remove package: %s", pk_error_get_details (error_code)); + gpk_dbus_task_handle_error (dtask, error_code); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* we're done */ + gpk_dbus_task_dbus_return_value (dtask, TRUE); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_printer_driver_what_provides_cb: + **/ +static void +gpk_dbus_task_printer_driver_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + GtkResponseType button; + const gchar *title; + const gchar *message; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? No problem*/ + if (array->len == 0) { + gpk_modal_dialog_close (dtask->priv->dialog); + gpk_dbus_task_dbus_return_value (dtask, FALSE); + goto out; + } + + /* optional */ + if (!dtask->priv->show_confirm_install) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks2; + } + + title = ngettext ("Install the following driver", "Install the following drivers", array->len); + message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len); + + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST); + gpk_modal_dialog_set_package_list (dtask->priv->dialog, array); + gpk_modal_dialog_set_title (dtask->priv->dialog, title); + gpk_modal_dialog_set_message (dtask->priv->dialog, message); + gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information"); + /* TRANSLATORS: button: install printer drivers */ + gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install")); + gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp); + button = gpk_modal_dialog_run (dtask->priv->dialog); + + /* close, we're going to fail the method */ + if (button != GTK_RESPONSE_OK) { + gpk_modal_dialog_close (dtask->priv->dialog); + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks2: + /* install with deps */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + gpk_dbus_task_install_package_ids (dtask); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_install_printer_drivers: + * @task: a valid #GpkDbusTask instance + * @device_ids: list of Device IDs such as <literal>MFG:Foo Inc;MDL:Bar 3000;</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Install printer drivers for a given set of models. + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_install_printer_drivers (GpkDbusTask *dtask, gchar **device_ids, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + guint i, j; + guint len; + guint n_tags; + guint n_fields; + gchar **fields; + gchar *mfg; + gchar *mdl; + gchar *tag; + gchar **tags; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (device_ids != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + gpk_modal_dialog_setup (dtask->priv->dialog, + GPK_MODAL_DIALOG_PAGE_PROGRESS, + GPK_MODAL_DIALOG_PACKAGE_PADDING); + gpk_modal_dialog_set_title (dtask->priv->dialog, + _("Searching for packages")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, + PK_STATUS_ENUM_WAIT); + + /* setup the UI */ + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + len = g_strv_length (device_ids); + if (len > 1) + /* hardcode for now as we only support one at a time */ + len = 1; + + /* make a list of provides tags */ + tags = g_new0 (gchar *, len); + n_tags = 0; + for (i=0; i<len; i++) { + gchar *p, *ltag; + fields = g_strsplit (device_ids[i], ";", 0); + n_fields = g_strv_length (fields); + mfg = mdl = NULL; + for (j=0; j<n_fields && (!mfg || !mdl); j++) { + if (g_str_has_prefix (fields[j], "MFG:")) + mfg = g_strdup (fields[j] + 4); + else if (g_str_has_prefix (fields[j], "MDL:")) + mdl = g_strdup (fields[j] + 4); + } + g_strfreev (fields); + + if (!mfg || !mdl) { + g_warning("invalid line '%s', missing field", + device_ids[i]); + continue; + } + + tag = g_strconcat (mfg, ";", mdl, ";", NULL); + ltag = g_ascii_strdown (tag, -1); + g_free (tag); + + /* Replace spaces with underscores */ + for (p = ltag; *p != '\0'; p++) + if (*p == ' ') + *p = '_'; + + tags[n_tags++] = g_strdup (ltag); + g_free (ltag); + } + + if (n_tags == 0) { + gpk_dbus_task_dbus_return_value (dtask, FALSE); + goto out; + } + + tags = g_renew (gchar *, tags, n_tags + 1); + tags[n_tags] = NULL; + + /* get driver packages */ + pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), + pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, + PK_FILTER_ENUM_ARCH, + PK_FILTER_ENUM_NEWEST, + -1), +#if !PK_CHECK_VERSION(0,9,0) + PK_PROVIDES_ENUM_POSTSCRIPT_DRIVER, +#endif + tags, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_printer_driver_what_provides_cb, dtask); + + out: + g_strfreev (tags); +} + +/** + * gpk_dbus_task_remove_package_ids: + * @task: a valid #GpkDbusTask instance + **/ +static void +gpk_dbus_task_remove_package_ids (GpkDbusTask *dtask) +{ + GtkWindow *window; + + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING); + /* TRANSLATORS: title: removing packages */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Removing packages")); + if (dtask->priv->show_progress) + gpk_modal_dialog_present (dtask->priv->dialog); + + /* ensure parent is set */ + window = gpk_modal_dialog_get_window (dtask->priv->dialog); + gpk_task_set_parent_window (GPK_TASK (dtask->priv->task), window); + + /* remove async */ + pk_task_remove_packages_async (dtask->priv->task, dtask->priv->package_ids, TRUE, TRUE, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_remove_packages_cb, dtask); +} + +/** + * gpk_dbus_task_remove_package_by_file_search_file_cb: + **/ +static void +gpk_dbus_task_remove_package_by_file_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask) +{ + GError *error = NULL; + GError *error_dbus = NULL; + PkResults *results = NULL; + GPtrArray *array = NULL; + PkError *error_code = NULL; + + /* get the results */ + results = pk_client_generic_finish (client, res, &error); + if (results == NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search by file: %s", error->message); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_warning ("failed to resolve: %s", error->message); + g_error_free (error); + g_error_free (error_dbus); + goto out; + } + + /* check error code */ + error_code = pk_results_get_error_code (results); + if (error_code != NULL) { + error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search by file: %s", pk_error_get_details (error_code)); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* get results */ + array = pk_results_get_package_array (results); + + /* found nothing? */ + if (array->len == 0) { + if (dtask->priv->show_warning) { + gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + /* TRANSLATORS: failed to find the package for the file */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find package for this file")); + /* TRANSLATORS: nothing found */ + gpk_modal_dialog_set_message (dtask->priv->dialog, _("The file could not be found in any packages")); + /* TRANSLATORS: button: show the user a button to get more help finding stuff */ + gpk_modal_dialog_present (dtask->priv->dialog); + gpk_modal_dialog_run (dtask->priv->dialog); + } + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no packages found for this file"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + + /* convert to data */ + dtask->priv->package_ids = pk_package_array_to_strv (array); + + /* remove these packages with deps */ + gpk_dbus_task_remove_package_ids (dtask); +out: + if (error_code != NULL) + g_object_unref (error_code); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); +} + +/** + * gpk_dbus_task_remove_package_by_file: + * @task: a valid #GpkDbusTask instance + * @full_path: a file path name such as <literal>/usr/sbin/packagekitd</literal> + * @error: a %GError to put the error code and message in, or %NULL + * + * Remove a package which provides a file on the system. + * + * Return value: %TRUE if the method succeeded + **/ +void +gpk_dbus_task_remove_package_by_file (GpkDbusTask *dtask, gchar **full_paths, GpkDbusTaskFinishedCb finished_cb, gpointer userdata) +{ + gboolean ret; + GError *error_dbus = NULL; + guint len; + guint i; + gchar *text; + gchar *message; + GString *string; + + g_return_if_fail (GPK_IS_DBUS_TASK (dtask)); + g_return_if_fail (full_paths != NULL); + + /* save callback information */ + dtask->priv->finished_cb = finished_cb; + dtask->priv->finished_userdata = userdata; + + /* optional */ + if (!dtask->priv->show_confirm_search) { + g_debug ("skip confirm as not allowed to interact with user"); + goto skip_checks; + } + + string = g_string_new (""); + len = g_strv_length (full_paths); + + /* don't use a bullet for one item */ + if (len == 1) { + g_string_append_printf (string, "%s\n", full_paths[0]); + } else { + for (i=0; i<len; i++) + g_string_append_printf (string, "• %s\n", full_paths[i]); + } + /* display messagebox */ + text = g_string_free (string, FALSE); + + /* check user wanted operation */ + message = g_strdup_printf ("%s\n\n%s\n\n%s", + /* TRANSLATORS: a program wants to remove a file, e.g. /lib/moo.so */ + ngettext ("The following file will be removed:", "The following files will be removed:", len), + text, + /* TRANSLATORS: confirm with the user */ + ngettext ("Do you want to remove this file now?", "Do you want to remove these files now?", len)); + + /* make title using application name */ + if (dtask->priv->parent_title != NULL) { + /* TRANSLATORS: string is a program name, e.g. "Movie Player" */ + text = g_strdup_printf (ngettext ("%s wants to remove a file", "%s wants to remove files", len), dtask->priv->parent_title); + } else { + /* TRANSLATORS: a random program which we can't get the name wants to do something */ + text = g_strdup (ngettext ("A program wants to remove a file", "A program wants to remove files", len)); + } + + /* TRANSLATORS: button: confirm to search for packages */ + ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Remove")); + g_free (text); + g_free (message); + if (!ret) { + error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search"); + gpk_dbus_task_dbus_return_error (dtask, error_dbus); + g_error_free (error_dbus); + goto out; + } + +skip_checks: + /* TRANSLATORS: searching for the package that provides the file */ + gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file")); + gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT); + + /* do search */ + pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, PK_FILTER_ENUM_INSTALLED, -1), full_paths, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, + (GAsyncReadyCallback) gpk_dbus_task_remove_package_by_file_search_file_cb, dtask); + + /* wait for async reply */ +out: + return; +} + +/** + * gpk_dbus_task_get_package_for_exec: + **/ +gchar * +gpk_dbus_task_get_package_for_exec (GpkDbusTask *dtask, const gchar *exec) +{ + const gchar *package_id; + gchar *package = NULL; + GError *error = NULL; + GPtrArray *array = NULL; + PkPackage *item; + PkResults *results = NULL; + gchar **values = NULL; + gchar **split = NULL; + + /* find the package name */ + values = g_strsplit (exec, "&", -1); + results = pk_client_search_files (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), values, NULL, + (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, &error); + if (results == NULL) { + g_warning ("failed to search file: %s", error->message); + g_error_free (error); + goto out; + } + + /* get the list of packages */ + array = pk_results_get_package_array (results); + + /* nothing found */ + if (array->len == 0) { + g_debug ("cannot find installed package that provides : %s", exec); + goto out; + } + + /* check we have one */ + if (array->len != 1) + g_warning ("not one return, using first"); + + /* copy name */ + item = g_ptr_array_index (array, 0); + package_id = pk_package_get_id (item); + split = pk_package_id_split (package_id); + package = g_strdup (split[0]); + g_debug ("got package %s", package); +out: + g_strfreev (values); + g_strfreev (split); + if (array != NULL) + g_ptr_array_unref (array); + if (results != NULL) + g_object_unref (results); + return package; +} + +/** + * gpk_dbus_task_path_is_trusted: + **/ +gboolean +gpk_dbus_task_path_is_trusted (const gchar *exec) +{ + gboolean res = FALSE; + gchar *path; + + /* special case the plugin helper -- it's trusted */ + + path = g_build_filename (LIBEXECDIR, "gst-install-plugins-helper", NULL); + res = res || (g_strcmp0 (exec, path) == 0); + g_free (path); + + path = g_build_filename (LIBEXECDIR, "pk-gstreamer-install", NULL); + res = res || (g_strcmp0 (exec, path) == 0); + g_free (path); + + return res; +} + +/** + * gpk_dbus_task_set_exec: + * + * This sets the package name of the application that is trying to install + * software, e.g. "totem" and is used for the PkDesktop lookup to provide + * a translated name and icon. + **/ +gboolean +gpk_dbus_task_set_exec (GpkDbusTask *dtask, const gchar *exec) +{ + GpkX11 *x11; + gchar *package = NULL; + + g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE); + + /* old values invalid */ + g_free (dtask->priv->exec); + g_free (dtask->priv->parent_title); + g_free (dtask->priv->parent_icon_name); + dtask->priv->exec = g_strdup (exec); + dtask->priv->parent_title = NULL; + dtask->priv->parent_icon_name = NULL; + + /* is the binary trusted, i.e. can we probe it's window properties */ + if (gpk_dbus_task_path_is_trusted (exec) && + dtask->priv->parent_window != NULL) { + g_debug ("using application window properties"); + /* get from window properties */ + x11 = gpk_x11_new (); + gpk_x11_set_window (x11, dtask->priv->parent_window); + dtask->priv->parent_title = gpk_x11_get_title (x11); + g_object_unref (x11); + goto out; + } + + /* get from installed database */ + package = gpk_dbus_task_get_package_for_exec (dtask, exec); + g_debug ("got package %s", package); + if (package != NULL) + dtask->priv->parent_title = g_strdup (package); + + /* fallback to exec - eugh... */ + if (dtask->priv->parent_title == NULL) { + g_debug ("did not get package for %s, using exec basename", package); + dtask->priv->parent_title = g_path_get_basename (exec); + } +out: + g_free (package); + g_debug ("got name=%s, icon=%s", dtask->priv->parent_title, dtask->priv->parent_icon_name); + return TRUE; +} + +/** + * gpk_dbus_task_class_init: + * @klass: The #GpkDbusTaskClass + **/ +static void +gpk_dbus_task_class_init (GpkDbusTaskClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_dbus_task_finalize; + g_type_class_add_private (klass, sizeof (GpkDbusTaskPrivate)); +} + +/** + * gpk_dbus_task_init: + * @task: a valid #GpkDbusTask instance + **/ +static void +gpk_dbus_task_init (GpkDbusTask *dtask) +{ + GtkWindow *main_window; + + dtask->priv = GPK_DBUS_TASK_GET_PRIVATE (dtask); + + dtask->priv->package_ids = NULL; + dtask->priv->files = NULL; + dtask->priv->parent_window = NULL; + dtask->priv->parent_title = NULL; + dtask->priv->exec = NULL; + dtask->priv->parent_icon_name = NULL; + dtask->priv->cached_error_code = NULL; + dtask->priv->context = NULL; + dtask->priv->cancellable = g_cancellable_new (); + dtask->priv->exit = PK_EXIT_ENUM_FAILED; + dtask->priv->show_confirm_search = TRUE; + dtask->priv->show_confirm_deps = TRUE; + dtask->priv->show_confirm_install = TRUE; + dtask->priv->show_progress = TRUE; + dtask->priv->show_finished = TRUE; + dtask->priv->show_warning = TRUE; + dtask->priv->timestamp = 0; + + /* add application specific icons to search path */ + gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), + GPK_DATA G_DIR_SEPARATOR_S "icons"); + + /* only initialize if the application didn't do it before */ + if (!notify_is_initted ()) + notify_init (_("Software Install")); + + dtask->priv->vendor = gpk_vendor_new (); + dtask->priv->dialog = gpk_modal_dialog_new (); + main_window = gpk_modal_dialog_get_window (dtask->priv->dialog); + gpk_modal_dialog_set_window_icon (dtask->priv->dialog, "pk-package-installed"); + g_signal_connect (dtask->priv->dialog, "cancel", + G_CALLBACK (gpk_dbus_task_button_cancel_cb), dtask); + g_signal_connect (dtask->priv->dialog, "close", + G_CALLBACK (gpk_dbus_task_button_close_cb), dtask); + + /* helpers */ + dtask->priv->helper_run = gpk_helper_run_new (); + gpk_helper_run_set_parent (dtask->priv->helper_run, main_window); + + dtask->priv->helper_chooser = gpk_helper_chooser_new (); + g_signal_connect (dtask->priv->helper_chooser, "event", G_CALLBACK (gpk_dbus_task_chooser_event_cb), dtask); + gpk_helper_chooser_set_parent (dtask->priv->helper_chooser, main_window); + + /* map ISO639 to language names */ + dtask->priv->language = gpk_language_new (); + gpk_language_populate (dtask->priv->language, NULL); + + /* gat session settings */ + dtask->priv->settings = g_settings_new (GPK_SETTINGS_SCHEMA); + + /* get actions */ + dtask->priv->control = pk_control_new (); + dtask->priv->task = PK_TASK(gpk_task_new ()); + dtask->priv->roles = pk_control_get_properties (dtask->priv->control, NULL, NULL); +} + +/** + * gpk_dbus_task_finalize: + * @object: The object to finalize + **/ +static void +gpk_dbus_task_finalize (GObject *object) +{ + GpkDbusTask *dtask; + GError *error; + + g_return_if_fail (GPK_IS_DBUS_TASK (object)); + + dtask = GPK_DBUS_TASK (object); + g_return_if_fail (dtask->priv != NULL); + + /* no reply was sent */ + if (dtask->priv->context != NULL) { + error = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "context never was returned"); + gpk_dbus_task_dbus_return_error (dtask, error); + g_error_free (error); + } + + g_free (dtask->priv->parent_title); + g_free (dtask->priv->parent_icon_name); + g_free (dtask->priv->exec); + if (dtask->priv->cached_error_code != NULL) + g_object_unref (dtask->priv->cached_error_code); + g_strfreev (dtask->priv->files); + g_strfreev (dtask->priv->package_ids); + g_object_unref (PK_CLIENT(dtask->priv->task)); + g_object_unref (dtask->priv->control); + g_object_unref (dtask->priv->settings); + g_object_unref (dtask->priv->dialog); + g_object_unref (dtask->priv->vendor); + g_object_unref (dtask->priv->language); + g_object_unref (dtask->priv->cancellable); + g_object_unref (dtask->priv->helper_run); + g_object_unref (dtask->priv->helper_chooser); + + G_OBJECT_CLASS (gpk_dbus_task_parent_class)->finalize (object); +} + +/** + * gpk_dbus_task_new: + * + * PkClient is a nice GObject wrapper for gnome-packagekit and makes installing software easy + * + * Return value: A new %GpkDbusTask instance + **/ +GpkDbusTask * +gpk_dbus_task_new (void) +{ + GpkDbusTask *dtask; + dtask = g_object_new (GPK_TYPE_DBUS_TASK, NULL); + return GPK_DBUS_TASK (dtask); +} Index: gnome-packagekit-3.20.0/src/gpk-dbus-task.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-dbus-task.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_DBUS_TASK_H +#define __GPK_DBUS_TASK_H + +#include <glib-object.h> +#include <dbus/dbus-glib.h> +#include <packagekit-glib2/packagekit.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_DBUS_TASK (gpk_dbus_task_get_type ()) +#define GPK_DBUS_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_DBUS_TASK, GpkDbusTask)) +#define GPK_DBUS_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass)) +#define GPK_IS_DBUS_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_DBUS_TASK)) +#define GPK_IS_DBUS_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_DBUS_TASK)) +#define GPK_DBUS_TASK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass)) + +typedef struct _GpkDbusTaskPrivate GpkDbusTaskPrivate; +typedef struct _GpkDbusTask GpkDbusTask; +typedef struct _GpkDbusTaskClass GpkDbusTaskClass; + +struct _GpkDbusTask +{ + GObject parent; + GpkDbusTaskPrivate *priv; +}; + +struct _GpkDbusTaskClass +{ + GObjectClass parent_class; +}; + +/** + * GpkDbusTaskInteract: + */ +typedef enum +{ + GPK_CLIENT_INTERACT_CONFIRM_SEARCH, + GPK_CLIENT_INTERACT_CONFIRM_DEPS, + GPK_CLIENT_INTERACT_CONFIRM_INSTALL, + GPK_CLIENT_INTERACT_PROGRESS, + GPK_CLIENT_INTERACT_FINISHED, + GPK_CLIENT_INTERACT_WARNING, + GPK_CLIENT_INTERACT_UNKNOWN +} GpkDbusTaskInteract; + +#define GPK_CLIENT_INTERACT_NEVER 0 +#define GPK_CLIENT_INTERACT_ALWAYS pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \ + GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \ + GPK_CLIENT_INTERACT_CONFIRM_DEPS, \ + GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \ + GPK_CLIENT_INTERACT_PROGRESS, \ + GPK_CLIENT_INTERACT_FINISHED, -1) +#define GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \ + GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \ + GPK_CLIENT_INTERACT_CONFIRM_DEPS, \ + GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \ + GPK_CLIENT_INTERACT_PROGRESS, -1) +#define GPK_CLIENT_INTERACT_WARNING pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, -1) +#define GPK_CLIENT_INTERACT_WARNING_PROGRESS pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \ + GPK_CLIENT_INTERACT_PROGRESS, -1) + +GQuark gpk_dbus_task_error_quark (void); +GType gpk_dbus_task_get_type (void); +GType gpk_dbus_task_error_get_type (void); +GpkDbusTask *gpk_dbus_task_new (void); + +/* callback when done */ +typedef void (*GpkDbusTaskFinishedCb) (GpkDbusTask *dtask, + gpointer userdata); + +/* methods that expect a DBusGMethodInvocation return */ +void gpk_dbus_task_is_installed (GpkDbusTask *dtask, + const gchar *package_name, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_search_file (GpkDbusTask *dtask, + const gchar *search_file, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_package_files (GpkDbusTask *dtask, + gchar **files_rel, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_provide_files (GpkDbusTask *dtask, + gchar **full_paths, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_mime_types (GpkDbusTask *dtask, + gchar **mime_types, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_gstreamer_resources (GpkDbusTask *dtask, + gchar **codec_names, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *dtask, + gchar **fonts, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_resources (GpkDbusTask *dtask, + gchar **resources, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_printer_drivers (GpkDbusTask *dtask, + gchar **ids, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_install_package_names (GpkDbusTask *dtask, + gchar **packages, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); +void gpk_dbus_task_remove_package_by_file (GpkDbusTask *dtask, + gchar **full_paths, + GpkDbusTaskFinishedCb finished_cb, + gpointer userdata); + +/* set state */ +gboolean gpk_dbus_task_set_interaction (GpkDbusTask *dtask, + PkBitfield interact); +gboolean gpk_dbus_task_set_timestamp (GpkDbusTask *dtask, + guint timeout); +gboolean gpk_dbus_task_set_context (GpkDbusTask *dtask, + DBusGMethodInvocation *context); +gboolean gpk_dbus_task_set_xid (GpkDbusTask *dtask, + guint xid); +gboolean gpk_dbus_task_set_exec (GpkDbusTask *dtask, + const gchar *exec); + +/* for self checks */ +gchar *gpk_dbus_task_font_tag_to_localised_name (GpkDbusTask *dtask, + const gchar *tag); +gboolean gpk_dbus_task_path_is_trusted (const gchar *exec); +gchar *gpk_dbus_task_get_package_for_exec (GpkDbusTask *dtask, + const gchar *exec); +gchar *gpk_dbus_task_font_tag_to_lang (const gchar *tag); + + +G_END_DECLS + +#endif /* __GPK_DBUS_TASK_H */ Index: gnome-packagekit-3.20.0/src/gpk-dbus.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-dbus.c @@ -0,0 +1,590 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <signal.h> + +#include <string.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include <sys/wait.h> +#include <fcntl.h> + +#include <glib/gi18n.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include <packagekit-glib2/packagekit.h> + +#include "egg-string.h" + +#include "gpk-dbus.h" +#include "gpk-dbus-task.h" +#include "gpk-x11.h" +#include "gpk-common.h" + +static void gpk_dbus_finalize (GObject *object); + +#define GPK_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_DBUS, GpkDbusPrivate)) + +struct GpkDbusPrivate +{ + GSettings *settings; + gint timeout_tmp; + GTimer *timer; + guint refcount; + GpkX11 *x11; + DBusGProxy *proxy_session_pid; + DBusGProxy *proxy_system_pid; +}; + +G_DEFINE_TYPE (GpkDbus, gpk_dbus, G_TYPE_OBJECT) + +/** + * gpk_dbus_error_quark: + * Return value: Our personal error quark. + **/ +GQuark +gpk_dbus_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("gpk_dbus_error"); + return quark; +} + +/** + * gpk_dbus_error_get_type: + **/ +GType +gpk_dbus_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + guint i; + static GEnumValue values[PK_ERROR_ENUM_LAST]; + for (i = 0; i < PK_ERROR_ENUM_LAST; i++) { + values[i].value = i; + values[i].value_name = pk_error_enum_to_string (i); + values[i].value_nick = pk_error_enum_to_string (i); + } + etype = g_enum_register_static ("GpkDbusError", values); + } + return etype; +} + +/** + * gpk_dbus_get_idle_time: + **/ +guint +gpk_dbus_get_idle_time (GpkDbus *dbus) +{ + guint idle = 0; + + /* we need to return 0 if there is a task in progress */ + if (dbus->priv->refcount > 0) + goto out; + + idle = (guint) g_timer_elapsed (dbus->priv->timer, NULL); + g_debug ("we've been idle for %is", idle); +out: + return idle; +} + +/** + * gpk_dbus_get_pid_session: + **/ +static guint +gpk_dbus_get_pid_session (GpkDbus *dbus, const gchar *sender) +{ + guint pid = G_MAXUINT; + gboolean ret; + GError *error = NULL; + + /* get pid from DBus (quite slow) */ + ret = dbus_g_proxy_call (dbus->priv->proxy_session_pid, "GetConnectionUnixProcessID", &error, + G_TYPE_STRING, sender, + G_TYPE_INVALID, + G_TYPE_UINT, &pid, + G_TYPE_INVALID); + if (!ret) { + g_debug ("failed to get pid from session: %s", error->message); + g_error_free (error); + goto out; + } +out: + return pid; +} + +/** + * gpk_dbus_get_pid_system: + **/ +static guint +gpk_dbus_get_pid_system (GpkDbus *dbus, const gchar *sender) +{ + guint pid = G_MAXUINT; + gboolean ret; + GError *error = NULL; + + /* get pid from DBus (quite slow) */ + ret = dbus_g_proxy_call (dbus->priv->proxy_system_pid, "GetConnectionUnixProcessID", &error, + G_TYPE_STRING, sender, + G_TYPE_INVALID, + G_TYPE_UINT, &pid, + G_TYPE_INVALID); + if (!ret) { + g_debug ("failed to get pid from system: %s", error->message); + g_error_free (error); + goto out; + } +out: + return pid; +} + +/** + * gpk_dbus_get_pid: + **/ +static guint +gpk_dbus_get_pid (GpkDbus *dbus, const gchar *sender) +{ + guint pid; + + g_return_val_if_fail (PK_IS_DBUS (dbus), G_MAXUINT); + g_return_val_if_fail (dbus->priv->proxy_session_pid != NULL, G_MAXUINT); + g_return_val_if_fail (dbus->priv->proxy_system_pid != NULL, G_MAXUINT); + g_return_val_if_fail (sender != NULL, G_MAXUINT); + + /* check system bus first */ + pid = gpk_dbus_get_pid_system (dbus, sender); + if (pid != G_MAXUINT) + goto out; + + /* and then session bus */ + pid = gpk_dbus_get_pid_session (dbus, sender); + if (pid != G_MAXUINT) + goto out; + + /* should be impossible */ + g_warning ("could not find pid!"); +out: + return pid; +} + +/** + * gpk_dbus_get_exec_for_sender: + **/ +static gchar * +gpk_dbus_get_exec_for_sender (GpkDbus *dbus, const gchar *sender) +{ + gchar *filename = NULL; + gchar *cmdline = NULL; + GError *error = NULL; + guint pid; + + g_return_val_if_fail (PK_IS_DBUS (dbus), NULL); + g_return_val_if_fail (sender != NULL, NULL); + + /* get pid */ + pid = gpk_dbus_get_pid (dbus, sender); + if (pid == G_MAXUINT) { + g_warning ("failed to get PID"); + goto out; + } + + /* get command line from proc */ + filename = g_strdup_printf ("/proc/%i/exe", pid); + cmdline = g_file_read_link (filename, &error); + if (cmdline == NULL) { + g_warning ("failed to find exec: %s", error->message); + g_error_free (error); + } +out: + g_free (filename); + return cmdline; +} + +/** + * gpk_dbus_set_interaction_from_text: + **/ +static void +gpk_dbus_set_interaction_from_text (PkBitfield *interact, gint *timeout, const gchar *interaction) +{ + guint i; + guint len; + gchar **interactions; + interactions = g_strsplit (interaction, ",", -1); + len = g_strv_length (interactions); + + /* do special keys first */ + for (i=0; i<len; i++) { + if (g_strcmp0 (interactions[i], "always") == 0) + *interact = GPK_CLIENT_INTERACT_ALWAYS; + else if (g_strcmp0 (interactions[i], "never") == 0) + *interact = GPK_CLIENT_INTERACT_NEVER; + } + + /* add or remove from defaults */ + for (i=0; i<len; i++) { + /* show */ + if (g_strcmp0 (interactions[i], "show-confirm-search") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH); + else if (g_strcmp0 (interactions[i], "show-confirm-deps") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS); + else if (g_strcmp0 (interactions[i], "show-confirm-install") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL); + else if (g_strcmp0 (interactions[i], "show-progress") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_PROGRESS); + else if (g_strcmp0 (interactions[i], "show-finished") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_FINISHED); + else if (g_strcmp0 (interactions[i], "show-warning") == 0) + pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_WARNING); + /* hide */ + else if (g_strcmp0 (interactions[i], "hide-confirm-search") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH); + else if (g_strcmp0 (interactions[i], "hide-confirm-deps") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS); + else if (g_strcmp0 (interactions[i], "hide-confirm-install") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL); + else if (g_strcmp0 (interactions[i], "hide-progress") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_PROGRESS); + else if (g_strcmp0 (interactions[i], "hide-finished") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_FINISHED); + else if (g_strcmp0 (interactions[i], "hide-warning") == 0) + pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_WARNING); + /* wait */ + else if (g_str_has_prefix (interactions[i], "timeout=")) + *timeout = atoi (&interactions[i][8]); + } + g_strfreev (interactions); +} + +/** + * gpk_dbus_parse_interaction: + **/ +static void +gpk_dbus_parse_interaction (GpkDbus *dbus, const gchar *interaction, PkBitfield *interact, gint *timeout) +{ + gchar *policy; + + /* set temp default */ + *interact = 0; + dbus->priv->timeout_tmp = -1; + + /* get default policy from settings */ + policy = g_settings_get_string (dbus->priv->settings, GPK_SETTINGS_DBUS_DEFAULT_INTERACTION); + if (policy != NULL) { + g_debug ("default is %s", policy); + gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy); + } + g_free (policy); + + /* now override with policy from client */ + gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, interaction); + g_debug ("client is %s", interaction); + + /* now override with enforced policy */ + policy = g_settings_get_string (dbus->priv->settings, GPK_SETTINGS_DBUS_ENFORCED_INTERACTION); + if (policy != NULL) { + g_debug ("enforced is %s", policy); + gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy); + } + g_free (policy); + + /* copy from temp */ + *timeout = dbus->priv->timeout_tmp; +} + +/** + * gpk_dbus_create_task: + **/ +static GpkDbusTask * +gpk_dbus_create_task (GpkDbus *dbus, guint32 xid, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + PkBitfield interact = 0; + gint timeout = 0; + gchar *sender; + gchar *exec; + guint timestamp = 0; + gboolean ret; + + task = gpk_dbus_task_new (); + + /* work out what interaction the task should use */ + gpk_dbus_parse_interaction (dbus, interaction, &interact, &timeout); + + /* set interaction mode */ + g_debug ("interact=%i", (gint) interact); + gpk_dbus_task_set_interaction (task, interact); + + /* try to get the user time of the window */ + if (xid != 0) { + ret = gpk_x11_set_xid (dbus->priv->x11, xid); + if (ret) + timestamp = gpk_x11_get_user_time (dbus->priv->x11); + } + + /* set the context for the return values */ + gpk_dbus_task_set_context (task, context); + + /* set the last interaction */ + gpk_dbus_task_set_timestamp (task, timestamp); + + /* set the window for the modal and timestamp */ + if (xid != 0) + gpk_dbus_task_set_xid (task, xid); + + /* get the program name and set */ + sender = dbus_g_method_get_sender (context); + exec = gpk_dbus_get_exec_for_sender (dbus, sender); + if (exec != NULL) + gpk_dbus_task_set_exec (task, exec); + + /* unref on delete */ + //g_signal_connect... + + /* reset time */ + g_timer_reset (dbus->priv->timer); + dbus->priv->refcount++; + + g_free (sender); + g_free (exec); + return task; +} + +/** + * gpk_dbus_task_finished_cb: + **/ +static void +gpk_dbus_task_finished_cb (GpkDbusTask *task, GpkDbus *dbus) +{ + /* one context has returned */ + if (dbus->priv->refcount > 0) + dbus->priv->refcount--; + + /* reset time */ + g_timer_reset (dbus->priv->timer); + + g_object_unref (task); +} + +/** + * gpk_dbus_is_installed: + **/ +void +gpk_dbus_is_installed (GpkDbus *dbus, const gchar *package_name, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, 0, interaction, context); + gpk_dbus_task_is_installed (task, package_name, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_search_file: + **/ +void +gpk_dbus_search_file (GpkDbus *dbus, const gchar *file_name, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, 0, interaction, context); + gpk_dbus_task_search_file (task, file_name, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_package_files: + **/ +void +gpk_dbus_install_package_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_package_files (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_provide_files: + **/ +void +gpk_dbus_install_provide_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_provide_files (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_remove_package_by_files: + **/ +void +gpk_dbus_remove_package_by_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_remove_package_by_file (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_package_names: + **/ +void +gpk_dbus_install_package_names (GpkDbus *dbus, guint32 xid, gchar **packages, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_package_names (task, packages, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_mime_types: + **/ +void +gpk_dbus_install_mime_types (GpkDbus *dbus, guint32 xid, gchar **mime_types, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_mime_types (task, mime_types, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_fontconfig_resources: + **/ +void +gpk_dbus_install_fontconfig_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_fontconfig_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_gstreamer_resources: + **/ +void +gpk_dbus_install_gstreamer_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_gstreamer_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_resources: + **/ +void +gpk_dbus_install_resources (GpkDbus *dbus, guint32 xid, const gchar *type, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_install_printer_drivers: + **/ +void +gpk_dbus_install_printer_drivers (GpkDbus *dbus, guint32 xid, gchar **device_ids, const gchar *interaction, DBusGMethodInvocation *context) +{ + GpkDbusTask *task; + task = gpk_dbus_create_task (dbus, xid, interaction, context); + gpk_dbus_task_install_printer_drivers (task, device_ids, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus); +} + +/** + * gpk_dbus_class_init: + * @klass: The GpkDbusClass + **/ +static void +gpk_dbus_class_init (GpkDbusClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_dbus_finalize; + g_type_class_add_private (klass, sizeof (GpkDbusPrivate)); +} + +/** + * gpk_dbus_init: + * @dbus: This class instance + **/ +static void +gpk_dbus_init (GpkDbus *dbus) +{ + DBusGConnection *connection; + + dbus->priv = GPK_DBUS_GET_PRIVATE (dbus); + dbus->priv->timeout_tmp = -1; + dbus->priv->settings = g_settings_new (GPK_SETTINGS_SCHEMA); + dbus->priv->x11 = gpk_x11_new (); + dbus->priv->timer = g_timer_new (); + + /* find out PIDs on the session bus */ + connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + dbus->priv->proxy_session_pid = dbus_g_proxy_new_for_name_owner (connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus/Bus", + "org.freedesktop.DBus", NULL); + /* find out PIDs on the system bus */ + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + dbus->priv->proxy_system_pid = dbus_g_proxy_new_for_name_owner (connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus/Bus", + "org.freedesktop.DBus", NULL); +} + +/** + * gpk_dbus_finalize: + * @object: The object to finalize + **/ +static void +gpk_dbus_finalize (GObject *object) +{ + GpkDbus *dbus; + g_return_if_fail (PK_IS_DBUS (object)); + + dbus = GPK_DBUS (object); + g_return_if_fail (dbus->priv != NULL); + g_timer_destroy (dbus->priv->timer); + g_object_unref (dbus->priv->settings); + g_object_unref (dbus->priv->x11); + g_object_unref (dbus->priv->proxy_session_pid); + g_object_unref (dbus->priv->proxy_system_pid); + + G_OBJECT_CLASS (gpk_dbus_parent_class)->finalize (object); +} + +/** + * gpk_dbus_new: + * + * Return value: a new GpkDbus object. + **/ +GpkDbus * +gpk_dbus_new (void) +{ + GpkDbus *dbus; + dbus = g_object_new (GPK_TYPE_DBUS, NULL); + return GPK_DBUS (dbus); +} Index: gnome-packagekit-3.20.0/src/gpk-dbus.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-dbus.h @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_DBUS_H +#define __GPK_DBUS_H + +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_DBUS (gpk_dbus_get_type ()) +#define GPK_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_DBUS, GpkDbus)) +#define GPK_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_DBUS, GpkDbusClass)) +#define PK_IS_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_DBUS)) +#define PK_IS_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_DBUS)) +#define GPK_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_DBUS, GpkDbusClass)) +#define GPK_DBUS_ERROR (gpk_dbus_error_quark ()) +#define GPK_DBUS_TYPE_ERROR (gpk_dbus_error_get_type ()) + +typedef struct GpkDbusPrivate GpkDbusPrivate; + +typedef struct +{ + GObject parent; + GpkDbusPrivate *priv; +} GpkDbus; + +typedef struct +{ + GObjectClass parent_class; +} GpkDbusClass; + +GQuark gpk_dbus_error_quark (void); +GType gpk_dbus_error_get_type (void); +GType gpk_dbus_get_type (void); +GpkDbus *gpk_dbus_new (void); + +guint gpk_dbus_get_idle_time (GpkDbus *dbus); + +/* org.freedesktop.PackageKit.Query */ +void gpk_dbus_is_installed (GpkDbus *dbus, + const gchar *package_name, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_search_file (GpkDbus *dbus, + const gchar *file_name, + const gchar *interaction, + DBusGMethodInvocation *context); + +/* org.freedesktop.PackageKit.Modify */ +void gpk_dbus_install_provide_files (GpkDbus *dbus, + guint32 xid, + gchar **files, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_catalogs (GpkDbus *dbus, + guint32 xid, + gchar **files, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_package_files (GpkDbus *dbus, + guint32 xid, + gchar **files, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_package_names (GpkDbus *dbus, + guint32 xid, + gchar **packages, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_mime_types (GpkDbus *dbus, + guint32 xid, + gchar **mime_types, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_fontconfig_resources (GpkDbus *dbus, + guint32 xid, + gchar **fonts, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_gstreamer_resources (GpkDbus *dbus, + guint32 xid, + gchar **codecs, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_install_resources (GpkDbus *dbus, + guint32 xid, + const gchar *type, + gchar **resources, + const gchar *interaction, + DBusGMethodInvocation *context); +void gpk_dbus_remove_package_by_files (GpkDbus *dbus, + guint32 xid, + gchar **files, + const gchar *interaction, + DBusGMethodInvocation *context); + +void gpk_dbus_install_printer_drivers (GpkDbus *dbus, + guint32 xid, + gchar **device_ids, + const gchar *interaction, + DBusGMethodInvocation *context); +G_END_DECLS + +#endif /* __GPK_DBUS_H */ Index: gnome-packagekit-3.20.0/src/gpk-enum.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-enum.c +++ gnome-packagekit-3.20.0/src/gpk-enum.c @@ -100,6 +100,46 @@ static const PkEnumMatch enum_status_ico {0, NULL} }; +static const PkEnumMatch enum_status_animation[] = { + {PK_STATUS_ENUM_UNKNOWN, "help-browser"}, + {PK_STATUS_ENUM_CANCEL, "pk-action-cleanup"}, + {PK_STATUS_ENUM_CLEANUP, "pk-action-cleanup"}, + {PK_STATUS_ENUM_COMMIT, "pk-setup"}, + {PK_STATUS_ENUM_DEP_RESOLVE, "pk-action-testing"}, + {PK_STATUS_ENUM_DOWNLOAD_CHANGELOG, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_DOWNLOAD_FILELIST, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_DOWNLOAD_GROUP, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_DOWNLOAD, "pk-action-download"}, + {PK_STATUS_ENUM_DOWNLOAD_REPOSITORY, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_FINISHED, "pk-package-cleanup"}, + {PK_STATUS_ENUM_GENERATE_PACKAGE_LIST, "pk-action-searching"}, + {PK_STATUS_ENUM_WAITING_FOR_LOCK, "pk-action-waiting"}, + {PK_STATUS_ENUM_WAITING_FOR_AUTH, "pk-action-waiting"}, + {PK_STATUS_ENUM_INFO, "process-working"}, + {PK_STATUS_ENUM_INSTALL, "pk-action-installing"}, + {PK_STATUS_ENUM_LOADING_CACHE, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_OBSOLETE, "pk-package-cleanup"}, + {PK_STATUS_ENUM_QUERY, "pk-action-searching"}, + {PK_STATUS_ENUM_REFRESH_CACHE, "pk-action-refresh-cache"}, + {PK_STATUS_ENUM_REMOVE, "pk-action-removing"}, + {PK_STATUS_ENUM_REPACKAGING, "pk-package-info"}, + {PK_STATUS_ENUM_REQUEST, "process-working"}, + {PK_STATUS_ENUM_RUNNING, "pk-setup"}, + {PK_STATUS_ENUM_SCAN_APPLICATIONS, "pk-action-searching"}, + {PK_STATUS_ENUM_SETUP, "pk-package-info"}, + {PK_STATUS_ENUM_SIG_CHECK, "pk-package-info"}, + {PK_STATUS_ENUM_TEST_COMMIT, "pk-action-testing"}, + {PK_STATUS_ENUM_UPDATE, "pk-action-installing"}, + {PK_STATUS_ENUM_WAIT, "pk-action-waiting"}, + {PK_STATUS_ENUM_SCAN_PROCESS_LIST, "pk-package-info"}, + {PK_STATUS_ENUM_CHECK_EXECUTABLE_FILES, "pk-package-info"}, + {PK_STATUS_ENUM_CHECK_LIBRARIES, "pk-package-info"}, + {PK_STATUS_ENUM_COPY_FILES, "pk-package-info"}, + {0, NULL} +}; + static const PkEnumMatch enum_role_icon_name[] = { {PK_ROLE_ENUM_UNKNOWN, "help-browser"}, /* fall though value */ {PK_ROLE_ENUM_ACCEPT_EULA, "pk-package-info"}, @@ -187,6 +227,17 @@ static const PkEnumMatch enum_restart_ic {0, NULL} }; +static const PkEnumMatch enum_restart_dialog_icon_name[] = { + {PK_RESTART_ENUM_UNKNOWN, "help-browser"}, /* fall though value */ + {PK_RESTART_ENUM_NONE, "dialog-information"}, + {PK_RESTART_ENUM_SYSTEM, "dialog-error"}, + {PK_RESTART_ENUM_SESSION, "dialog-warning"}, + {PK_RESTART_ENUM_APPLICATION, "dialog-warning"}, + {PK_RESTART_ENUM_SECURITY_SYSTEM, "dialog-error"}, + {PK_RESTART_ENUM_SECURITY_SESSION, "dialog-error"}, + {0, NULL} +}; + /** * gpk_media_type_enum_to_localised_text: **/ @@ -757,6 +808,32 @@ gpk_restart_enum_to_localised_text (PkRe } /** + * gpk_update_state_enum_to_localised_text: + **/ +const gchar * +gpk_update_state_enum_to_localised_text (PkUpdateStateEnum state) +{ + const gchar *text = NULL; + switch (state) { + case PK_UPDATE_STATE_ENUM_STABLE: + /* TRANSLATORS: A distribution stability level */ + text = _("Stable"); + break; + case PK_UPDATE_STATE_ENUM_UNSTABLE: + /* TRANSLATORS: A distribution stability level */ + text = _("Unstable"); + break; + case PK_UPDATE_STATE_ENUM_TESTING: + /* TRANSLATORS: A distribution stability level */ + text = _("Testing"); + break; + default: + g_warning ("state unrecognized: %i", state); + } + return text; +} + +/** * gpk_status_enum_to_localised_text: **/ const gchar * @@ -915,6 +992,48 @@ gpk_status_enum_to_localised_text (PkSta } /** + * gpk_update_enum_to_localised_text: + **/ +gchar * +gpk_update_enum_to_localised_text (PkInfoEnum info, guint number) +{ + gchar *text = NULL; + switch (info) { + case PK_INFO_ENUM_LOW: + /* TRANSLATORS: type of update */ + text = g_strdup_printf (ngettext ("%i trivial update", "%i trivial updates", number), number); + break; + case PK_INFO_ENUM_NORMAL: + /* TRANSLATORS: type of update in the case that we don't have any data */ + text = g_strdup_printf (ngettext ("%i update", "%i updates", number), number); + break; + case PK_INFO_ENUM_IMPORTANT: + /* TRANSLATORS: type of update */ + text = g_strdup_printf (ngettext ("%i important update", "%i important updates", number), number); + break; + case PK_INFO_ENUM_SECURITY: + /* TRANSLATORS: type of update */ + text = g_strdup_printf (ngettext ("%i security update", "%i security updates", number), number); + break; + case PK_INFO_ENUM_BUGFIX: + /* TRANSLATORS: type of update */ + text = g_strdup_printf (ngettext ("%i bug fix update", "%i bug fix updates", number), number); + break; + case PK_INFO_ENUM_ENHANCEMENT: + /* TRANSLATORS: type of update */ + text = g_strdup_printf (ngettext ("%i enhancement update", "%i enhancement updates", number), number); + break; + case PK_INFO_ENUM_BLOCKED: + /* TRANSLATORS: number of updates that cannot be installed due to deps */ + text = g_strdup_printf (ngettext ("%i blocked update", "%i blocked updates", number), number); + break; + default: + g_warning ("update info unrecognized: %s", pk_info_enum_to_string (info)); + } + return text; +} + +/** * gpk_info_enum_to_localised_text: **/ const gchar * @@ -977,7 +1096,7 @@ gpk_info_enum_to_localised_text (PkInfoE /** * gpk_info_enum_to_localised_present: **/ -static const gchar * +const gchar * gpk_info_enum_to_localised_present (PkInfoEnum info) { const gchar *text = NULL; @@ -1529,6 +1648,15 @@ gpk_status_enum_to_icon_name (PkStatusEn } /** + * gpk_status_enum_to_animation: + **/ +const gchar * +gpk_status_enum_to_animation (PkStatusEnum status) +{ + return pk_enum_find_string (enum_status_animation, status); +} + +/** * gpk_role_enum_to_icon_name: **/ const gchar * @@ -1560,6 +1688,15 @@ gpk_restart_enum_to_icon_name (PkRestart } /** + * gpk_restart_enum_to_dialog_icon_name: + **/ +const gchar * +gpk_restart_enum_to_dialog_icon_name (PkRestartEnum restart) +{ + return pk_enum_find_string (enum_restart_dialog_icon_name, restart); +} + +/** * gpk_info_status_enum_to_string: **/ const gchar * Index: gnome-packagekit-3.20.0/src/gpk-enum.h =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-enum.h +++ gnome-packagekit-3.20.0/src/gpk-enum.h @@ -84,10 +84,13 @@ const gchar *gpk_info_enum_to_localised_ G_GNUC_CONST; const gchar *gpk_info_enum_to_localised_past (PkInfoEnum info) G_GNUC_CONST; +const gchar *gpk_info_enum_to_localised_present (PkInfoEnum info) + G_GNUC_CONST; const gchar *gpk_info_enum_to_icon_name (PkInfoEnum info); const gchar *gpk_status_enum_to_localised_text (PkStatusEnum status) G_GNUC_CONST; const gchar *gpk_status_enum_to_icon_name (PkStatusEnum status); +const gchar *gpk_status_enum_to_animation (PkStatusEnum status); const gchar *gpk_restart_enum_to_icon_name (PkRestartEnum restart); const gchar *gpk_restart_enum_to_dialog_icon_name (PkRestartEnum restart); const gchar *gpk_error_enum_to_localised_text (PkErrorEnum code) @@ -95,11 +98,16 @@ const gchar *gpk_error_enum_to_localised const gchar *gpk_error_enum_to_localised_message (PkErrorEnum code); const gchar *gpk_restart_enum_to_localised_text (PkRestartEnum restart) G_GNUC_CONST; +const gchar *gpk_update_state_enum_to_localised_text (PkUpdateStateEnum state) + G_GNUC_CONST; const gchar *gpk_restart_enum_to_localised_text_future(PkRestartEnum restart) G_GNUC_CONST; const gchar *gpk_group_enum_to_localised_text (PkGroupEnum group) G_GNUC_CONST; const gchar *gpk_group_enum_to_icon_name (PkGroupEnum group); +gchar *gpk_update_enum_to_localised_text (PkInfoEnum info, + guint number) + G_GNUC_CONST; const gchar *gpk_info_status_enum_to_string (GpkInfoStatusEnum info); const gchar *gpk_info_status_enum_to_icon_name (GpkInfoStatusEnum info); Index: gnome-packagekit-3.20.0/src/gpk-error.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-error.c +++ gnome-packagekit-3.20.0/src/gpk-error.c @@ -58,7 +58,7 @@ gpk_error_dialog_expanded_cb (GObject *o * * Shows a modal error, and blocks until the user clicks close **/ -static gboolean +gboolean gpk_error_dialog_modal_with_time (GtkWindow *window, const gchar *title, const gchar *message, const gchar *details, guint timestamp) { GtkWidget *widget; Index: gnome-packagekit-3.20.0/src/gpk-error.h =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-error.h +++ gnome-packagekit-3.20.0/src/gpk-error.h @@ -33,6 +33,11 @@ gboolean gpk_error_dialog_modal (GtkW const gchar *title, const gchar *message, const gchar *details); +gboolean gpk_error_dialog_modal_with_time (GtkWindow *window, + const gchar *title, + const gchar *message, + const gchar *details, + guint timestamp); G_END_DECLS Index: gnome-packagekit-3.20.0/src/gpk-gnome.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-gnome.c @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib.h> +#include <gtk/gtk.h> +#include <string.h> + +#include "gpk-gnome.h" + +/** + * gpk_gnome_open: + * @url: a url such as <literal>http://www.hughsie.com</literal> + **/ +gboolean +gpk_gnome_open (const gchar *url) +{ + gboolean ret; + GError *error = NULL; + + g_return_val_if_fail (url != NULL, FALSE); + + ret = gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error); + + if (!ret) { + g_warning ("spawn of '%s' failed", url); + g_error_free (error); + } + return ret; +} Index: gnome-packagekit-3.20.0/src/gpk-gnome.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-gnome.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_GNOME_H +#define __GPK_GNOME_H + +#include <glib.h> + +G_BEGIN_DECLS + +gboolean gpk_gnome_open (const gchar *url); + +G_END_DECLS + +#endif /* __GPK_GNOME_H */ Index: gnome-packagekit-3.20.0/src/gpk-helper-chooser.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-helper-chooser.c @@ -0,0 +1,348 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <packagekit-glib2/packagekit.h> + +#include "gpk-helper-chooser.h" +#include "gpk-marshal.h" +#include "gpk-gnome.h" +#include "gpk-common.h" +#include "gpk-enum.h" + +static void gpk_helper_chooser_finalize (GObject *object); + +#define GPK_HELPER_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserPrivate)) + +struct GpkHelperChooserPrivate +{ + GtkBuilder *builder; + gchar *package_id; + GtkListStore *list_store; +}; + +enum { + GPK_HELPER_CHOOSER_EVENT, + GPK_HELPER_CHOOSER_LAST_SIGNAL +}; + +enum { + GPK_CHOOSER_COLUMN_ICON, + GPK_CHOOSER_COLUMN_TEXT, + GPK_CHOOSER_COLUMN_ID, + GPK_CHOOSER_COLUMN_LAST +}; + +static guint signals [GPK_HELPER_CHOOSER_LAST_SIGNAL] = { 0 }; +G_DEFINE_TYPE (GpkHelperChooser, gpk_helper_chooser, G_TYPE_OBJECT) + +/** + * gpk_helper_chooser_button_install_cb: + **/ +static void +gpk_helper_chooser_button_install_cb (GtkWidget *widget, GpkHelperChooser *helper) +{ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_widget_hide (widget); + g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_YES, helper->priv->package_id); +} + +/** + * gpk_helper_chooser_button_cancel_cb: + **/ +static void +gpk_helper_chooser_button_cancel_cb (GtkWidget *widget, GpkHelperChooser *helper) +{ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_widget_hide (widget); + g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_NO, helper->priv->package_id); +} + +/** + * gpk_helper_chooser_button_response_cb: + **/ +static void +gpk_helper_chooser_button_response_cb (GtkDialog *dialog, GtkResponseType response_id, GpkHelperChooser *helper) +{ + if (response_id == GTK_RESPONSE_DELETE_EVENT) { + gtk_widget_hide (GTK_WIDGET (dialog)); + g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_NO, helper->priv->package_id); + } +} + +/** + * gpk_helper_chooser_treeview_clicked_cb: + **/ +static void +gpk_helper_chooser_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperChooser *helper) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + /* This will only work in single or browse selection mode! */ + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + g_free (helper->priv->package_id); + gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_ID, &helper->priv->package_id, -1); + + /* show package_id */ + g_debug ("selected row is: %s", helper->priv->package_id); + } else { + g_debug ("no row selected"); + } +} + +/** + * pk_treeview_add_general_columns: + **/ +static void +pk_treeview_add_general_columns (GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL); + /* TRANSLATORS: column for the application icon */ + column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer, + "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL); + gtk_tree_view_append_column (treeview, column); + + /* column for text */ + renderer = gtk_cell_renderer_text_new (); + /* TRANSLATORS: column for the application name */ + column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer, + "markup", GPK_CHOOSER_COLUMN_TEXT, NULL); + gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT); + gtk_tree_view_append_column (treeview, column); + gtk_tree_view_column_set_expand (column, TRUE); +} + +/** + * gpk_helper_chooser_show: + * + * Return value: if we agreed + **/ +gboolean +gpk_helper_chooser_show (GpkHelperChooser *helper, GPtrArray *list) +{ + GtkWidget *widget; + gchar *text; + const gchar *icon_name; + guint i; + PkPackage *item; + GtkTreeIter iter; + PkInfoEnum info; + gchar *package_id = NULL; + gchar *summary = NULL; + + g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE); + g_return_val_if_fail (list != NULL, FALSE); + + /* see what we've got already */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + for (i=0; i<list->len; i++) { + item = g_ptr_array_index (list, i); + g_object_get (item, + "info", &info, + "package-id", &package_id, + "summary", &summary, + NULL); + g_debug ("package '%s' got:", package_id); + + /* put formatted text into treeview */ + gtk_list_store_append (helper->priv->list_store, &iter); + text = gpk_package_id_format_twoline (gtk_widget_get_style_context (widget), + package_id, + summary); + icon_name = gpk_info_enum_to_icon_name (info); + gtk_list_store_set (helper->priv->list_store, &iter, + GPK_CHOOSER_COLUMN_TEXT, text, + GPK_CHOOSER_COLUMN_ID, package_id, -1); + gtk_list_store_set (helper->priv->list_store, &iter, GPK_CHOOSER_COLUMN_ICON, icon_name, -1); + g_free (package_id); + g_free (summary); + g_free (text); + } + + /* show window */ + gtk_widget_show (widget); + + return TRUE; +} + +/** + * gpk_helper_chooser_set_parent: + **/ +gboolean +gpk_helper_chooser_set_parent (GpkHelperChooser *helper, GtkWindow *window) +{ + GtkWindow *widget; + + g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE); + g_return_val_if_fail (window != NULL, FALSE); + + /* make modal if window set */ + widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_window_set_transient_for (widget, window); + gtk_window_set_modal (widget, TRUE); + + /* this is a modal popup, so don't show a window title */ + gtk_window_set_title (widget, ""); + + return TRUE; +} + +/** + * gpk_helper_chooser_class_init: + * @klass: The GpkHelperChooserClass + **/ +static void +gpk_helper_chooser_class_init (GpkHelperChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_helper_chooser_finalize; + g_type_class_add_private (klass, sizeof (GpkHelperChooserPrivate)); + signals [GPK_HELPER_CHOOSER_EVENT] = + g_signal_new ("event", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkHelperChooserClass, event), + NULL, NULL, gpk_marshal_VOID__UINT_STRING, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); +} + +/** + * gpk_helper_chooser_init: + **/ +static void +gpk_helper_chooser_init (GpkHelperChooser *helper) +{ + GtkWidget *widget; + guint retval; + GError *error = NULL; + GtkWidget *button; + GtkTreeSelection *selection; + + helper->priv = GPK_HELPER_CHOOSER_GET_PRIVATE (helper); + + helper->priv->package_id = NULL; + + /* get UI */ + helper->priv->builder = gtk_builder_new (); + retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error); + if (retval == 0) { + g_warning ("failed to load ui: %s", error->message); + g_error_free (error); + } + + /* connect up default actions */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + g_signal_connect (GTK_DIALOG (widget), "response", G_CALLBACK (gpk_helper_chooser_button_response_cb), helper); + + /* set icon name */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER); + gtk_window_set_title (GTK_WINDOW (widget), _("Applications that can open this type of file")); + + /* set a size, if the screen allows */ + gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300); + + /* connect up buttons */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close")); + g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_chooser_button_cancel_cb), helper); + + /* TRANSLATORS: button label, install */ + button = gtk_button_new_with_mnemonic (_("_Install")); + g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_chooser_button_install_cb), helper); + + /* TRANSLATORS: button tooltip */ + gtk_widget_set_tooltip_text (button, _("Install package")); + + /* add to box */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + widget = gtk_dialog_get_action_area (GTK_DIALOG(widget)); + gtk_box_pack_start (GTK_BOX (widget), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + /* hide the filter box */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter")); + gtk_widget_hide (widget); + + /* hide the refresh button */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh")); + gtk_widget_hide (widget); + + /* create list stores */ + helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + /* create package_id tree view */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (helper->priv->list_store)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + g_signal_connect (selection, "changed", + G_CALLBACK (gpk_helper_chooser_treeview_clicked_cb), helper); + + /* add columns to the tree view */ + pk_treeview_add_general_columns (GTK_TREE_VIEW (widget)); + gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE); +} + +/** + * gpk_helper_chooser_finalize: + **/ +static void +gpk_helper_chooser_finalize (GObject *object) +{ + GtkWidget *widget; + GpkHelperChooser *helper; + + g_return_if_fail (GPK_IS_HELPER_CHOOSER (object)); + + helper = GPK_HELPER_CHOOSER (object); + + /* hide window */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + if (GTK_IS_WIDGET (widget)) + gtk_widget_hide (widget); + g_free (helper->priv->package_id); + g_object_unref (helper->priv->builder); + + G_OBJECT_CLASS (gpk_helper_chooser_parent_class)->finalize (object); +} + +/** + * gpk_helper_chooser_new: + **/ +GpkHelperChooser * +gpk_helper_chooser_new (void) +{ + GpkHelperChooser *helper; + helper = g_object_new (GPK_TYPE_HELPER_CHOOSER, NULL); + return GPK_HELPER_CHOOSER (helper); +} + Index: gnome-packagekit-3.20.0/src/gpk-helper-chooser.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-helper-chooser.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_HELPER_CHOOSER_H +#define __GPK_HELPER_CHOOSER_H + +#include <glib-object.h> +#include <gtk/gtk.h> +#include <packagekit-glib2/packagekit.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_HELPER_CHOOSER (gpk_helper_chooser_get_type ()) +#define GPK_HELPER_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooser)) +#define GPK_HELPER_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass)) +#define GPK_IS_HELPER_CHOOSER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_CHOOSER)) +#define GPK_IS_HELPER_CHOOSER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_CHOOSER)) +#define GPK_HELPER_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass)) +#define GPK_HELPER_CHOOSER_ERROR (gpk_helper_chooser_error_quark ()) +#define GPK_HELPER_CHOOSER_TYPE_ERROR (gpk_helper_chooser_error_get_type ()) + +typedef struct GpkHelperChooserPrivate GpkHelperChooserPrivate; + +typedef struct +{ + GObject parent; + GpkHelperChooserPrivate *priv; +} GpkHelperChooser; + +typedef struct +{ + void (* event) (GpkHelperChooser *helper, + GtkResponseType type, + const gchar *package_id); + GObjectClass parent_class; +} GpkHelperChooserClass; + +GType gpk_helper_chooser_get_type (void); +GpkHelperChooser *gpk_helper_chooser_new (void); +gboolean gpk_helper_chooser_set_parent (GpkHelperChooser *helper, + GtkWindow *window); +gboolean gpk_helper_chooser_show (GpkHelperChooser *helper, + GPtrArray *list); + +G_END_DECLS + +#endif /* __GPK_HELPER_CHOOSER_H */ Index: gnome-packagekit-3.20.0/src/gpk-helper-run.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-helper-run.c @@ -0,0 +1,392 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <packagekit-glib2/packagekit.h> +#include <gio/gdesktopappinfo.h> + +#include "gpk-helper-run.h" +#include "gpk-marshal.h" +#include "gpk-gnome.h" +#include "gpk-common.h" +#include "gpk-enum.h" + +static void gpk_helper_run_finalize (GObject *object); + +#define GPK_HELPER_RUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunPrivate)) + +struct GpkHelperRunPrivate +{ + GtkBuilder *builder; + GtkListStore *list_store; +}; + +enum { + GPK_CHOOSER_COLUMN_ICON, + GPK_CHOOSER_COLUMN_TEXT, + GPK_CHOOSER_COLUMN_FILENAME, + GPK_CHOOSER_COLUMN_LAST +}; + +G_DEFINE_TYPE (GpkHelperRun, gpk_helper_run, G_TYPE_OBJECT) + +/** + * gpk_helper_run_path: + **/ +static gboolean +gpk_helper_run_path (GpkHelperRun *helper, const gchar *filename) +{ + gboolean ret = FALSE; + GError *error = NULL; + GAppInfo *app = NULL; + + /* check have value */ + if (filename == NULL) { + g_warning ("no full path"); + goto out; + } + + /* launch application */ + app = G_APP_INFO(g_desktop_app_info_new_from_filename (filename)); + ret = g_app_info_launch (app, NULL, NULL, &error); + if (!ret) { + g_warning ("failed to launch: %s", error->message); + g_error_free (error); + } +out: + if (app != NULL) + g_object_unref (app); + return ret; +} + +/** + * gpk_helper_run_button_run_cb: + **/ +static void +gpk_helper_run_button_run_cb (GtkWidget *widget, GpkHelperRun *helper) +{ + GtkTreeView *treeview; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeSelection *selection; + gboolean ret; + gchar *filename; + + /* get selection */ + treeview = GTK_TREE_VIEW (gtk_builder_get_object (helper->priv->builder, "treeview_simple")); + selection = gtk_tree_view_get_selection (treeview); + ret = gtk_tree_selection_get_selected (selection, &model, &iter); + if (!ret) { + g_warning ("failed to get selection"); + return; + } + + gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1); + gpk_helper_run_path (helper, filename); + g_free (filename); +} + +/** + * gpk_helper_run_button_close_cb: + **/ +static void +gpk_helper_run_button_close_cb (GtkWidget *widget, GpkHelperRun *helper) +{ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_widget_hide (widget); +} + +/** + * gpk_helper_run_delete_event_cb: + **/ +static gboolean +gpk_helper_run_delete_event_cb (GtkWidget *widget, GdkEvent *event, GpkHelperRun *helper) +{ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_widget_hide (widget); + return FALSE; +} + +/** + * gpk_helper_run_treeview_clicked_cb: + **/ +static void +gpk_helper_run_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperRun *helper) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gchar *filename = NULL; + + /* This will only work in single or browse selection mode! */ + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + g_free (filename); + gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1); + + /* show full path */ + g_debug ("selected row is: %s", filename); + } else { + g_debug ("no row selected"); + } + g_free (filename); +} + +/** + * gpk_helper_run_row_activated_cb: + **/ +static void +gpk_helper_run_row_activated_cb (GtkTreeView *treeview, GtkTreePath *path, + GtkTreeViewColumn *col, GpkHelperRun *helper) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean ret; + gchar *filename; + + /* get selection */ + model = gtk_tree_view_get_model (treeview); + ret = gtk_tree_model_get_iter (model, &iter, path); + if (!ret) { + g_warning ("failed to get selection"); + return; + } + + gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1); + gpk_helper_run_path (helper, filename); + g_free (filename); +} + +/** + * pk_treeview_add_general_columns: + **/ +static void +pk_treeview_add_general_columns (GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* image */ + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL); + /* TRANSLATORS: column for the application icon */ + column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer, + "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL); + gtk_tree_view_append_column (treeview, column); + + /* column for text */ + renderer = gtk_cell_renderer_text_new (); + /* TRANSLATORS: column for the package name */ + column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer, + "markup", GPK_CHOOSER_COLUMN_TEXT, NULL); + gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT); + gtk_tree_view_append_column (treeview, column); + gtk_tree_view_column_set_expand (column, TRUE); +} + +/** + * gpk_helper_run_add_package_ids: + **/ +static guint +gpk_helper_run_add_package_ids (GpkHelperRun *helper, gchar **package_ids) +{ + return 0; +} + +/** + * gpk_helper_run_show: + * + * Return value: if we agreed + **/ +gboolean +gpk_helper_run_show (GpkHelperRun *helper, gchar **package_ids) +{ + GtkWidget *widget; + guint len; + + g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE); + g_return_val_if_fail (package_ids != NULL, FALSE); + + /* clear old list */ + gtk_list_store_clear (helper->priv->list_store); + + /* add all the apps */ + len = gpk_helper_run_add_package_ids (helper, package_ids); + if (len == 0) { + g_debug ("no executable file for %s", package_ids[0]); + goto out; + } + + /* show window */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_widget_show (widget); +out: + return TRUE; +} + +/** + * gpk_helper_run_set_parent: + **/ +gboolean +gpk_helper_run_set_parent (GpkHelperRun *helper, GtkWindow *window) +{ + GtkWindow *widget; + + g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE); + g_return_val_if_fail (window != NULL, FALSE); + + /* make modal if window set */ + widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_window_set_transient_for (widget, window); + gtk_window_set_modal (widget, TRUE); + + /* this is a modal popup */ + gtk_window_set_type_hint (widget, GDK_WINDOW_TYPE_HINT_DIALOG); + + return TRUE; +} + +/** + * gpk_helper_run_class_init: + * @klass: The GpkHelperRunClass + **/ +static void +gpk_helper_run_class_init (GpkHelperRunClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_helper_run_finalize; + g_type_class_add_private (klass, sizeof (GpkHelperRunPrivate)); +} + +/** + * gpk_helper_run_init: + **/ +static void +gpk_helper_run_init (GpkHelperRun *helper) +{ + GtkWidget *widget; + GtkWidget *button; + guint retval; + GError *error = NULL; + GtkTreeSelection *selection; + GtkBox *box; + + helper->priv = GPK_HELPER_RUN_GET_PRIVATE (helper); + + /* get UI */ + helper->priv->builder = gtk_builder_new (); + retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error); + if (retval == 0) { + g_warning ("failed to load ui: %s", error->message); + g_error_free (error); + } + + /* connect up default actions */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_helper_run_delete_event_cb), helper); + + /* set icon name */ + gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER); + + /* set a size, if the screen allows */ + gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300); + + /* connect up buttons */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close")); + g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_run_button_close_cb), helper); + + /* hide the filter box */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter")); + gtk_widget_hide (widget); + + /* hide the refresh button */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh")); + gtk_widget_hide (widget); + + /* set icon name */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER); + /* TRANSLATORS: window title: do we want to execute a program we just installed? */ + gtk_window_set_title (GTK_WINDOW (widget), _("Run new application?")); + + /* add run button */ + button = gtk_button_new_with_mnemonic (_("_Run")); + box = GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (widget))); + gtk_box_pack_start (box, button, FALSE, FALSE, 0); + gtk_widget_show (button); + g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_run_button_run_cb), helper); + + /* create list stores */ + helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + /* create package_id tree view */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple")); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), + GTK_TREE_MODEL (helper->priv->list_store)); + g_signal_connect (GTK_TREE_VIEW (widget), "row-activated", + G_CALLBACK (gpk_helper_run_row_activated_cb), helper); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + g_signal_connect (selection, "changed", + G_CALLBACK (gpk_helper_run_treeview_clicked_cb), helper); + + /* add columns to the tree view */ + pk_treeview_add_general_columns (GTK_TREE_VIEW (widget)); + gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget)); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE); +} + +/** + * gpk_helper_run_finalize: + **/ +static void +gpk_helper_run_finalize (GObject *object) +{ + GtkWidget *widget; + GpkHelperRun *helper; + + g_return_if_fail (GPK_IS_HELPER_RUN (object)); + + helper = GPK_HELPER_RUN (object); + + /* hide window */ + widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple")); + if (GTK_IS_WIDGET (widget)) + gtk_widget_hide (widget); + g_object_unref (helper->priv->builder); + g_object_unref (helper->priv->list_store); + + G_OBJECT_CLASS (gpk_helper_run_parent_class)->finalize (object); +} + +/** + * gpk_helper_run_new: + **/ +GpkHelperRun * +gpk_helper_run_new (void) +{ + GpkHelperRun *helper; + helper = g_object_new (GPK_TYPE_HELPER_RUN, NULL); + return GPK_HELPER_RUN (helper); +} + Index: gnome-packagekit-3.20.0/src/gpk-helper-run.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-helper-run.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_HELPER_RUN_H +#define __GPK_HELPER_RUN_H + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_HELPER_RUN (gpk_helper_run_get_type ()) +#define GPK_HELPER_RUN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_RUN, GpkHelperRun)) +#define GPK_HELPER_RUN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_RUN, GpkHelperRunClass)) +#define GPK_IS_HELPER_RUN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_RUN)) +#define GPK_IS_HELPER_RUN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_RUN)) +#define GPK_HELPER_RUN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunClass)) +#define GPK_HELPER_RUN_ERROR (gpk_helper_run_error_quark ()) +#define GPK_HELPER_RUN_TYPE_ERROR (gpk_helper_run_error_get_type ()) + +typedef struct GpkHelperRunPrivate GpkHelperRunPrivate; + +typedef struct +{ + GObject parent; + GpkHelperRunPrivate *priv; +} GpkHelperRun; + +typedef struct +{ + GObjectClass parent_class; +} GpkHelperRunClass; + +GType gpk_helper_run_get_type (void); +GpkHelperRun *gpk_helper_run_new (void); +gboolean gpk_helper_run_set_parent (GpkHelperRun *helper, + GtkWindow *window); +gboolean gpk_helper_run_show (GpkHelperRun *helper, + gchar **package_ids); + +G_END_DECLS + +#endif /* __GPK_HELPER_RUN_H */ Index: gnome-packagekit-3.20.0/src/gpk-install-local-file.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-install-local-file.c @@ -0,0 +1,139 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <locale.h> +#include <dbus/dbus-glib.h> + +#include "gpk-common.h" +#include "gpk-error.h" +#include "gpk-dbus.h" +#include "gpk-debug.h" + +/** + * main: + **/ +int +main (int argc, char *argv[]) +{ + GOptionContext *context; + gboolean ret; + GError *error = NULL; + gchar **files = NULL; + gchar *tmp; + gchar *current_dir; + guint i; + DBusGConnection *connection; + DBusGProxy *proxy = NULL; + + const GOptionEntry options[] = { + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &files, + /* TRANSLATORS: command line option: a list of files to install */ + _("Files to install"), NULL }, + { NULL} + }; + + setlocale (LC_ALL, ""); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + /* TRANSLATORS: program name: application to install a package to provide a file */ + g_set_application_name (_("Software Install")); + context = g_option_context_new ("gpk-install-local-file"); + g_option_context_set_summary (context, _("PackageKit File Installer")); + g_option_context_add_main_entries (context, options, NULL); + g_option_context_add_group (context, gpk_debug_get_option_group ()); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + /* TRANSLATORS: title to pass to to the user if there are not enough privs */ + ret = gpk_check_privileged_user (_("Local file installer"), TRUE); + if (!ret) + goto out; + + if (files == NULL) { + /* TRANSLATORS: could not install a package that contained the file we wanted */ + gpk_error_dialog (_("Failed to install a package to provide a file"), + /* TRANSLATORS: nothing selected */ + _("You need to specify a file to install"), NULL); + goto out; + } + + /* make sure we don't pass relative paths to the session-interface */ + /* (this is needed if install-local-files is executed from the command-line) */ + current_dir = g_get_current_dir (); + for (i = 0; files[i] != NULL; i++) { + if (!g_str_has_prefix (files[i], "/")) { + tmp = g_build_filename (current_dir, files[i], NULL); + g_free (files[i]); + files[i] = tmp; + } + } + g_free (current_dir); + + /* check dbus connections, exit if not valid */ + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) { + g_warning ("%s", error->message); + goto out; + } + + /* get a connection */ + proxy = dbus_g_proxy_new_for_name (connection, + "org.freedesktop.PackageKit", + "/org/freedesktop/PackageKit", + "org.freedesktop.PackageKit.Modify"); + if (proxy == NULL) { + g_warning ("Cannot connect to session service"); + goto out; + } + + /* don't timeout, as dbus-glib sets the timeout ~25 seconds */ + dbus_g_proxy_set_default_timeout (proxy, INT_MAX); + + /* do method */ + ret = dbus_g_proxy_call (proxy, "InstallPackageFiles", &error, + G_TYPE_UINT, 0, /* xid */ + G_TYPE_STRV, files, /* data */ + G_TYPE_STRING, "hide-finished,show-warnings", /* interaction */ + G_TYPE_INVALID, + G_TYPE_INVALID); + if (!ret) { + g_warning ("%s", error->message); + goto out; + } +out: + if (error != NULL) + g_error_free (error); + if (proxy != NULL) + g_object_unref (proxy); + g_strfreev (files); + return !ret; +} Index: gnome-packagekit-3.20.0/src/gpk-language.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-language.c @@ -0,0 +1,196 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> +#include <glib.h> + +#include "gpk-language.h" + +static void gpk_language_finalize (GObject *object); + +#define GPK_LANGUAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_LANGUAGE, GpkLanguagePrivate)) + +struct GpkLanguagePrivate +{ + GHashTable *hash; +}; + +G_DEFINE_TYPE (GpkLanguage, gpk_language, G_TYPE_OBJECT) + +/** + * gpk_language_parser_start_element: + **/ +static void +gpk_language_parser_start_element (GMarkupParseContext *context, const gchar *element_name, + const gchar **attribute_names, const gchar **attribute_values, + gpointer user_data, GError **error) +{ + guint i, len; + const gchar *code1 = NULL; + const gchar *code2b = NULL; + const gchar *name = NULL; + GpkLanguage *language = user_data; + + if (strcmp (element_name, "iso_639_entry") != 0) + return; + + /* find data */ + len = g_strv_length ((gchar**)attribute_names); + for (i=0; i<len; i++) { + if (strcmp (attribute_names[i], "iso_639_1_code") == 0) + code1 = attribute_values[i]; + if (strcmp (attribute_names[i], "iso_639_2B_code") == 0) + code2b = attribute_values[i]; + if (strcmp (attribute_names[i], "name") == 0) + name = attribute_values[i]; + } + + /* not valid entry */ + if (name == NULL) + return; + + /* add both to hash */ + if (code1 != NULL) + g_hash_table_insert (language->priv->hash, g_strdup (code1), g_strdup (name)); + if (code2b != NULL) + g_hash_table_insert (language->priv->hash, g_strdup (code2b), g_strdup (name)); +} + +/* trivial parser */ +static const GMarkupParser gpk_language_markup_parser = +{ + gpk_language_parser_start_element, + NULL, /* end_element */ + NULL, /* characters */ + NULL, /* passthrough */ + NULL /* error */ +}; + +/** + * gpk_language_populate: + * + * <iso_639_entry iso_639_2B_code="hun" iso_639_2T_code="hun" iso_639_1_code="hu" name="Hungarian" /> + **/ +gboolean +gpk_language_populate (GpkLanguage *language, GError **error) +{ + gboolean ret = FALSE; + gchar *contents = NULL; + gchar *filename; + gsize size; + GMarkupParseContext *context = NULL; + + /* find filename */ + filename = g_build_filename (DATADIR, "xml", "iso-codes", "iso_639.xml", NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + g_free (filename); + filename = g_build_filename ("/usr", "share", "xml", "iso-codes", "iso_639.xml", NULL); + } + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + g_set_error (error, 1, 0, "cannot find source file : '%s'", filename); + goto out; + } + + /* get contents */ + ret = g_file_get_contents (filename, &contents, &size, error); + if (!ret) + goto out; + + /* create parser */ + context = g_markup_parse_context_new (&gpk_language_markup_parser, G_MARKUP_PREFIX_ERROR_POSITION, language, NULL); + + /* parse data */ + ret = g_markup_parse_context_parse (context, contents, (gssize) size, error); + if (!ret) + goto out; +out: + if (context != NULL) + g_markup_parse_context_free (context); + g_free (filename); + g_free (contents); + return ret; +} + +/** + * gpk_language_iso639_to_language: + **/ +gchar * +gpk_language_iso639_to_language (GpkLanguage *language, const gchar *iso639) +{ + return g_strdup (g_hash_table_lookup (language->priv->hash, iso639)); +} + +/** + * gpk_language_finalize: + * @object: The object to finalize + **/ +static void +gpk_language_finalize (GObject *object) +{ + GpkLanguage *language; + + g_return_if_fail (GPK_IS_LANGUAGE (object)); + + language = GPK_LANGUAGE (object); + + g_return_if_fail (language->priv != NULL); + g_hash_table_unref (language->priv->hash); + + G_OBJECT_CLASS (gpk_language_parent_class)->finalize (object); +} + +/** + * gpk_language_init: + * @language: This class instance + **/ +static void +gpk_language_init (GpkLanguage *language) +{ + language->priv = GPK_LANGUAGE_GET_PRIVATE (language); + language->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); +} + +/** + * gpk_language_class_init: + * @klass: The GpkLanguageClass + **/ +static void +gpk_language_class_init (GpkLanguageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_language_finalize; + g_type_class_add_private (klass, sizeof (GpkLanguagePrivate)); +} + +/** + * gpk_language_new: + * + * Return value: a new GpkLanguage object. + **/ +GpkLanguage * +gpk_language_new (void) +{ + GpkLanguage *language; + language = g_object_new (GPK_TYPE_LANGUAGE, NULL); + return GPK_LANGUAGE (language); +} Index: gnome-packagekit-3.20.0/src/gpk-language.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-language.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_LANGUAGE_H +#define __GPK_LANGUAGE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_LANGUAGE (gpk_language_get_type ()) +#define GPK_LANGUAGE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_LANGUAGE, GpkLanguage)) +#define GPK_LANGUAGE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_LANGUAGE, GpkLanguageClass)) +#define GPK_IS_LANGUAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_LANGUAGE)) +#define GPK_IS_LANGUAGE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_LANGUAGE)) +#define GPK_LANGUAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_LANGUAGE, GpkLanguageClass)) +#define GPK_LANGUAGE_ERROR (gpk_language_error_quark ()) +#define GPK_LANGUAGE_TYPE_ERROR (gpk_language_error_get_type ()) + +typedef struct GpkLanguagePrivate GpkLanguagePrivate; + +typedef struct +{ + GObject parent; + GpkLanguagePrivate *priv; +} GpkLanguage; + +typedef struct +{ + GObjectClass parent_class; +} GpkLanguageClass; + +GType gpk_language_get_type (void); +GpkLanguage *gpk_language_new (void); +gboolean gpk_language_populate (GpkLanguage *language, + GError **error); +gchar *gpk_language_iso639_to_language (GpkLanguage *language, + const gchar *iso639); + +G_END_DECLS + +#endif /* __GPK_LANGUAGE_H */ Index: gnome-packagekit-3.20.0/src/gpk-log.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-log.c +++ gnome-packagekit-3.20.0/src/gpk-log.c @@ -32,6 +32,7 @@ #include <packagekit-glib2/packagekit.h> #include "gpk-common.h" +#include "gpk-gnome.h" #include "gpk-debug.h" static GtkBuilder *builder = NULL; Index: gnome-packagekit-3.20.0/src/gpk-marshal.list =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-marshal.list @@ -0,0 +1,3 @@ +VOID:UINT,STRING +VOID:UINT,STRING,STRING + Index: gnome-packagekit-3.20.0/src/gpk-modal-dialog.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-modal-dialog.c @@ -0,0 +1,861 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <signal.h> + +#include <string.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#include <sys/wait.h> +#include <fcntl.h> +#include <glib/gi18n.h> +#include <packagekit-glib2/packagekit.h> + +#include "egg-string.h" + +#include "gpk-animated-icon.h" +#include "gpk-modal-dialog.h" +#include "gpk-common.h" +#include "gpk-gnome.h" +#include "gpk-enum.h" + +static void gpk_modal_dialog_finalize (GObject *object); + +#define GPK_MODAL_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogPrivate)) + +struct _GpkModalDialogPrivate +{ + GtkBuilder *builder; + guint pulse_timer_id; + gboolean show_progress_files; + gboolean has_parent; + GMainLoop *loop; + GtkResponseType response; + GtkListStore *store; + gchar *title; + gboolean set_image; + GpkModalDialogPage page; + PkBitfield options; + GtkWidget *image_status; +}; + +enum { + GPK_MODAL_DIALOG_CLOSE, + GPK_MODAL_DIALOG_QUIT, + GPK_MODAL_DIALOG_ACTION, + GPK_MODAL_DIALOG_CANCEL, + LAST_SIGNAL +}; + +enum { + GPK_MODAL_DIALOG_STORE_IMAGE, + GPK_MODAL_DIALOG_STORE_ID, + GPK_MODAL_DIALOG_STORE_TEXT, + GPK_MODAL_DIALOG_STORE_LAST +}; + +static guint signals [LAST_SIGNAL] = { 0 }; +G_DEFINE_TYPE (GpkModalDialog, gpk_modal_dialog, G_TYPE_OBJECT) + +/** + * gpk_modal_dialog_show_widget: + **/ +static void +gpk_modal_dialog_show_widget (GpkModalDialog *dialog, const gchar *name, gboolean enabled) +{ + GtkWidget *widget; + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, name)); + if (enabled) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); +} + +/** + * gpk_modal_dialog_setup: + **/ +gboolean +gpk_modal_dialog_setup (GpkModalDialog *dialog, GpkModalDialogPage page, PkBitfield options) +{ + GtkLabel *label; + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + /* reset state */ + dialog->priv->set_image = FALSE; + dialog->priv->page = page; + dialog->priv->options = options; + label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message")); + gtk_label_set_label (label, ""); + gpk_modal_dialog_set_action (dialog, NULL); + return TRUE; +} + +/** + * gpk_modal_dialog_present_with_time: + **/ +gboolean +gpk_modal_dialog_present_with_time (GpkModalDialog *dialog, guint32 timestamp) +{ + GtkWidget *widget; + PkBitfield bitfield = 0; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_title")); + gtk_widget_show (widget); + gtk_widget_show (dialog->priv->image_status); + /* helper */ + if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) { + if (!dialog->priv->set_image) + gpk_modal_dialog_set_image (dialog, "dialog-question"); + bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL, + GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION, + GPK_MODAL_DIALOG_WIDGET_MESSAGE, + -1); + gpk_modal_dialog_set_allow_cancel (dialog, TRUE); + } else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_FINISHED) { + if (!dialog->priv->set_image) + gpk_modal_dialog_set_image (dialog, "dialog-information"); + bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE, + GPK_MODAL_DIALOG_WIDGET_MESSAGE, + -1); + } else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) { + if (!dialog->priv->set_image) + gpk_modal_dialog_set_image (dialog, "dialog-question"); + bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE, + GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION, + GPK_MODAL_DIALOG_WIDGET_MESSAGE, + -1); + } else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_WARNING) { + if (!dialog->priv->set_image) + gpk_modal_dialog_set_image (dialog, "dialog-warning"); + bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE, + GPK_MODAL_DIALOG_WIDGET_MESSAGE, + -1); + } else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_PROGRESS) { + if (!dialog->priv->set_image) + gpk_modal_dialog_set_image (dialog, "dialog-warning"); + bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE, + GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL, + GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR, + -1); + } + + /* we can specify extras */ + bitfield += dialog->priv->options; + + gpk_modal_dialog_show_widget (dialog, "button_cancel", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL)); + gpk_modal_dialog_show_widget (dialog, "button_close", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE)); + gpk_modal_dialog_show_widget (dialog, "button_action", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION)); + gpk_modal_dialog_show_widget (dialog, "progressbar_percent", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR)); + gpk_modal_dialog_show_widget (dialog, "label_message", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_MESSAGE)); + gpk_modal_dialog_show_widget (dialog, "scrolledwindow_packages", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST)); + gpk_modal_dialog_show_widget (dialog, "label_force_height", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PADDING)); + + /* always force width */ + gpk_modal_dialog_show_widget (dialog, "label_force_width", TRUE); + + /* show */ + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_widget_realize (widget); + gtk_window_present_with_time (GTK_WINDOW (widget), timestamp); + + return TRUE; +} + +/** + * gpk_modal_dialog_present: + **/ +gboolean +gpk_modal_dialog_present (GpkModalDialog *dialog) +{ + return gpk_modal_dialog_present_with_time (dialog, 0); +} + +/** + * gpk_modal_dialog_set_parent: + **/ +gboolean +gpk_modal_dialog_set_parent (GpkModalDialog *dialog, GdkWindow *window) +{ + GtkWidget *widget; + GdkWindow *window_ours; + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + /* never set, and nothing now */ + if (window == NULL && !dialog->priv->has_parent) + return TRUE; + + /* not sure what to do here, should probably unparent somehow */ + if (window == NULL) { + g_warning ("parent set NULL when already modal with another window, setting non-modal"); + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_window_set_modal (GTK_WINDOW (widget), FALSE); + dialog->priv->has_parent = FALSE; + + /* use the saved title if it exists */ + if (dialog->priv->title != NULL) + gpk_modal_dialog_set_title (dialog, dialog->priv->title); + + return FALSE; + } + + /* check we are a valid window */ + if (!GDK_WINDOW (window)) { + g_warning ("not a valid GdkWindow!"); + return FALSE; + } + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_widget_realize (widget); + gtk_window_set_modal (GTK_WINDOW (widget), TRUE); + window_ours = gtk_widget_get_window (widget); + gdk_window_set_transient_for (window_ours, window); + dialog->priv->has_parent = TRUE; + return TRUE; +} + +/** + * gpk_modal_dialog_set_window_title: + **/ +static gboolean +gpk_modal_dialog_set_window_title (GpkModalDialog *dialog, const gchar *title) +{ + GtkWindow *window; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (title != NULL, FALSE); + + g_debug ("setting window title: %s", title); + window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_window_set_title (window, title); + return TRUE; +} + +/** + * gpk_modal_dialog_set_window_icon: + **/ +gboolean +gpk_modal_dialog_set_window_icon (GpkModalDialog *dialog, const gchar *icon) +{ + GtkWindow *window; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (icon != NULL, FALSE); + + g_debug ("setting window icon: %s", icon); + window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_window_set_icon_name (window, icon); + return TRUE; +} + +/** + * gpk_modal_dialog_set_title: + **/ +gboolean +gpk_modal_dialog_set_title (GpkModalDialog *dialog, const gchar *title) +{ + GtkLabel *label; + GtkWidget *widget; + gchar *title_bold; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (title != NULL, FALSE); + + /* only set the window title if we are non-modal */ + if (!dialog->priv->has_parent) { + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, + "dialog_client")); + gtk_window_set_modal (GTK_WINDOW (widget), FALSE); + } + + /* we save this in case we are non-modal and have to use a title */ + g_free (dialog->priv->title); + dialog->priv->title = g_strdup (title); + + title_bold = g_strdup_printf ("<b><big>%s</big></b>", title); + g_debug ("setting title: %s", title_bold); + label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_title")); + gtk_label_set_markup (label, title_bold); + g_free (title_bold); + return TRUE; +} + +/** + * gpk_modal_dialog_set_message: + **/ +gboolean +gpk_modal_dialog_set_message (GpkModalDialog *dialog, const gchar *message) +{ + GtkLabel *label; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + /* ignore this if it's uninteresting */ + if (!dialog->priv->show_progress_files) + return FALSE; + + g_debug ("setting message: %s", message); + label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message")); + gtk_label_set_markup (label, message); + return TRUE; +} + +/** + * gpk_modal_dialog_set_action: + **/ +gboolean +gpk_modal_dialog_set_action (GpkModalDialog *dialog, const gchar *action) +{ + GtkWidget *widget; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + g_debug ("setting action: %s", action); + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action")); + if (action != NULL) + gtk_button_set_label (GTK_BUTTON (widget), action); + else + gtk_widget_hide (widget); + return TRUE; +} + +/** + * gpk_modal_dialog_pulse_progress: + **/ +static gboolean +gpk_modal_dialog_pulse_progress (GpkModalDialog *dialog) +{ + GtkWidget *widget; + static guint rate_limit = 0; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + /* debug so we can catch polling */ + if (rate_limit++ % 20 == 0) + g_debug ("polling check"); + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent")); + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget)); + return TRUE; +} + +/** + * gpk_modal_dialog_make_progressbar_pulse: + **/ +static void +gpk_modal_dialog_make_progressbar_pulse (GpkModalDialog *dialog) +{ + GtkProgressBar *progress_bar; + if (dialog->priv->pulse_timer_id == 0) { + progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent")); + gtk_progress_bar_set_pulse_step (progress_bar, 0.04); + dialog->priv->pulse_timer_id = g_timeout_add (75, (GSourceFunc) gpk_modal_dialog_pulse_progress, dialog); + g_source_set_name_by_id (dialog->priv->pulse_timer_id, "[GpkModalDialog] pulse"); + } +} + +/** + * gpk_modal_dialog_set_percentage: + **/ +gboolean +gpk_modal_dialog_set_percentage (GpkModalDialog *dialog, gint percentage) +{ + GtkProgressBar *progress_bar; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (percentage <= 100, FALSE); + + g_debug ("setting percentage: %u", percentage); + + progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent")); + if (dialog->priv->pulse_timer_id != 0) { + g_source_remove (dialog->priv->pulse_timer_id); + dialog->priv->pulse_timer_id = 0; + } + + /* either pulse or set percentage */ + if (percentage < 0) + gpk_modal_dialog_make_progressbar_pulse (dialog); + else + gtk_progress_bar_set_fraction (progress_bar, (gfloat) percentage / 100.0); + return TRUE; +} + +/** + * gpk_modal_dialog_set_remaining: + **/ +gboolean +gpk_modal_dialog_set_remaining (GpkModalDialog *dialog, guint remaining) +{ + GtkProgressBar *progress_bar; + gchar *timestring = NULL; + gchar *text = NULL; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + g_debug ("setting remaining: %u", remaining); + progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent")); + + /* unknown */ + if (remaining == 0) { + gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress_bar), ""); + goto out; + } + + /* get time text */ + timestring = gpk_time_to_imprecise_string (remaining); + text = g_strdup_printf (_("Remaining time: %s"), timestring); + gtk_progress_bar_set_text (progress_bar, text); +out: + g_free (timestring); + g_free (text); + return TRUE; +} + +/** + * gpk_modal_dialog_set_image: + **/ +gboolean +gpk_modal_dialog_set_image (GpkModalDialog *dialog, const gchar *image) +{ + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + g_return_val_if_fail (image != NULL, FALSE); + + /* set state */ + dialog->priv->set_image = TRUE; + + g_debug ("setting image: %s", image); + gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE); + gtk_image_set_from_icon_name (GTK_IMAGE (dialog->priv->image_status), image, GTK_ICON_SIZE_DIALOG); + return TRUE; +} + +/** + * gpk_modal_dialog_set_image_status: + **/ +gboolean +gpk_modal_dialog_set_image_status (GpkModalDialog *dialog, PkStatusEnum status) +{ + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + /* set state */ + dialog->priv->set_image = TRUE; + gpk_set_animated_icon_from_status (GPK_ANIMATED_ICON (dialog->priv->image_status), status, GTK_ICON_SIZE_DIALOG); + return TRUE; +} + +/** + * gpk_modal_dialog_get_window: + **/ +GtkWindow * +gpk_modal_dialog_get_window (GpkModalDialog *dialog) +{ + GtkWindow *window; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), NULL); + + window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + return window; +} + +/** + * gpk_modal_dialog_set_allow_cancel: + **/ +gboolean +gpk_modal_dialog_set_allow_cancel (GpkModalDialog *dialog, gboolean can_cancel) +{ + GtkWidget *widget; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel")); + gtk_widget_set_sensitive (widget, can_cancel); + + return TRUE; +} + +/** + * gpk_modal_dialog_run: + **/ +GtkResponseType +gpk_modal_dialog_run (GpkModalDialog *dialog) +{ + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + /* already running */ + if (g_main_loop_is_running (dialog->priv->loop)) + g_main_loop_quit (dialog->priv->loop); + + dialog->priv->response = GTK_RESPONSE_NONE; + g_main_loop_run (dialog->priv->loop); + + return dialog->priv->response; +} + +/** + * gpk_modal_dialog_close: + **/ +gboolean +gpk_modal_dialog_close (GpkModalDialog *dialog) +{ + GtkWidget *widget; + + g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE); + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + gtk_widget_hide (widget); + + if (dialog->priv->pulse_timer_id != 0) { + g_source_remove (dialog->priv->pulse_timer_id); + dialog->priv->pulse_timer_id = 0; + } + + gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE); + return TRUE; +} + +/** + * gpk_modal_dialog_window_delete_cb: + **/ +static gboolean +gpk_modal_dialog_window_delete_cb (GtkWidget *widget, GdkEvent *event, GpkModalDialog *dialog) +{ + dialog->priv->response = GTK_RESPONSE_DELETE_EVENT; + gpk_modal_dialog_close (dialog); + if (g_main_loop_is_running (dialog->priv->loop)) + g_main_loop_quit (dialog->priv->loop); + /* do not destroy the window */ + return TRUE; +} + +/** + * gpk_modal_dialog_button_close_cb: + **/ +static void +gpk_modal_dialog_button_close_cb (GtkWidget *widget_button, GpkModalDialog *dialog) +{ + dialog->priv->response = GTK_RESPONSE_CLOSE; + g_main_loop_quit (dialog->priv->loop); + + if (dialog->priv->pulse_timer_id != 0) { + g_source_remove (dialog->priv->pulse_timer_id); + dialog->priv->pulse_timer_id = 0; + } + + gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE); + if (g_main_loop_is_running (dialog->priv->loop)) + g_main_loop_quit (dialog->priv->loop); + else + g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CLOSE], 0); +} + +/** + * gpk_modal_dialog_button_action_cb: + **/ +static void +gpk_modal_dialog_button_action_cb (GtkWidget *widget_button, GpkModalDialog *dialog) +{ + dialog->priv->response = GTK_RESPONSE_OK; + g_main_loop_quit (dialog->priv->loop); + if (g_main_loop_is_running (dialog->priv->loop)) + g_main_loop_quit (dialog->priv->loop); + else + g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_ACTION], 0); +} + +/** + * gpk_modal_dialog_button_cancel_cb: + **/ +static void +gpk_modal_dialog_button_cancel_cb (GtkWidget *widget_button, GpkModalDialog *dialog) +{ + dialog->priv->response = GTK_RESPONSE_CANCEL; + if (g_main_loop_is_running (dialog->priv->loop)) + g_main_loop_quit (dialog->priv->loop); + else + g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CANCEL], 0); +} + +/** + * gpk_modal_dialog_set_package_list: + **/ +gboolean +gpk_modal_dialog_set_package_list (GpkModalDialog *dialog, const GPtrArray *list) +{ + GtkTreeIter iter; + PkPackage *item; + const gchar *icon; + gchar *text; + guint i; + GtkWidget *widget; + gchar **split; + PkInfoEnum info; + gchar *package_id = NULL; + gchar *summary = NULL; + + gtk_list_store_clear (dialog->priv->store); + + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "scrolledwindow_packages")); + if (list->len > 5) + gtk_widget_set_size_request (widget, -1, 300); + else if (list->len > 1) + gtk_widget_set_size_request (widget, -1, 150); + + /* add each well */ + for (i=0; i<list->len; i++) { + item = g_ptr_array_index (list, i); + g_object_get (item, + "info", &info, + NULL); + + /* not installed, so ignore icon */ + if (info == PK_INFO_ENUM_DOWNLOADING || + info == PK_INFO_ENUM_CLEANUP) + continue; + + g_object_get (item, + "package-id", &package_id, + "summary", &summary, + NULL); + + text = gpk_package_id_format_twoline (gtk_widget_get_style_context (widget), + package_id, summary); + + /* get the icon */ + split = pk_package_id_split (package_id); + icon = gpk_info_enum_to_icon_name (PK_INFO_ENUM_INSTALLED); + gtk_list_store_append (dialog->priv->store, &iter); + gtk_list_store_set (dialog->priv->store, &iter, + GPK_MODAL_DIALOG_STORE_IMAGE, icon, + GPK_MODAL_DIALOG_STORE_ID, package_id, + GPK_MODAL_DIALOG_STORE_TEXT, text, + -1); + g_strfreev (split); + g_free (package_id); + g_free (summary); + g_free (text); + } + + return TRUE; +} + +/** + * gpk_dialog_treeview_for_package_list: + **/ +static gboolean +gpk_dialog_treeview_for_package_list (GpkModalDialog *dialog) +{ + GtkTreeView *treeview; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + + treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages")); + + /* column for images */ + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DND, NULL); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, "icon-name", GPK_MODAL_DIALOG_STORE_IMAGE); + gtk_tree_view_append_column (treeview, column); + + /* column for name */ + renderer = gtk_cell_renderer_text_new (); + /* TRANSLATORS: column for the package name */ + column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer, + "markup", GPK_MODAL_DIALOG_STORE_TEXT, NULL); + gtk_tree_view_column_set_sort_column_id (column, GPK_MODAL_DIALOG_STORE_TEXT); + gtk_tree_view_append_column (treeview, column); + + /* set some common options */ + gtk_tree_view_set_headers_visible (treeview, FALSE); + selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); + gtk_tree_selection_unselect_all (selection); + + return TRUE; +} + +/** + * gpk_modal_dialog_class_init: + * @klass: The GpkModalDialogClass + **/ +static void +gpk_modal_dialog_class_init (GpkModalDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_modal_dialog_finalize; + g_type_class_add_private (klass, sizeof (GpkModalDialogPrivate)); + signals [GPK_MODAL_DIALOG_QUIT] = + g_signal_new ("quit", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [GPK_MODAL_DIALOG_CLOSE] = + g_signal_new ("close", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [GPK_MODAL_DIALOG_ACTION] = + g_signal_new ("action", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [GPK_MODAL_DIALOG_CANCEL] = + g_signal_new ("cancel", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * gpk_modal_dialog_init: + * @dialog: This class instance + **/ +static void +gpk_modal_dialog_init (GpkModalDialog *dialog) +{ + GtkWidget *widget; + GtkTreeView *treeview; + guint retval; + GError *error = NULL; + GtkBox *box; + + dialog->priv = GPK_MODAL_DIALOG_GET_PRIVATE (dialog); + + dialog->priv->loop = g_main_loop_new (NULL, FALSE); + dialog->priv->response = GTK_RESPONSE_NONE; + dialog->priv->pulse_timer_id = 0; + dialog->priv->show_progress_files = TRUE; + dialog->priv->has_parent = FALSE; + dialog->priv->set_image = FALSE; + dialog->priv->page = GPK_MODAL_DIALOG_PAGE_UNKNOWN; + dialog->priv->options = 0; + dialog->priv->title = NULL; + + dialog->priv->store = gtk_list_store_new (GPK_MODAL_DIALOG_STORE_LAST, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + /* get UI */ + dialog->priv->builder = gtk_builder_new (); + retval = gtk_builder_add_from_file (dialog->priv->builder, GPK_DATA "/gpk-client.ui", &error); + if (retval == 0) { + g_warning ("failed to load ui: %s", error->message); + g_error_free (error); + goto out_build; + } + + /* add animated widget */ + dialog->priv->image_status = gpk_animated_icon_new (); + box = GTK_BOX (gtk_builder_get_object (dialog->priv->builder, "hbox_status")); + gtk_box_pack_start (box, dialog->priv->image_status, FALSE, FALSE, 0); + gtk_widget_show (dialog->priv->image_status); + + gpk_dialog_treeview_for_package_list (dialog); + + treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages")); + gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (dialog->priv->store)); + + /* common stuff */ + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client")); + g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_modal_dialog_window_delete_cb), dialog); + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_close")); + g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_close_cb), dialog); + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action")); + g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_action_cb), dialog); + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel")); + g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_cancel_cb), dialog); + + /* set the message text an absolute width so it's forced to wrap */ + widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_message")); + gtk_label_set_max_width_chars (GTK_LABEL (widget), 80); + +out_build: + /* clear status and progress text */ + gpk_modal_dialog_set_window_title (dialog, ""); + gpk_modal_dialog_set_title (dialog, ""); + gpk_modal_dialog_set_message (dialog, ""); +} + +/** + * gpk_modal_dialog_finalize: + * @object: The object to finalize + **/ +static void +gpk_modal_dialog_finalize (GObject *object) +{ + GpkModalDialog *dialog; + g_return_if_fail (GPK_IS_CLIENT_DIALOG (object)); + + dialog = GPK_MODAL_DIALOG (object); + g_return_if_fail (dialog->priv != NULL); + + /* no updates, we're about to rip the builder up */ + if (dialog->priv->pulse_timer_id != 0) + g_source_remove (dialog->priv->pulse_timer_id); + + /* if it's closed, then hide */ + gpk_modal_dialog_close (dialog); + + /* shouldn't be, but just in case */ + if (g_main_loop_is_running (dialog->priv->loop)) { + g_warning ("mainloop running on exit"); + g_main_loop_quit (dialog->priv->loop); + } + + g_object_unref (dialog->priv->store); + g_object_unref (dialog->priv->builder); + g_main_loop_unref (dialog->priv->loop); + g_free (dialog->priv->title); + + G_OBJECT_CLASS (gpk_modal_dialog_parent_class)->finalize (object); +} + +/** + * gpk_modal_dialog_new: + * + * Return value: a new GpkModalDialog object. + **/ +GpkModalDialog * +gpk_modal_dialog_new (void) +{ + GpkModalDialog *dialog; + dialog = g_object_new (GPK_TYPE_CLIENT_DIALOG, NULL); + return GPK_MODAL_DIALOG (dialog); +} Index: gnome-packagekit-3.20.0/src/gpk-modal-dialog.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-modal-dialog.h @@ -0,0 +1,127 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_MODAL_DIALOG_H +#define __GPK_MODAL_DIALOG_H + +#include <glib-object.h> +#include <gtk/gtk.h> +#include <packagekit-glib2/packagekit.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_CLIENT_DIALOG (gpk_modal_dialog_get_type ()) +#define GPK_MODAL_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialog)) +#define GPK_MODAL_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass)) +#define GPK_IS_CLIENT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_CLIENT_DIALOG)) +#define GPK_IS_CLIENT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_CLIENT_DIALOG)) +#define GPK_MODAL_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass)) +#define GPK_MODAL_DIALOG_ERROR (gpk_modal_dialog_error_quark ()) +#define GPK_MODAL_DIALOG_TYPE_ERROR (gpk_modal_dialog_error_get_type ()) + +/** + * GpkModalDialogPage: + */ +typedef enum +{ + GPK_MODAL_DIALOG_PAGE_CONFIRM, + GPK_MODAL_DIALOG_PAGE_PROGRESS, + GPK_MODAL_DIALOG_PAGE_FINISHED, + GPK_MODAL_DIALOG_PAGE_WARNING, + GPK_MODAL_DIALOG_PAGE_CUSTOM, + GPK_MODAL_DIALOG_PAGE_UNKNOWN +} GpkModalDialogPage; + +/** + * GpkModalDialogWidgets: + */ +typedef enum +{ + GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL, + GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE, + GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION, + GPK_MODAL_DIALOG_WIDGET_PADDING, + GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST, + GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR, + GPK_MODAL_DIALOG_WIDGET_MESSAGE, + GPK_MODAL_DIALOG_WIDGET_UNKNOWN +} GpkModalDialogWidgets; + +/* helpers */ +#define GPK_MODAL_DIALOG_PACKAGE_PADDING pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_PADDING, GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1) +#define GPK_MODAL_DIALOG_PACKAGE_LIST pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST) +#define GPK_MODAL_DIALOG_BUTTON_ACTION pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION) + +typedef struct _GpkModalDialogPrivate GpkModalDialogPrivate; +typedef struct _GpkModalDialog GpkModalDialog; +typedef struct _GpkModalDialogClass GpkModalDialogClass; + +struct _GpkModalDialog +{ + GObject parent; + GpkModalDialogPrivate *priv; +}; + +struct _GpkModalDialogClass +{ + GObjectClass parent_class; +}; + +GQuark gpk_modal_dialog_error_quark (void); +GType gpk_modal_dialog_get_type (void); +GpkModalDialog *gpk_modal_dialog_new (void); + +gboolean gpk_modal_dialog_present (GpkModalDialog *dialog); +gboolean gpk_modal_dialog_present_with_time (GpkModalDialog *dialog, + guint32 timestamp); +gboolean gpk_modal_dialog_set_package_list (GpkModalDialog *dialog, + const GPtrArray *list); +gboolean gpk_modal_dialog_set_parent (GpkModalDialog *dialog, + GdkWindow *window); +gboolean gpk_modal_dialog_set_window_icon (GpkModalDialog *dialog, + const gchar *icon); +gboolean gpk_modal_dialog_set_title (GpkModalDialog *dialog, + const gchar *title); +gboolean gpk_modal_dialog_set_message (GpkModalDialog *dialog, + const gchar *message); +gboolean gpk_modal_dialog_set_action (GpkModalDialog *dialog, + const gchar *action); +gboolean gpk_modal_dialog_set_percentage (GpkModalDialog *dialog, + gint percentage); +gboolean gpk_modal_dialog_set_remaining (GpkModalDialog *dialog, + guint remaining); +gboolean gpk_modal_dialog_set_image (GpkModalDialog *dialog, + const gchar *image); +gboolean gpk_modal_dialog_set_image_status (GpkModalDialog *dialog, + PkStatusEnum status); +gboolean gpk_modal_dialog_set_allow_cancel (GpkModalDialog *dialog, + gboolean can_cancel); +GtkWindow *gpk_modal_dialog_get_window (GpkModalDialog *dialog); +GtkResponseType gpk_modal_dialog_run (GpkModalDialog *dialog); +gboolean gpk_modal_dialog_close (GpkModalDialog *dialog); +gboolean gpk_modal_dialog_setup (GpkModalDialog *dialog, + GpkModalDialogPage page, + PkBitfield options); + +G_END_DECLS + +#endif /* __GPK_MODAL_DIALOG_H */ + Index: gnome-packagekit-3.20.0/src/gpk-prefs.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-prefs.c +++ gnome-packagekit-3.20.0/src/gpk-prefs.c @@ -32,6 +32,7 @@ #include "gpk-debug.h" #include "gpk-enum.h" #include "gpk-error.h" +#include "gpk-gnome.h" typedef struct { const gchar *id_tmp; Index: gnome-packagekit-3.20.0/src/gpk-self-test.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-self-test.c +++ gnome-packagekit-3.20.0/src/gpk-self-test.c @@ -25,8 +25,12 @@ #include "egg-markdown.h" #include "gpk-common.h" +#include "gpk-dbus.h" +#include "gpk-dbus-task.h" #include "gpk-enum.h" #include "gpk-error.h" +#include "gpk-language.h" +#include "gpk-modal-dialog.h" #include "gpk-task.h" @@ -106,6 +110,15 @@ gpk_test_enum_func (void) } } + /* check we convert all the status animation enums */ + for (i = PK_STATUS_ENUM_UNKNOWN+1; i < PK_STATUS_ENUM_UNKNOWN; i++) { + string = gpk_status_enum_to_animation (i); + if (string == NULL || g_strcmp0 (string, "help-browser") == 0) { + g_warning ("failed to get %s", pk_status_enum_to_string (i)); + break; + } + } + /* check we convert all the info icon names enums */ for (i = PK_INFO_ENUM_UNKNOWN+1; i < PK_INFO_ENUM_LAST; i++) { string = gpk_info_enum_to_icon_name (i); @@ -199,6 +212,197 @@ gpk_test_enum_func (void) } static void +gpk_test_dbus_task_func (void) +{ + GpkDbusTask *dtask; + gchar *lang; + gchar *language; + gchar *package; + gboolean ret; +// const gchar *fonts[] = { ":lang=mn", NULL }; +// GError *error; + + /* get GpkDbusTask object */ + dtask = gpk_dbus_task_new (); + g_assert (dtask); + + /* convert tag to lang */ + lang = gpk_dbus_task_font_tag_to_lang (":lang=mn"); + g_assert_cmpstr (lang, ==, "mn"); + g_free (lang); + + /* convert tag to language */ + language = gpk_dbus_task_font_tag_to_localised_name (dtask, ":lang=mn"); + g_assert_cmpstr (language, ==, "Mongolian"); + g_free (language); + + /* test trusted path */ +// ret = gpk_dbus_task_path_is_trusted ("/usr/libexec/gst-install-plugins-helper"); +// g_assert (ret); + + /* test trusted path */ + ret = gpk_dbus_task_path_is_trusted ("/usr/bin/totem"); + g_assert (!ret); + + /* get package for exec */ + package = gpk_dbus_task_get_package_for_exec (dtask, "/usr/bin/totem"); + g_assert_cmpstr (package, ==, "totem"); + g_free (package); + + /* set exec */ + ret = gpk_dbus_task_set_exec (dtask, "/usr/bin/totem"); + g_assert (ret); +#if 0 + /* install fonts (no UI) */ + error = NULL; + gpk_dbus_task_set_interaction (dtask, GPK_CLIENT_INTERACT_NEVER); + ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* install fonts (if found) */ + error = NULL; + gpk_dbus_task_set_interaction (dtask, pk_bitfield_from_enums (GPK_CLIENT_INTERACT_CONFIRM_SEARCH, GPK_CLIENT_INTERACT_FINISHED, -1)); + ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* install fonts (always) */ + error = NULL; + gpk_dbus_task_set_interaction (dtask, GPK_CLIENT_INTERACT_ALWAYS); + ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error); + g_assert_no_error (error); + g_assert (ret); +#endif +} + +static void +gpk_test_modal_dialog_func (void) +{ + GtkResponseType button; + GpkModalDialog *dialog = NULL; + GPtrArray *array; + PkPackage *item; + gboolean ret; + + /* get GpkModalDialog object */ + dialog = gpk_modal_dialog_new (); + g_assert (dialog); + + /* set some packages */ + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + item = pk_package_new (); + ret = pk_package_set_id (item, "totem;001;i386;fedora", NULL); + g_assert (ret); + g_object_set (item, + "info", PK_INFO_ENUM_INSTALLED, + "summary", "Totem is a music player for GNOME", + NULL); + g_ptr_array_add (array, item); + item = pk_package_new (); + ret = pk_package_set_id (item, "totem;001;i386;fedora", NULL); + g_assert (ret); + g_object_set (item, + "info", PK_INFO_ENUM_AVAILABLE, + "summary", "Amarok is a music player for KDE", + NULL); + g_ptr_array_add (array, item); + gpk_modal_dialog_set_package_list (dialog, array); + g_ptr_array_unref (array); + + /* help button */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0); + gpk_modal_dialog_set_title (dialog, "Button press test"); + gpk_modal_dialog_set_message (dialog, "Please press close"); + gpk_modal_dialog_set_image (dialog, "dialog-warning"); + gpk_modal_dialog_present (dialog); + button = gpk_modal_dialog_run (dialog); + g_assert_cmpint (button, ==, GTK_RESPONSE_CLOSE); + + /* confirm button */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0); + gpk_modal_dialog_set_title (dialog, "Button press test with a really really long title"); + gpk_modal_dialog_set_message (dialog, "Please press Uninstall\n\nThis is a really really, really,\nreally long title <i>with formatting</i>"); + gpk_modal_dialog_set_image (dialog, "dialog-information"); + gpk_modal_dialog_set_action (dialog, "Uninstall"); + gpk_modal_dialog_present (dialog); + button = gpk_modal_dialog_run (dialog); + g_assert_cmpint (button, ==, GTK_RESPONSE_OK); + + /* no message */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0); + gpk_modal_dialog_set_title (dialog, "Refresh cache"); + gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_REFRESH_CACHE); + gpk_modal_dialog_set_percentage (dialog, -1); + gpk_modal_dialog_present (dialog); + gpk_modal_dialog_run (dialog); + + /* progress */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING); + gpk_modal_dialog_set_title (dialog, "Button press test"); + gpk_modal_dialog_set_message (dialog, "Please press cancel"); + gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_RUNNING); + gpk_modal_dialog_set_percentage (dialog, 50); + gpk_modal_dialog_present (dialog); + button = gpk_modal_dialog_run (dialog); + g_assert_cmpint (button, ==, GTK_RESPONSE_CANCEL); + + /* progress */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1)); + gpk_modal_dialog_set_title (dialog, "Button press test"); + gpk_modal_dialog_set_message (dialog, "Please press close"); + gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_INSTALL); + gpk_modal_dialog_set_percentage (dialog, -1); + gpk_modal_dialog_present (dialog); + button = gpk_modal_dialog_run (dialog); + g_assert_cmpint (button, ==, GTK_RESPONSE_CLOSE); + + /* confirm install button */ + gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST); + gpk_modal_dialog_set_title (dialog, "Button press test"); + gpk_modal_dialog_set_message (dialog, "Please press Install if you can see the package list"); + gpk_modal_dialog_set_image (dialog, "dialog-information"); + gpk_modal_dialog_set_action (dialog, "Install"); + gpk_modal_dialog_present (dialog); + button = gpk_modal_dialog_run (dialog); + g_assert_cmpint (button, ==, GTK_RESPONSE_OK); + + gpk_modal_dialog_close (dialog); + + g_object_unref (dialog); +} + +static void +gpk_test_language_func (void) +{ + gboolean ret; + gchar *lang; + GError *error = NULL; + GpkLanguage *language = NULL; + + /* get GpkLanguage object */ + language = gpk_language_new (); + g_assert (language != NULL); + + /* populate */ + ret = gpk_language_populate (language, &error); + g_assert_no_error (error); + g_assert (ret); + + /* get data (present) */ + lang = gpk_language_iso639_to_language (language, "en"); + g_assert_cmpstr (lang, ==, "English"); + g_free (lang); + + /* get data (missing) */ + lang = gpk_language_iso639_to_language (language, "notgoingtoexist"); + g_assert_cmpstr (lang, ==, NULL); + + g_object_unref (language); +>>>>>>> parent of 52b1ece... Remove unused functionality +} + +static void gpk_test_error_func (void) { gboolean ret; @@ -212,6 +416,17 @@ gpk_test_error_func (void) } static void +gpk_test_dbus_func (void) +{ + GpkDbus *dbus = NULL; + + /* get GpkDbus object */ + dbus = gpk_dbus_new (); + g_assert (dbus); + g_object_unref (dbus); +} + +static void gpk_test_common_func (void) { gchar *text; @@ -554,8 +769,12 @@ main (int argc, char **argv) g_test_add_func ("/gnome-packagekit/enum", gpk_test_enum_func); g_test_add_func ("/gnome-packagekit/common", gpk_test_common_func); + g_test_add_func ("/gnome-packagekit/language", gpk_test_language_func); g_test_add_func ("/gnome-packagekit/markdown", gpk_test_markdown_func); + g_test_add_func ("/gnome-packagekit/dbus", gpk_test_dbus_func); + g_test_add_func ("/gnome-packagekit/dbus-task", gpk_test_dbus_task_func); if (g_test_thorough ()) { + g_test_add_func ("/gnome-packagekit/modal-dialog", gpk_test_modal_dialog_func); g_test_add_func ("/gnome-packagekit/error", gpk_test_error_func); g_test_add_func ("/gnome-packagekit/task", gpk_test_task_func); } Index: gnome-packagekit-3.20.0/src/gpk-session.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-session.c @@ -0,0 +1,361 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <dbus/dbus-glib.h> + +#include "gpk-session.h" +#include "gpk-common.h" + +static void gpk_session_finalize (GObject *object); + +#define GPK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_SESSION, GpkSessionPrivate)) + +#define GPK_SESSION_MANAGER_SERVICE "org.gnome.SessionManager" +#define GPK_SESSION_MANAGER_PATH "/org/gnome/SessionManager" +#define GPK_SESSION_MANAGER_INTERFACE "org.gnome.SessionManager" +#define GPK_SESSION_MANAGER_PRESENCE_PATH "/org/gnome/SessionManager/Presence" +#define GPK_SESSION_MANAGER_PRESENCE_INTERFACE "org.gnome.SessionManager.Presence" +#define GPK_SESSION_MANAGER_CLIENT_PRIVATE_INTERFACE "org.gnome.SessionManager.ClientPrivate" +#define GPK_DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" + +typedef enum { + GPK_SESSION_STATUS_ENUM_AVAILABLE = 0, + GPK_SESSION_STATUS_ENUM_INVISIBLE, + GPK_SESSION_STATUS_ENUM_BUSY, + GPK_SESSION_STATUS_ENUM_IDLE, + GPK_SESSION_STATUS_ENUM_UNKNOWN +} GpkSessionStatusEnum; + +typedef enum { + GPK_SESSION_INHIBIT_MASK_LOGOUT = 1, + GPK_SESSION_INHIBIT_MASK_SWITCH = 2, + GPK_SESSION_INHIBIT_MASK_SUSPEND = 4, + GPK_SESSION_INHIBIT_MASK_IDLE = 8 +} GpkSessionInhibitMask; + +struct GpkSessionPrivate +{ + DBusGProxy *proxy; + DBusGProxy *proxy_presence; + DBusGProxy *proxy_client_private; + DBusGProxy *proxy_prop; + gboolean is_idle_old; + gboolean is_inhibited_old; +}; + +enum { + IDLE_CHANGED, + INHIBITED_CHANGED, + STOP, + QUERY_END_SESSION, + END_SESSION, + CANCEL_END_SESSION, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0 }; +static gpointer gpk_session_object = NULL; + +G_DEFINE_TYPE (GpkSession, gpk_session, G_TYPE_OBJECT) + +/** + * gpk_session_logout: + **/ +gboolean +gpk_session_logout (GpkSession *session) +{ + g_return_val_if_fail (GPK_IS_SESSION (session), FALSE); + + /* no gnome-session */ + if (session->priv->proxy == NULL) { + g_warning ("no gnome-session"); + return FALSE; + } + + /* we have to use no reply, as the SM calls into g-p-m to get the can_suspend property */ + dbus_g_proxy_call_no_reply (session->priv->proxy, "Logout", + G_TYPE_UINT, 1, /* no confirmation, but use inhibitors */ + G_TYPE_INVALID); + return TRUE; +} + +/** + * gpk_session_presence_status_changed_cb: + **/ +static void +gpk_session_presence_status_changed_cb (DBusGProxy *proxy, guint status, GpkSession *session) +{ + gboolean is_idle; + is_idle = (status == GPK_SESSION_STATUS_ENUM_IDLE); + if (is_idle != session->priv->is_idle_old) { + g_debug ("emitting idle-changed : (%i)", is_idle); + session->priv->is_idle_old = is_idle; + g_signal_emit (session, signals [IDLE_CHANGED], 0, is_idle); + } +} + +/** + * gpk_session_is_idle: + **/ +static gboolean +gpk_session_is_idle (GpkSession *session) +{ + gboolean ret; + gboolean is_idle = FALSE; + GError *error = NULL; + GValue *value; + + /* no gnome-session */ + if (session->priv->proxy_prop == NULL) { + g_warning ("no gnome-session"); + goto out; + } + + value = g_new0(GValue, 1); + /* find out if this change altered the inhibited state */ + ret = dbus_g_proxy_call (session->priv->proxy_prop, "Get", &error, + G_TYPE_STRING, GPK_SESSION_MANAGER_PRESENCE_INTERFACE, + G_TYPE_STRING, "status", + G_TYPE_INVALID, + G_TYPE_VALUE, value, + G_TYPE_INVALID); + if (!ret) { + g_warning ("failed to get idle status: %s", error->message); + g_error_free (error); + is_idle = FALSE; + goto out; + } + is_idle = (g_value_get_uint (value) == GPK_SESSION_STATUS_ENUM_IDLE); + g_free (value); +out: + return is_idle; +} + +/** + * gpk_session_is_inhibited: + **/ +static gboolean +gpk_session_is_inhibited (GpkSession *session) +{ + gboolean ret; + gboolean is_inhibited = FALSE; + GError *error = NULL; + + /* no gnome-session */ + if (session->priv->proxy == NULL) { + g_warning ("no gnome-session"); + goto out; + } + + /* find out if this change altered the inhibited state */ + ret = dbus_g_proxy_call (session->priv->proxy, "IsInhibited", &error, + G_TYPE_UINT, GPK_SESSION_INHIBIT_MASK_IDLE, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &is_inhibited, + G_TYPE_INVALID); + if (!ret) { + g_warning ("failed to get inhibit status: %s", error->message); + g_error_free (error); + is_inhibited = FALSE; + } +out: + return is_inhibited; +} + +/** + * gpk_session_inhibit_changed_cb: + **/ +static void +gpk_session_inhibit_changed_cb (DBusGProxy *proxy, const gchar *id, GpkSession *session) +{ + gboolean is_inhibited; + + is_inhibited = gpk_session_is_inhibited (session); + if (is_inhibited != session->priv->is_inhibited_old) { + g_debug ("emitting inhibited-changed : (%i)", is_inhibited); + session->priv->is_inhibited_old = is_inhibited; + g_signal_emit (session, signals [INHIBITED_CHANGED], 0, is_inhibited); + } +} + +/** + * gpk_session_class_init: + * @klass: This class instance + **/ +static void +gpk_session_class_init (GpkSessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_session_finalize; + g_type_class_add_private (klass, sizeof (GpkSessionPrivate)); + + signals [IDLE_CHANGED] = + g_signal_new ("idle-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, idle_changed), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals [INHIBITED_CHANGED] = + g_signal_new ("inhibited-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, inhibited_changed), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals [STOP] = + g_signal_new ("stop", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, stop), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [QUERY_END_SESSION] = + g_signal_new ("query-end-session", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, query_end_session), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [END_SESSION] = + g_signal_new ("end-session", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, end_session), + NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals [CANCEL_END_SESSION] = + g_signal_new ("cancel-end-session", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GpkSessionClass, cancel_end_session), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * gpk_session_init: + * @session: This class instance + **/ +static void +gpk_session_init (GpkSession *session) +{ + DBusGConnection *connection; + GError *error = NULL; + + session->priv = GPK_SESSION_GET_PRIVATE (session); + session->priv->is_idle_old = FALSE; + session->priv->is_inhibited_old = FALSE; + session->priv->proxy_client_private = NULL; + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + + /* get org.gnome.Session interface */ + session->priv->proxy = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE, + GPK_SESSION_MANAGER_PATH, + GPK_SESSION_MANAGER_INTERFACE, &error); + if (session->priv->proxy == NULL) { + g_warning ("DBUS error: %s", error->message); + g_error_free (error); + return; + } + + /* get org.gnome.Session.Presence interface */ + session->priv->proxy_presence = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE, + GPK_SESSION_MANAGER_PRESENCE_PATH, + GPK_SESSION_MANAGER_PRESENCE_INTERFACE, &error); + if (session->priv->proxy_presence == NULL) { + g_warning ("DBUS error: %s", error->message); + g_error_free (error); + return; + } + + /* get properties interface */ + session->priv->proxy_prop = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE, + GPK_SESSION_MANAGER_PRESENCE_PATH, + GPK_DBUS_PROPERTIES_INTERFACE, &error); + if (session->priv->proxy_prop == NULL) { + g_warning ("DBUS error: %s", error->message); + g_error_free (error); + return; + } + + /* get StatusChanged */ + dbus_g_proxy_add_signal (session->priv->proxy_presence, "StatusChanged", G_TYPE_UINT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (session->priv->proxy_presence, "StatusChanged", G_CALLBACK (gpk_session_presence_status_changed_cb), session, NULL); + + /* get InhibitorAdded */ + dbus_g_proxy_add_signal (session->priv->proxy, "InhibitorAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (session->priv->proxy, "InhibitorAdded", G_CALLBACK (gpk_session_inhibit_changed_cb), session, NULL); + + /* get InhibitorRemoved */ + dbus_g_proxy_add_signal (session->priv->proxy, "InhibitorRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (session->priv->proxy, "InhibitorRemoved", G_CALLBACK (gpk_session_inhibit_changed_cb), session, NULL); + + /* coldplug */ + session->priv->is_inhibited_old = gpk_session_is_inhibited (session); + session->priv->is_idle_old = gpk_session_is_idle (session); + g_debug ("idle: %i, inhibited: %i", session->priv->is_idle_old, session->priv->is_inhibited_old); +} + +/** + * gpk_session_finalize: + * @object: This class instance + **/ +static void +gpk_session_finalize (GObject *object) +{ + GpkSession *session; + g_return_if_fail (object != NULL); + g_return_if_fail (GPK_IS_SESSION (object)); + + session = GPK_SESSION (object); + session->priv = GPK_SESSION_GET_PRIVATE (session); + + g_object_unref (session->priv->proxy); + g_object_unref (session->priv->proxy_presence); + if (session->priv->proxy_client_private != NULL) + g_object_unref (session->priv->proxy_client_private); + g_object_unref (session->priv->proxy_prop); + + G_OBJECT_CLASS (gpk_session_parent_class)->finalize (object); +} + +/** + * gpk_session_new: + * Return value: new GpkSession instance. + **/ +GpkSession * +gpk_session_new (void) +{ + if (gpk_session_object != NULL) { + g_object_ref (gpk_session_object); + } else { + gpk_session_object = g_object_new (GPK_TYPE_SESSION, NULL); + g_object_add_weak_pointer (gpk_session_object, &gpk_session_object); + } + return GPK_SESSION (gpk_session_object); +} Index: gnome-packagekit-3.20.0/src/gpk-session.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-session.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_SESSION_H +#define __GPK_SESSION_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_SESSION (gpk_session_get_type ()) +#define GPK_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_SESSION, GpkSession)) +#define GPK_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_SESSION, GpkSessionClass)) +#define GPK_IS_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_SESSION)) +#define GPK_IS_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_SESSION)) +#define GPK_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_SESSION, GpkSessionClass)) + +typedef struct GpkSessionPrivate GpkSessionPrivate; + +typedef struct +{ + GObject parent; + GpkSessionPrivate *priv; +} GpkSession; + +typedef struct +{ + GObjectClass parent_class; + void (* idle_changed) (GpkSession *session, + gboolean is_idle); + void (* inhibited_changed) (GpkSession *session, + gboolean is_inhibited); + /* just exit */ + void (* stop) (GpkSession *session); + /* reply with EndSessionResponse */ + void (* query_end_session) (GpkSession *session, + guint flags); + /* reply with EndSessionResponse */ + void (* end_session) (GpkSession *session, + guint flags); + void (* cancel_end_session) (GpkSession *session); +} GpkSessionClass; + +GType gpk_session_get_type (void); +GpkSession *gpk_session_new (void); + +gboolean gpk_session_logout (GpkSession *session); + +G_END_DECLS + +#endif /* __GPK_SESSION_H */ Index: gnome-packagekit-3.20.0/src/gpk-task.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-task.c +++ gnome-packagekit-3.20.0/src/gpk-task.c @@ -25,6 +25,7 @@ #include <packagekit-glib2/packagekit.h> #include "gpk-task.h" +#include "gpk-gnome.h" #include "gpk-common.h" #include "gpk-enum.h" #include "gpk-dialog.h" Index: gnome-packagekit-3.20.0/src/gpk-vendor.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-vendor.c @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib/gi18n.h> + +#include "egg-string.h" +#include "gpk-vendor.h" + +static void gpk_vendor_finalize (GObject *object); + +#define GPK_VENDOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_VENDOR, GpkVendorPrivate)) + +struct GpkVendorPrivate +{ + GKeyFile *file; +}; + +G_DEFINE_TYPE (GpkVendor, gpk_vendor, G_TYPE_OBJECT) + +/** + * gpk_vendor_class_init: + * @klass: The GpkVendorClass + **/ +static void +gpk_vendor_class_init (GpkVendorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_vendor_finalize; + g_type_class_add_private (klass, sizeof (GpkVendorPrivate)); +} + +/** + * gpk_vendor_type_to_string: + **/ +static const gchar * +gpk_vendor_type_to_string (GpkVendorUrlType type) +{ + if (type == GPK_VENDOR_URL_TYPE_CODEC) + return "CodecUrl"; + if (type == GPK_VENDOR_URL_TYPE_FONT) + return "FontUrl"; + if (type == GPK_VENDOR_URL_TYPE_MIME) + return "MimeUrl"; + if (type == GPK_VENDOR_URL_TYPE_HARDWARE) + return "HardwareUrl"; + return "DefaultUrl"; +} + +/** + * gpk_vendor_get_not_found_url: + **/ +gchar * +gpk_vendor_get_not_found_url (GpkVendor *vendor, GpkVendorUrlType type) +{ + const gchar *key; + gchar *url = NULL; + + /* get data */ + key = gpk_vendor_type_to_string (type); + url = g_key_file_get_string (vendor->priv->file, "PackagesNotFound", key, NULL); + + /* none is a special value */ + if (g_strcmp0 (url, "none") == 0) { + g_free (url); + url = NULL; + } + + /* got a valid URL */ + if (url != NULL) + goto out; + + /* default has no fallback */ + if (type == GPK_VENDOR_URL_TYPE_DEFAULT) + goto out; + + /* get fallback data */ + g_debug ("using fallback"); + key = gpk_vendor_type_to_string (GPK_VENDOR_URL_TYPE_DEFAULT); + url = g_key_file_get_string (vendor->priv->file, "PackagesNotFound", key, NULL); + + /* none is a special value */ + if (g_strcmp0 (url, "none") == 0) { + g_free (url); + url = NULL; + } +out: + g_debug ("url=%s", url); + return url; +} + +/** + * gpk_vendor_init: + * @vendor: This class instance + **/ +static void +gpk_vendor_init (GpkVendor *vendor) +{ + gboolean ret; + + vendor->priv = GPK_VENDOR_GET_PRIVATE (vendor); + + vendor->priv->file = g_key_file_new (); + ret = g_key_file_load_from_file (vendor->priv->file, "/etc/PackageKit/Vendor.conf", G_KEY_FILE_NONE, NULL); + if (!ret) + g_warning ("file not found"); +} + +/** + * gpk_vendor_finalize: + * @object: The object to finalize + **/ +static void +gpk_vendor_finalize (GObject *object) +{ + GpkVendor *vendor; + + g_return_if_fail (PK_IS_VENDOR (object)); + + vendor = GPK_VENDOR (object); + g_return_if_fail (vendor->priv != NULL); + + g_key_file_free (vendor->priv->file); + + G_OBJECT_CLASS (gpk_vendor_parent_class)->finalize (object); +} + +/** + * gpk_vendor_new: + * + * Return value: a new GpkVendor object. + **/ +GpkVendor * +gpk_vendor_new (void) +{ + GpkVendor *vendor; + vendor = g_object_new (GPK_TYPE_VENDOR, NULL); + return GPK_VENDOR (vendor); +} + Index: gnome-packagekit-3.20.0/src/gpk-vendor.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-vendor.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_VENDOR_H +#define __GPK_VENDOR_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_VENDOR (gpk_vendor_get_type ()) +#define GPK_VENDOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_VENDOR, GpkVendor)) +#define GPK_VENDOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_VENDOR, GpkVendorClass)) +#define PK_IS_VENDOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_VENDOR)) +#define PK_IS_VENDOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_VENDOR)) +#define GPK_VENDOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_VENDOR, GpkVendorClass)) +#define GPK_VENDOR_ERROR (gpk_vendor_error_quark ()) +#define GPK_VENDOR_TYPE_ERROR (gpk_vendor_error_get_type ()) + +typedef struct GpkVendorPrivate GpkVendorPrivate; + +typedef struct +{ + GObject parent; + GpkVendorPrivate *priv; +} GpkVendor; + +typedef struct +{ + GObjectClass parent_class; +} GpkVendorClass; + +/** + * GpkModalDialogWidgets: + */ +typedef enum +{ + GPK_VENDOR_URL_TYPE_CODEC, + GPK_VENDOR_URL_TYPE_FONT, + GPK_VENDOR_URL_TYPE_MIME, + GPK_VENDOR_URL_TYPE_HARDWARE, + GPK_VENDOR_URL_TYPE_DEFAULT +} GpkVendorUrlType; + +GType gpk_vendor_get_type (void); +GpkVendor *gpk_vendor_new (void); +gchar *gpk_vendor_get_not_found_url (GpkVendor *vendor, + GpkVendorUrlType type); + +G_END_DECLS + +#endif /* __GPK_VENDOR_H */ Index: gnome-packagekit-3.20.0/src/gpk-x11.c =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-x11.c @@ -0,0 +1,250 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <X11/Xatom.h> + +#include "egg-string.h" + +#include "gpk-x11.h" + +static void gpk_x11_finalize (GObject *object); + +#define GPK_X11_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_X11, GpkX11Private)) + +struct GpkX11Private +{ + GdkDisplay *gdk_display; + Display *display; + Window window; +}; + +G_DEFINE_TYPE (GpkX11, gpk_x11, G_TYPE_OBJECT) + +/** + * gpk_x11_set_xid: + **/ +gboolean +gpk_x11_set_xid (GpkX11 *x11, guint32 xid) +{ + GdkWindow *window; + + g_return_val_if_fail (GPK_IS_X11 (x11), FALSE); + + window = gdk_x11_window_foreign_new_for_display (x11->priv->gdk_display, xid); + if (window == NULL) + return FALSE; + + /* save the x state */ + x11->priv->display = GDK_DISPLAY_XDISPLAY (x11->priv->gdk_display); + x11->priv->window = GDK_WINDOW_XID (window); + + return TRUE; +} + +/** + * gpk_x11_set_window: + **/ +gboolean +gpk_x11_set_window (GpkX11 *x11, GdkWindow *window) +{ + g_return_val_if_fail (GPK_IS_X11 (x11), FALSE); + + /* save the x state */ + x11->priv->display = GDK_DISPLAY_XDISPLAY (x11->priv->gdk_display); + x11->priv->window = GDK_WINDOW_XID (window); + + return TRUE; +} + +/** + * gpk_x11_get_user_time: + **/ +guint32 +gpk_x11_get_user_time (GpkX11 *x11) +{ + guint32 timestamp = 0; + Atom atom = None; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + Window *win = NULL; + int rc; + int err; + + g_return_val_if_fail (GPK_IS_X11 (x11), 0); + + /* check we have a window */ + if (x11->priv->window == None) { + g_debug ("no window, so cannot get user_time"); + goto out; + } + + /* get _NET_WM_USER_TIME_WINDOW which points to a window on which you can find the _NET_WM_USER_TIME property */ + gdk_error_trap_push (); + atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_USER_TIME_WINDOW"); + rc = XGetWindowProperty (x11->priv->display, x11->priv->window, atom, 0, G_MAXLONG, False, XA_WINDOW, + &type, &format, &nitems, &bytes_after, (void*) &win); + err = gdk_error_trap_pop (); + if (err != Success || rc != Success) { + g_warning ("couldn't get _NET_WM_USER_TIME_WINDOW"); + goto out; + } + + /* is not a window */ + if (type != XA_WINDOW) { + g_warning ("not type XA_WINDOW"); + goto out; + } + + /* get _NET_WM_USER_TIME so we can get the user time */ + gdk_error_trap_push (); + atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_USER_TIME"); + rc = XGetWindowProperty (x11->priv->display, *win, atom, 0, G_MAXLONG, False, XA_CARDINAL, + &type, &format, &nitems, &bytes_after, (void*) ×tamp); + err = gdk_error_trap_pop (); + if (err != Success || rc != Success) { + g_warning ("couldn't get _NET_WM_USER_TIME"); + goto out; + } + + /* is not a window */ + if (type != XA_CARDINAL) { + g_warning ("not type XA_CARDINAL"); + goto out; + } +out: + if (win != NULL) + XFree (win); + return timestamp; +} + +/** + * gpk_x11_get_title: + **/ +gchar * +gpk_x11_get_title (GpkX11 *x11) +{ + gchar *title = NULL; + Atom atom = None; + Atom atom_type = None; + gchar *data = NULL; + Atom type; + gint format; + gulong nitems; + gulong bytes_after; + int rc; + + g_return_val_if_fail (GPK_IS_X11 (x11), NULL); + + /* check we have a window */ + if (x11->priv->window == None) { + g_debug ("no window, so cannot get user_time"); + goto out; + } + + /* get _NET_WM_NAME */ + gdk_error_trap_push (); + atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_NAME"); + atom_type = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "UTF8_STRING"); + rc = XGetWindowProperty (x11->priv->display, x11->priv->window, atom, 0, G_MAXLONG, False, atom_type, + &type, &format, &nitems, &bytes_after, (void*) &data); + gdk_error_trap_pop_ignored (); + if (rc == Success && nitems > 0) { + title = g_strdup (data); + goto out; + } + + /* we failed to get the UTF8 title, try plain old WM_NAME */ + gdk_error_trap_push (); + rc = XGetWindowProperty (x11->priv->display, x11->priv->window, XA_WM_NAME, 0, G_MAXLONG, False, XA_STRING, + &type, &format, &nitems, &bytes_after, (void*) &data); + gdk_error_trap_pop_ignored (); + if (rc == Success && nitems > 0) { + title = g_strdup (data); + goto out; + } + g_warning ("failed to get X11 name for window %i", (gint) x11->priv->window); +out: + if (data != NULL) + XFree (data); + return title; +} + +/** + * gpk_x11_class_init: + * @klass: The GpkX11Class + **/ +static void +gpk_x11_class_init (GpkX11Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gpk_x11_finalize; + g_type_class_add_private (klass, sizeof (GpkX11Private)); +} + +/** + * gpk_x11_init: + * @x11: This class instance + **/ +static void +gpk_x11_init (GpkX11 *x11) +{ + x11->priv = GPK_X11_GET_PRIVATE (x11); + x11->priv->display = NULL; + x11->priv->window = None; + x11->priv->gdk_display = gdk_display_get_default (); +} + +/** + * gpk_x11_finalize: + * @object: The object to finalize + **/ +static void +gpk_x11_finalize (GObject *object) +{ + GpkX11 *x11; + g_return_if_fail (GPK_IS_X11 (object)); + x11 = GPK_X11 (object); + + g_return_if_fail (x11->priv != NULL); + + G_OBJECT_CLASS (gpk_x11_parent_class)->finalize (object); +} + +/** + * gpk_x11_new: + * + * Return value: a new GpkX11 object. + **/ +GpkX11 * +gpk_x11_new (void) +{ + GpkX11 *x11; + x11 = g_object_new (GPK_TYPE_X11, NULL); + return GPK_X11 (x11); +} + Index: gnome-packagekit-3.20.0/src/gpk-x11.h =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/gpk-x11.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GPK_X11_H +#define __GPK_X11_H + +#include <glib-object.h> +#include <gdk/gdk.h> + +G_BEGIN_DECLS + +#define GPK_TYPE_X11 (gpk_x11_get_type ()) +#define GPK_X11(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_X11, GpkX11)) +#define GPK_X11_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_X11, GpkX11Class)) +#define GPK_IS_X11(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_X11)) +#define GPK_IS_X11_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_X11)) +#define GPK_X11_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_X11, GpkX11Class)) +#define GPK_X11_ERROR (gpk_x11_error_quark ()) +#define GPK_X11_TYPE_ERROR (gpk_x11_error_get_type ()) + +typedef struct GpkX11Private GpkX11Private; + +typedef struct +{ + GObject parent; + GpkX11Private *priv; +} GpkX11; + +typedef struct +{ + GObjectClass parent_class; +} GpkX11Class; + +GType gpk_x11_get_type (void); +GpkX11 *gpk_x11_new (void); +gboolean gpk_x11_set_xid (GpkX11 *x11, + guint32 xid); +gboolean gpk_x11_set_window (GpkX11 *x11, + GdkWindow *window); +guint32 gpk_x11_get_user_time (GpkX11 *x11); +gchar *gpk_x11_get_title (GpkX11 *x11); + +G_END_DECLS + +#endif /* __GPK_X11_H */ Index: gnome-packagekit-3.20.0/src/org.freedesktop.PackageKit.xml =================================================================== --- /dev/null +++ gnome-packagekit-3.20.0/src/org.freedesktop.PackageKit.xml @@ -0,0 +1,506 @@ +<!DOCTYPE node PUBLIC +"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ + <!ENTITY ERROR_GENERAL "org.freedesktop.PackageKit.Denied"> +]> +<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + + <interface name="org.freedesktop.PackageKit.Query"> + <doc:doc> + <doc:description> + <doc:para> + The interface used for quering the package database. + </doc:para> + </doc:description> + </doc:doc> + + <!--*****************************************************************************************--> + <method name="IsInstalled"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Finds out if the package is installed. + </doc:para> + </doc:description> + </doc:doc> + <arg type="s" name="package_name" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + A package name, e.g. <doc:tt>hal-info</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>timeout=10</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="b" name="installed" direction="out"> + <doc:doc> + <doc:summary> + <doc:para> + If the package is installed. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="SearchFile"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Finds the package name for an installed or available file + </doc:para> + </doc:description> + </doc:doc> + <arg type="s" name="file_name" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + A package name, e.g. <doc:tt>/usr/share/help/gimp/index.html</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>timeout=10</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="b" name="installed" direction="out"> + <doc:doc> + <doc:summary> + <doc:para> + If the package is installed. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="package_name" direction="out"> + <doc:doc> + <doc:summary> + <doc:para> + The package name of the file, e.g. <doc:tt>hal-info</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + </interface> + + <!-- ######################################################################################### --> + <interface name="org.freedesktop.PackageKit.Modify"> + <doc:doc> + <doc:description> + <doc:para> + The interface used for modifying the package database. + </doc:para> + </doc:description> + </doc:doc> + + <!--*****************************************************************************************--> + <method name="InstallPackageFiles"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs local package files or service packs. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="files" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of file names. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An interaction mode that specifies which UI elements should be shown + or hidden different from the user default, e.g. + <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,show-progress</doc:tt>. + The show options are: + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>. + The hide options are: + <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,hide-progress,hide-finished,hide-warning</doc:tt>. + Convenience options such as: + <doc:tt>never</doc:tt>, <doc:tt>defaults</doc:tt> or <doc:tt>always</doc:tt>. + are also available. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallProvideFiles"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs packages to provide files. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="files" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of file names. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallPackageNames"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs packages from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="packages" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of package names. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallMimeTypes"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs mimetype handlers from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="mime_types" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of mime types, e.g. <doc:tt>text/plain</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallFontconfigResources"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs fontconfig resources (usually fonts) from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="resources" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of font descriptors from fontconfig, e.g. <doc:tt>:lang=mn</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallGStreamerResources"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs GStreamer fontconfig resources (usually codecs) from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="resources" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of codecs descriptors from <doc:tt>pk-gstreamer-install</doc:tt>, e.g. + <doc:tt>Advanced Streaming Format (ASF) demuxer|decoder-video/x-ms-asf</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="InstallResources"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs resources of a given type from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="type" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The type of resource to request, e.g. <doc:tt>plasma-service</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="resources" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of resource descriptors + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <!--*****************************************************************************************--> + <method name="RemovePackageByFiles"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Removes packages that provide the given local files. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="files" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of file names. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An interaction mode that specifies which UI elements should be shown + or hidden different from the user default, e.g. + <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,show-progress</doc:tt>. + The show options are: + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>. + The hide options are: + <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,hide-progress,hide-finished,hide-warning</doc:tt>. + Convenience options such as: + <doc:tt>never</doc:tt>, <doc:tt>defaults</doc:tt> or <doc:tt>always</doc:tt>. + are also available. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + + <method name="InstallPrinterDrivers"> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <doc:doc> + <doc:description> + <doc:para> + Installs printer drivers from a configured package source. + </doc:para> + </doc:description> + </doc:doc> + <arg type="u" name="xid" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + The X window handle ID, used for focus stealing prevention and setting modality. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="as" name="resources" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An array of printer model descriptors in IEEE 1284 + Device ID format, + e.g. <doc:tt>MFG:Hewlett-Packard;MDL:HP LaserJet + 6MP;</doc:tt>. + </doc:para> + </doc:summary> + </doc:doc> + </arg> + <arg type="s" name="interaction" direction="in"> + <doc:doc> + <doc:summary> + <doc:para> + An optional interaction mode, e.g. + <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt> + </doc:para> + </doc:summary> + </doc:doc> + </arg> + </method> + </interface> +</node> + Index: gnome-packagekit-3.20.0/src/gpk-update-viewer.c =================================================================== --- gnome-packagekit-3.20.0.orig/src/gpk-update-viewer.c +++ gnome-packagekit-3.20.0/src/gpk-update-viewer.c @@ -21,6 +21,7 @@ #include "config.h" +#include <dbus/dbus-glib.h> #include <gdk/gdkkeysyms.h> #include <glib/gi18n.h> #include <glib/gi18n.h> @@ -42,6 +43,7 @@ #include "gpk-dialog.h" #include "gpk-enum.h" #include "gpk-error.h" +#include "gpk-session.h" #include "gpk-task.h" #include "gpk-debug.h" @@ -206,28 +208,33 @@ gpk_update_viewer_check_restart (void) gboolean show_button = TRUE; GError *error = NULL; + g_print ("gpk update viewer check restart\n"); /* get the text */ title = gpk_restart_enum_to_localised_text (restart_update); if (restart_update == PK_RESTART_ENUM_SYSTEM) { /* TRANSLATORS: the message text for the restart */ message = _("Some of the updates that were installed require the computer to be restarted before the changes will be applied."); + g_print ("%s\n", message); /* TRANSLATORS: the button text for the restart */ button = _("Restart Computer"); } else if (restart_update == PK_RESTART_ENUM_SECURITY_SYSTEM) { /* TRANSLATORS: the message text for the restart */ message = _("Some of the updates that were installed require the computer to be restarted to remain secure."); + g_print ("%s\n", message); /* TRANSLATORS: the button text for the restart */ button = _("Restart Computer"); } else if (restart_update == PK_RESTART_ENUM_SESSION) { /* TRANSLATORS: the message text for the log out */ message = _("Some of the updates that were installed require you to log out and back in before the changes will be applied."); + g_print ("%s\n", message); /* TRANSLATORS: the button text for the log out */ button = _("Log Out"); } else if (restart_update == PK_RESTART_ENUM_APPLICATION) { /* TRANSLATORS: the message text for the application restart */ message = _("Some of the updates that were installed require you to restart this application before the changes will be applied."); + g_print ("%s\n", message); /* TRANSLATORS: the button text for the application restart */ button = _("Restart Application"); @@ -239,6 +246,7 @@ gpk_update_viewer_check_restart (void) } else if (restart_update == PK_RESTART_ENUM_SECURITY_SESSION) { /* TRANSLATORS: the message text for the log out */ message = _("Some of the updates that were installed require you to log out and back in to remain secure."); + g_print ("%s\n", message); /* TRANSLATORS: the button text for the log out */ button = _("Log Out"); @@ -288,6 +296,13 @@ gpk_update_viewer_check_restart (void) g_error_free (error); } #endif + } else if (restart_update == PK_RESTART_ENUM_SESSION) { + GpkSession *session; + session = gpk_session_new (); + /* use gnome-session to log out */ + g_print ("gpk session logout\n"); + gpk_session_logout (session); + g_object_unref (session); } else if (restart_update == PK_RESTART_ENUM_APPLICATION) { char cmd[256] = {0}; /* need to wait for PackageKit to finish too */ @@ -425,9 +440,11 @@ gpk_update_viewer_update_packages_cb (Pk GtkTreeView *treeview; GtkTreeModel *model; + g_print ("gpk update viewer update packages cb\n"); /* get the results */ results = pk_task_generic_finish (task, res, &error); if (results == NULL) { + g_print ("results == NULL\n"); /* not a PK error */ if (error->domain != PK_CLIENT_ERROR) { /* TRANSLATORS: the PackageKit request did not complete, and it did not send an error */ @@ -459,6 +476,7 @@ gpk_update_viewer_update_packages_cb (Pk /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { + g_print ("failed to update packages\n"); g_warning ("failed to update packages: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); @@ -481,6 +499,7 @@ gpk_update_viewer_update_packages_cb (Pk /* get the worst restart case */ restart = pk_results_get_require_restart_worst (results); + g_print ("require restart worst: %d\n", restart); if (restart > restart_update) restart_update = restart; @@ -489,6 +508,8 @@ gpk_update_viewer_update_packages_cb (Pk gpk_update_viewer_check_blocked_packages (array); /* check restart */ + g_print ("restart: %d\n", restart); + g_print ("check restart: %d\n", restart_update); if (restart_update == PK_RESTART_ENUM_SYSTEM || restart_update == PK_RESTART_ENUM_SESSION || restart_update == PK_RESTART_ENUM_APPLICATION || @@ -498,6 +519,7 @@ gpk_update_viewer_update_packages_cb (Pk gpk_update_viewer_quit (); goto out; } else { + g_print ("no need to restart update\n"); goto out; } @@ -1221,6 +1243,7 @@ gpk_update_viewer_button_install_cb (Gtk GtkTreeView *treeview; gchar **package_ids = NULL; + g_print ("button install cb\n"); /* hide the upgrade viewbox from now on */ widget = GTK_WIDGET(gtk_builder_get_object (builder, "viewport_upgrade")); gtk_widget_hide (widget); @@ -1438,6 +1461,7 @@ gpk_update_viewer_reconsider_info (void) gchar *text_size; PkNetworkEnum state; + g_print ("reconsider info\n"); /* update global state */ gpk_update_viewer_update_global_state (); @@ -1561,6 +1585,7 @@ gpk_update_viewer_treeview_update_toggle GtkTreeView *treeview; GtkTreeModel *model; + g_print ("treeview update toggled\n"); treeview = GTK_TREE_VIEW(gtk_builder_get_object (builder, "treeview_updates")); model = gtk_tree_view_get_model (treeview); @@ -3663,6 +3688,7 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); + dbus_g_thread_init (); gtk_init (&argc, &argv); context = g_option_context_new (NULL);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor