[tomboy] Support Windows 7 Jump Lists (bug #587330)
- From: Sanford Armstrong <sharm src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [tomboy] Support Windows 7 Jump Lists (bug #587330)
- Date: Mon, 25 Jan 2010 08:35:31 +0000 (UTC)
commit 5ff67c1442743d8d55c06fb7cf7437eb64969aec
Author: Stefan Cosma <stefan cosma gmail com>
Date: Sun Nov 8 17:50:16 2009 +0200
Support Windows 7 Jump Lists (bug #587330)
Tomboy.csproj | 16 +++-
Tomboy/JumpListManager.cs | 205 ++++++++++++++++++++++++++++++++++++++
Tomboy/Tomboy.cs | 21 ++++
Tomboy/WindowsInterop.cs | 240 +++++++++++++++++++++++++++++++++++++++++++++
data/icons/new_note.ico | Bin 0 -> 1150 bytes
data/icons/note.ico | Bin 0 -> 1150 bytes
data/icons/search.ico | Bin 0 -> 894 bytes
7 files changed, 481 insertions(+), 1 deletions(-)
---
diff --git a/Tomboy.csproj b/Tomboy.csproj
index 808ca17..dd588de 100644
--- a/Tomboy.csproj
+++ b/Tomboy.csproj
@@ -109,6 +109,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Tomboy\ActionManager.cs" />
+ <Compile Include="Tomboy\JumpListManager.cs" />
<Compile Include="Tomboy\Contrast.cs" />
<Compile Include="Tomboy\Defines.WIN32.cs" />
<Compile Include="Tomboy\IRemoteControl.cs" />
@@ -136,6 +137,7 @@
<Compile Include="Tomboy\TagManager.cs" />
<Compile Include="Tomboy\Tag.cs" />
<Compile Include="Tomboy\TagButton.cs" />
+ <Compile Include="Tomboy\WindowsInterop.cs" />
<Compile Include="Tomboy\WindowsFactory.cs" />
<Compile Include="Tomboy\WindowsKeybinder.cs" />
<Compile Include="Tomboy\PreferencesDialog.cs" />
@@ -211,6 +213,15 @@
<None Include="Tomboy\Defines.cs.in" />
</ItemGroup>
<ItemGroup>
+ <Content Include="new_note.ico">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="note.ico">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="search.ico">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="tomboy.ico" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
@@ -233,6 +244,9 @@
</ProjectExtensions>
<PropertyGroup>
<PreBuildEvent>copy "$(ProjectDir)data\icons\tomboy.ico" "$(ProjectDir)tomboy.ico"
+copy "$(ProjectDir)data\icons\note.ico" "$(ProjectDir)note.ico"
+copy "$(ProjectDir)data\icons\new_note.ico" "$(ProjectDir)new_note.ico"
+copy "$(ProjectDir)data\icons\search.ico" "$(ProjectDir)search.ico"
copy "$(ProjectDir)data\icons\hicolor_apps_48x48_tomboy.png" "$(ProjectDir)tomboy.png"
copy "$(ProjectDir)data\icons\hicolor_places_22x22_note.png" "$(ProjectDir)note.png"
copy "$(ProjectDir)data\icons\hicolor_actions_16x16_note-new.png" "$(ProjectDir)note-new.png"
@@ -297,4 +311,4 @@ copy "$(ProjectDir)data\icons\hicolor_status_16x16_pin-active.png" "$(ProjectDir
copy "$(ProjectDir)Tomboy\Tomboy.addin.xml" "$(ProjectDir)"
copy "$(ProjectDir)data\UIManagerLayout.xml" "$(ProjectDir)"</PostBuildEvent>
</PropertyGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Tomboy/JumpListManager.cs b/Tomboy/JumpListManager.cs
new file mode 100644
index 0000000..20a5e63
--- /dev/null
+++ b/Tomboy/JumpListManager.cs
@@ -0,0 +1,205 @@
+//#if WIN32
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using Tomboy.Windows.Interop;
+using IShellLink = Tomboy.Windows.Interop.IShellLinkW;
+using Mono.Unix;
+
+namespace Tomboy
+{
+ public class JumpListManager
+ {
+ private static readonly string NoteIcon = "note.ico";
+ private static readonly string NewNoteIcon = "new_note.ico";
+ private static readonly string SearchIcon = "search.ico";
+
+ private static readonly string tomboy_path = System.Reflection.Assembly.GetExecutingAssembly ().Location;
+ private static readonly string icons_path = tomboy_path.Substring (0, tomboy_path.LastIndexOf ('\\') + 1);
+
+ public static void CreateJumpList ()
+ {
+ CreateJumpList (null);
+ }
+
+ public static void CreateJumpList (NoteManager note_manager)
+ {
+ try {
+ ICustomDestinationList custom_destinationd_list =
+ (ICustomDestinationList) Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.DestinationList));
+
+ uint slots;
+ Guid riid = CLSID.IObjectArray;
+ IObjectArray removed_objects;
+
+ Logger.Debug ("Windows Taskbar: Begin jump list");
+ custom_destinationd_list.BeginList (out slots, ref riid, out removed_objects);
+
+ AddUserTasks (custom_destinationd_list);
+ AddRecentNotes (custom_destinationd_list, note_manager, slots);
+
+ Logger.Debug ("Windows Taskbar: Commit jump list");
+ custom_destinationd_list.CommitList ();
+
+ Marshal.FinalReleaseComObject (removed_objects);
+ removed_objects = null;
+
+ Marshal.FinalReleaseComObject (custom_destinationd_list);
+ custom_destinationd_list = null;
+ } catch (COMException e) {
+ Logger.Error ("Error creating jump list: {0}\n{1}", e.Message, e.StackTrace);
+ }
+ }
+
+ public static void DeleteJumpList ()
+ {
+ try {
+ ICustomDestinationList custom_destinationd_list =
+ (ICustomDestinationList) Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.DestinationList));
+
+ Logger.Debug ("Windows Taskbar: Remove jump list");
+ custom_destinationd_list.DeleteList (null);
+
+ Marshal.FinalReleaseComObject (custom_destinationd_list);
+ custom_destinationd_list = null;
+ } catch (COMException e) {
+ Logger.Error ("Error removing jump list: {0}\n{1}", e.Message, e.StackTrace);
+ }
+ }
+
+ private static void AddUserTasks (ICustomDestinationList custom_destinationd_list)
+ {
+ IObjectCollection object_collection =
+ (IObjectCollection) Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.EnumerableObjectCollection));
+
+ IShellLink search_notes = CreateShellLink ("Search All Notes", tomboy_path, "--search",
+ icons_path + SearchIcon, -1);
+ if (search_notes != null)
+ object_collection.AddObject (search_notes);
+
+ //IShellLink new_notebook = CreateShellLink("New Notebook", topmboy_path, "--new-notebook",
+ // icons_path, (int)TomboyIcons.NewNotebook);
+ //if (new_notebook != null)
+ // object_collection.AddObject(new_notebook);
+
+ IShellLink new_note = CreateShellLink ("Create New Note", tomboy_path, "--new-note",
+ icons_path + NewNoteIcon, -1);
+ if (new_note != null)
+ object_collection.AddObject (new_note);
+
+ custom_destinationd_list.AddUserTasks ((IObjectArray) object_collection);
+
+ Marshal.ReleaseComObject (object_collection);
+ object_collection = null;
+ }
+
+ private static void AddRecentNotes (ICustomDestinationList custom_destinationd_list, NoteManager note_manager, uint slots)
+ {
+ IObjectCollection object_collection =
+ (IObjectCollection) Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.EnumerableObjectCollection));
+
+ // Prevent template notes from appearing in the menu
+ Tag template_tag = TagManager.GetOrCreateSystemTag (TagManager.TemplateNoteSystemTag);
+
+ uint index = 0;
+ foreach (Note note in note_manager.Notes) {
+ if (note.IsSpecial)
+ continue;
+
+ // Skip template notes
+ if (note.ContainsTag (template_tag))
+ continue;
+
+ string note_title = note.Title;
+ if (note.IsNew) {
+ note_title += Catalog.GetString (" (new)");
+ }
+
+ IShellLink note_link = CreateShellLink (note_title, tomboy_path, "--open-note " + note.Uri,
+ icons_path + NoteIcon, -1);
+ if (note_link != null)
+ object_collection.AddObject (note_link);
+
+ if (++index == slots - 1)
+ break;
+ }
+
+ // Add Start Here note
+ Note start_note = note_manager.FindByUri (NoteManager.StartNoteUri);
+ IShellLink start_note_link = CreateShellLink (start_note.Title, tomboy_path, "--open-note " +
+ NoteManager.StartNoteUri, icons_path + NoteIcon, -1);
+ if (start_note_link != null)
+ object_collection.AddObject (start_note_link);
+
+ custom_destinationd_list.AppendCategory ("Recent Notes", (IObjectArray) object_collection);
+
+ Marshal.ReleaseComObject (object_collection);
+ object_collection = null;
+ }
+
+ private static IShellLink CreateShellLink (string title, string path)
+ {
+ return CreateShellLink (title, path, string.Empty, string.Empty, 0);
+ }
+
+ private static IShellLink CreateShellLink (string title, string path, string arguments)
+ {
+ return CreateShellLink (title, path, arguments, string.Empty, 0);
+ }
+
+ private static IShellLink CreateShellLink (string title, string path, string arguments, string icon_path, int icon_pos)
+ {
+ try {
+ IShellLink shell_link = (IShellLink) Activator.CreateInstance (Type.GetTypeFromCLSID (CLSID.ShellLink));
+ shell_link.SetPath (path);
+
+ if (!string.IsNullOrEmpty (arguments))
+ shell_link.SetArguments (arguments);
+
+ if (!string.IsNullOrEmpty (icon_path))
+ shell_link.SetIconLocation (icon_path, icon_pos);
+
+ IntPtr pps;
+ Guid ipsiid = CLSID.IPropertyStore;
+
+ Marshal.QueryInterface (Marshal.GetIUnknownForObject (shell_link), ref ipsiid, out pps);
+ IPropertyStore property_store = (IPropertyStore) Marshal.GetTypedObjectForIUnknown (pps, typeof (IPropertyStore));
+
+ PROPVARIANT propvar = new PROPVARIANT ();
+ propvar.SetString (title);
+
+ // PKEY_Title
+ PROPERTYKEY PKEY_Title = new PROPERTYKEY ();
+ PKEY_Title.fmtid = new Guid ("F29F85E0-4FF9-1068-AB91-08002B27B3D9");
+ PKEY_Title.pid = 2;
+
+ property_store.SetValue (ref PKEY_Title, ref propvar);
+ property_store.Commit ();
+
+ IntPtr psl;
+ Guid psliid = CLSID.IShellLinkW;
+
+ Marshal.QueryInterface (Marshal.GetIUnknownForObject (shell_link), ref psliid, out psl);
+ IShellLink link = (IShellLink) Marshal.GetTypedObjectForIUnknown (psl, typeof (IShellLink));
+
+ propvar.Clear ();
+
+ Marshal.ReleaseComObject (property_store);
+ property_store = null;
+
+ Marshal.ReleaseComObject (shell_link);
+ shell_link = null;
+
+ return link;
+ } catch (COMException e) {
+ Logger.Error ("Error createing shell link: {0}\n{1}", e.Message, e.StackTrace);
+ }
+
+ return null;
+ }
+ }
+}
+
+//#endif // WIN32
diff --git a/Tomboy/Tomboy.cs b/Tomboy/Tomboy.cs
index 50f2c2e..319630b 100644
--- a/Tomboy/Tomboy.cs
+++ b/Tomboy/Tomboy.cs
@@ -116,6 +116,27 @@ namespace Tomboy
}
#endif
+#if WIN32
+ if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
+ var os_version = Environment.OSVersion.Version;
+ if (( os_version.Major == 6 && os_version.Minor > 0 ) || os_version.Major > 6) {
+ JumpListManager.CreateJumpList (manager);
+
+ manager.NoteAdded += delegate (object sender, Note changed) {
+ JumpListManager.CreateJumpList (manager);
+ };
+
+ manager.NoteRenamed += delegate (Note sender, string old_title) {
+ JumpListManager.CreateJumpList (manager);
+ };
+
+ manager.NoteDeleted += delegate (object sender, Note changed) {
+ JumpListManager.CreateJumpList (manager);
+ };
+ }
+ }
+#endif
+
if (is_panel_applet) {
tray_icon_showing = true;
diff --git a/Tomboy/WindowsInterop.cs b/Tomboy/WindowsInterop.cs
new file mode 100644
index 0000000..30fc43a
--- /dev/null
+++ b/Tomboy/WindowsInterop.cs
@@ -0,0 +1,240 @@
+//#if WIN32
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+
+using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
+
+namespace Tomboy.Windows.Interop
+{
+ public enum eKnownDestCategory
+ {
+ Frequent = 1,
+ Recent
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct WIN32_FIND_DATAW
+ {
+ public int FileAttributes;
+ public FILETIME CreationTime;
+ public FILETIME LastAccessTime;
+ public FILETIME LastWriteTime;
+ public int FileSizeHigh;
+ public int FileSizeLow;
+ public int Reserved0;
+ public int Reserved1;
+ [MarshalAs (UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
+ public string FileName;
+ [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 14)]
+ public string AlternateFileName;
+ private const int MAX_PATH = 260;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct PROPERTYKEY
+ {
+ public Guid fmtid;
+ public uint pid;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ public struct PROPVARIANT
+ {
+ ushort vt;
+ ushort wReserved1;
+ ushort wReserved2;
+ ushort wReserved3;
+ IntPtr p;
+ int p2;
+
+ private byte [] GetDataBytes ()
+ {
+ byte [] ret = new byte [IntPtr.Size + sizeof (int)];
+ if (IntPtr.Size == 4)
+ BitConverter.GetBytes (p.ToInt32 ()).CopyTo (ret, 0);
+ else if (IntPtr.Size == 8)
+ BitConverter.GetBytes (p.ToInt64 ()).CopyTo (ret, 0);
+ BitConverter.GetBytes (p2).CopyTo (ret, IntPtr.Size);
+ return ret;
+ }
+
+ [DllImport ("ole32.dll")]
+ private extern static int PropVariantClear (ref PROPVARIANT pvar);
+
+ public void Clear ()
+ {
+ PROPVARIANT var = this;
+ PropVariantClear (ref var);
+
+ vt = (ushort) VarEnum.VT_EMPTY;
+ wReserved1 = wReserved2 = wReserved3 = 0;
+ p = IntPtr.Zero;
+ p2 = 0;
+ }
+
+ public VarEnum Type
+ {
+ get { return (VarEnum) vt; }
+ }
+
+ public object Value
+ {
+ get
+ {
+ switch ((VarEnum) vt) {
+ case VarEnum.VT_LPWSTR:
+ return Marshal.PtrToStringUni (p);
+ case VarEnum.VT_UNKNOWN:
+ return Marshal.GetObjectForIUnknown (p);
+ case VarEnum.VT_DISPATCH:
+ return p;
+ default:
+ throw new NotSupportedException ("The type of this variable is not support ('" + vt.ToString () + "')");
+ }
+ }
+ }
+
+ public void SetString (string value)
+ {
+ vt = (ushort) VarEnum.VT_LPWSTR;
+ p = Marshal.StringToCoTaskMemUni (value);
+ }
+ }
+
+ [ComImport, Guid ("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IShellItem
+ {
+ void BindToHandler ([In] IBindCtx bindCtx, [In] ref Guid bhid, [In] ref Guid riid, [Out] out object ppv);
+
+ void GetParent ([Out] IShellItem shellItem);
+
+ void GetDisplayName ([In] uint sigdnName, [Out, MarshalAs (UnmanagedType.LPWStr)] out string name);
+
+ void GetAttributes ([In] uint mask, [Out] out uint attributes);
+
+ void Compare ([In] IShellItem shellItem, [In] uint sichIntf, [Out] out int order);
+ }
+
+ [ComImport, Guid ("000214F9-0000-0000-C000-000000000046")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IShellLinkW
+ {
+ void GetPath ([Out, MarshalAs (UnmanagedType.LPWStr)] out string file, [In] int cch, [In, Out] WIN32_FIND_DATAW data, [In] uint flags);
+
+ void GetIDList ([Out] IntPtr idl);
+
+ void SetIDList ([In] IntPtr idl);
+
+ void GetDescription ([Out, MarshalAs (UnmanagedType.LPWStr)] out string name, [In] int cch);
+
+ void SetDescription ([In, MarshalAs (UnmanagedType.LPWStr)] string name);
+
+ void GetWorkingDirectory ([Out, MarshalAs (UnmanagedType.LPWStr)] out string name, [In] int cch);
+
+ void SetWorkingDirectory ([In, MarshalAs (UnmanagedType.LPWStr)] string name);
+
+ void GetArguments ([Out, MarshalAs (UnmanagedType.LPWStr)] out string name, [In] int cch);
+
+ void SetArguments ([In, MarshalAs (UnmanagedType.LPWStr)] string name);
+
+ void GetHotkey ([Out] out ushort hotkey);
+
+ void SetHotkey ([In] ushort hotkey);
+
+ void GetShowCmd ([Out] out int showCmd);
+
+ void SetShowCmd ([In] int showCmd);
+
+ void GetIconLocation ([Out, MarshalAs (UnmanagedType.LPWStr)] out string iconPath, [In] int cch, [Out] int icon);
+
+ void SetIconLocation ([In, MarshalAs (UnmanagedType.LPWStr)] string iconPath, [In] int icon);
+
+ void SetRelativePath ([In, MarshalAs (UnmanagedType.LPWStr)] string pathrel, [In] ushort reserved);
+
+ void Resolve ([In] IntPtr hwnd, [In] ushort flags);
+
+ void SetPath ([In, MarshalAs (UnmanagedType.LPWStr)] string path);
+ }
+
+ [ComImport, Guid ("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IPropertyStore
+ {
+ void GetCount ([Out] out ushort cProps);
+
+ void GetAt ([In] ushort prop, [Out] out PROPERTYKEY key);
+
+ void GetValue ([In] ref PROPERTYKEY key, [Out] out PROPVARIANT val);
+
+ void SetValue ([In] ref PROPERTYKEY key, [In] ref PROPVARIANT val);
+
+ void Commit ();
+ }
+
+ [ComImport, Guid ("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IObjectArray
+ {
+ void GetCount ([Out] out uint cObjects);
+
+ void GetAt ([In] uint uiIndex, [In] ref Guid riid, [Out, MarshalAs (UnmanagedType.Interface)] out object ppv);
+ }
+
+ [ComImport, Guid ("5632b1a4-e38a-400a-928a-d4cd63230295")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IObjectCollection
+ {
+ [PreserveSig]
+ void GetCount ([Out] out uint cObjects);
+
+ [PreserveSig]
+ void GetAt ([In] uint uiIndex, [In] ref Guid riid, [Out, MarshalAs (UnmanagedType.Interface)] out object ppv);
+
+ void AddObject ([In, MarshalAs (UnmanagedType.Interface)] object pvObject);
+
+ void AddFromArray ([In, MarshalAs (UnmanagedType.Interface)] IObjectArray source);
+
+ void RemoveObjectAt ([In] uint index);
+
+ void Clear ();
+ }
+
+ [ComImport, Guid ("6332debf-87b5-4670-90c0-5e57b408a49e")]
+ [InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
+ public interface ICustomDestinationList
+ {
+ void SetAppID ([In, MarshalAs (UnmanagedType.LPWStr)] string appID);
+
+ void BeginList ([Out] out uint cMinSlots, [In] ref Guid riid, [Out, MarshalAs (UnmanagedType.Interface)] out IObjectArray ppv);
+
+ void AppendCategory ([In, MarshalAs (UnmanagedType.LPWStr)] string category, [In] IObjectArray objectArray);
+
+ void AppendKnownCategory ([In] eKnownDestCategory category);
+
+ void AddUserTasks ([In, MarshalAs (UnmanagedType.Interface)] IObjectArray objectArray);
+
+ void CommitList ();
+
+ void GetRemovedDestinations ([In] Guid riid, [Out] out object ppv);
+
+ void DeleteList ([In, MarshalAs (UnmanagedType.LPWStr)] string appID);
+
+ void AbortList ();
+ }
+
+ public struct CLSID
+ {
+ public static readonly Guid IObjectArray = new Guid ("92CA9DCD-5622-4bba-A805-5E9F541BD8C9");
+ public static readonly Guid IPropertyStore = new Guid ("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99");
+ public static readonly Guid IShellLinkW = new Guid ("000214F9-0000-0000-C000-000000000046");
+ public static readonly Guid DestinationList = new Guid ("77f10cf0-3db5-4966-b520-b7c54fd35ed6");
+ public static readonly Guid EnumerableObjectCollection = new Guid ("2d3468c1-36a7-43b6-ac24-d3f02fd9607a");
+ public static readonly Guid ShellItem = new Guid ("9ac9fbe1-e0a2-4ad6-b4ee-e212013ea917");
+ public static readonly Guid ShellLink = new Guid ("00021401-0000-0000-C000-000000000046");
+ }
+}
+
+//#endif // WIN32
diff --git a/data/icons/new_note.ico b/data/icons/new_note.ico
new file mode 100644
index 0000000..833006f
Binary files /dev/null and b/data/icons/new_note.ico differ
diff --git a/data/icons/note.ico b/data/icons/note.ico
new file mode 100644
index 0000000..f6c13a0
Binary files /dev/null and b/data/icons/note.ico differ
diff --git a/data/icons/search.ico b/data/icons/search.ico
new file mode 100644
index 0000000..4d1f827
Binary files /dev/null and b/data/icons/search.ico differ
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]