~ubuntu-branches/ubuntu/wily/keepass2/wily-proposed

« back to all changes in this revision

Viewing changes to KeePassLib/Utility/MonoWorkarounds.cs

  • Committer: Package Import Robot
  • Author(s): Julian Taylor
  • Date: 2014-08-17 15:55:03 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20140817155503-3jcbkd107zug4clp
Tags: 2.27+dfsg-1
* New upstream release (Closes: #754575)
* remove upstream applied fix-webdav-storage-with-mono-2.11.patch
* add fix-autotype-paste.patch to fix pasting with autotype
* mention the need for the mono-mcs package to be installed for plugins to
  work in README.Debian (Closes: #749346)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  KeePass Password Safe - The Open-Source Password Manager
 
3
  Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
 
4
 
 
5
  This program is free software; you can redistribute it and/or modify
 
6
  it under the terms of the GNU General Public License as published by
 
7
  the Free Software Foundation; either version 2 of the License, or
 
8
  (at your option) any later version.
 
9
 
 
10
  This program is distributed in the hope that it will be useful,
 
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
  GNU General Public License for more details.
 
14
 
 
15
  You should have received a copy of the GNU General Public License
 
16
  along with this program; if not, write to the Free Software
 
17
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
*/
 
19
 
 
20
using System;
 
21
using System.Collections.Generic;
 
22
using System.Text;
 
23
using System.Windows.Forms;
 
24
using System.ComponentModel;
 
25
using System.Reflection;
 
26
using System.Diagnostics;
 
27
 
 
28
using KeePassLib.Native;
 
29
 
 
30
namespace KeePassLib.Utility
 
31
{
 
32
        public static class MonoWorkarounds
 
33
        {
 
34
                private static bool? m_bReq = null;
 
35
                public static bool IsRequired()
 
36
                {
 
37
                        if(!m_bReq.HasValue) m_bReq = NativeLib.IsUnix();
 
38
                        return m_bReq.Value;
 
39
                }
 
40
 
 
41
                // 1245:
 
42
                //   Key events not raised while Alt is down, and nav keys out of order.
 
43
                //   https://sourceforge.net/p/keepass/bugs/1245/
 
44
                // 1254:
 
45
                //   NumericUpDown bug: text is drawn below up/down buttons.
 
46
                //   https://sourceforge.net/p/keepass/bugs/1254/
 
47
                // 5795:
 
48
                //   Text in input field is incomplete.
 
49
                //   https://bugzilla.xamarin.com/show_bug.cgi?id=5795
 
50
                //   https://sourceforge.net/p/keepass/discussion/329220/thread/d23dc88b/
 
51
                // 10163:
 
52
                //   WebRequest GetResponse call missing, breaks WebDAV due to no PUT.
 
53
                //   https://bugzilla.xamarin.com/show_bug.cgi?id=10163
 
54
                //   https://sourceforge.net/p/keepass/bugs/1117/
 
55
                //   https://sourceforge.net/p/keepass/discussion/329221/thread/9422258c/
 
56
                //   https://github.com/mono/mono/commit/8e67b8c2fc7cb66bff7816ebf7c1039fb8cfc43b
 
57
                //   https://bugzilla.xamarin.com/show_bug.cgi?id=1512
 
58
                //   https://sourceforge.net/p/keepass/patches/89/
 
59
                // 12525:
 
60
                //   PictureBox not rendered when bitmap height >= control height.
 
61
                //   https://bugzilla.xamarin.com/show_bug.cgi?id=12525
 
62
                //   https://sourceforge.net/p/keepass/discussion/329220/thread/54f61e9a/
 
63
                // 586901:
 
64
                //   RichTextBox doesn't handle Unicode string correctly.
 
65
                //   https://bugzilla.novell.com/show_bug.cgi?id=586901
 
66
                // 620618:
 
67
                //   ListView column headers not drawn.
 
68
                //   https://bugzilla.novell.com/show_bug.cgi?id=620618
 
69
                // 649266:
 
70
                //   Calling Control.Hide doesn't remove the application from taskbar.
 
71
                //   https://bugzilla.novell.com/show_bug.cgi?id=649266
 
72
                // 686017:
 
73
                //   Minimum sizes must be enforced.
 
74
                //   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=686017
 
75
                // 801414:
 
76
                //   Mono recreates the main window incorrectly.
 
77
                //   https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/801414
 
78
                // 891029:
 
79
                //   Increase tab control height, otherwise Mono throws exceptions.
 
80
                //   https://sourceforge.net/projects/keepass/forums/forum/329221/topic/4519750
 
81
                //   https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/891029
 
82
                // 836428016:
 
83
                //   ListView group header selection unsupported.
 
84
                //   https://sourceforge.net/p/keepass/discussion/329221/thread/31dae0f0/
 
85
                // 3574233558:
 
86
                //   Problems with minimizing windows, no content rendered.
 
87
                //   https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/
 
88
                public static bool IsRequired(uint uBugID)
 
89
                {
 
90
                        if(!MonoWorkarounds.IsRequired()) return false;
 
91
 
 
92
                        ulong v = NativeLib.MonoVersion;
 
93
                        if(v != 0)
 
94
                        {
 
95
                                if(uBugID == 10163)
 
96
                                        return (v >= 0x0002000B00000000UL); // >= 2.11
 
97
                        }
 
98
 
 
99
                        return true;
 
100
                }
 
101
 
 
102
                public static void ApplyTo(Form f)
 
103
                {
 
104
                        if(!MonoWorkarounds.IsRequired()) return;
 
105
                        if(f == null) { Debug.Assert(false); return; }
 
106
 
 
107
#if (!KeePassLibSD && !KeePassRT)
 
108
                        f.HandleCreated += MonoWorkarounds.OnFormHandleCreated;
 
109
                        SetWmClass(f);
 
110
 
 
111
                        ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ApplyToControl);
 
112
#endif
 
113
                }
 
114
 
 
115
                public static void Release(Form f)
 
116
                {
 
117
                        if(!MonoWorkarounds.IsRequired()) return;
 
118
                        if(f == null) { Debug.Assert(false); return; }
 
119
 
 
120
#if (!KeePassLibSD && !KeePassRT)
 
121
                        f.HandleCreated -= MonoWorkarounds.OnFormHandleCreated;
 
122
 
 
123
                        ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ReleaseControl);
 
124
#endif
 
125
                }
 
126
 
 
127
#if (!KeePassLibSD && !KeePassRT)
 
128
                private delegate void MwaControlHandler(Control c, Form fContext);
 
129
 
 
130
                private static void ApplyToControlsRec(Control.ControlCollection cc,
 
131
                        Form fContext, MwaControlHandler fn)
 
132
                {
 
133
                        if(cc == null) { Debug.Assert(false); return; }
 
134
 
 
135
                        foreach(Control c in cc)
 
136
                        {
 
137
                                fn(c, fContext);
 
138
                                ApplyToControlsRec(c.Controls, fContext, fn);
 
139
                        }
 
140
                }
 
141
 
 
142
                private static void ApplyToControl(Control c, Form fContext)
 
143
                {
 
144
                        Button btn = (c as Button);
 
145
                        if(btn != null) ApplyToButton(btn, fContext);
 
146
 
 
147
                        NumericUpDown nc = (c as NumericUpDown);
 
148
                        if((nc != null) && MonoWorkarounds.IsRequired(1254))
 
149
                        {
 
150
                                if(nc.TextAlign == HorizontalAlignment.Right)
 
151
                                        nc.TextAlign = HorizontalAlignment.Left;
 
152
                        }
 
153
                }
 
154
 
 
155
                private sealed class MwaHandlerInfo
 
156
                {
 
157
                        private readonly Delegate m_fnOrg; // May be null
 
158
                        public Delegate FunctionOriginal
 
159
                        {
 
160
                                get { return m_fnOrg; }
 
161
                        }
 
162
 
 
163
                        private readonly Delegate m_fnOvr;
 
164
                        public Delegate FunctionOverride
 
165
                        {
 
166
                                get { return m_fnOvr; }
 
167
                        }
 
168
 
 
169
                        private readonly DialogResult m_dr;
 
170
                        public DialogResult Result
 
171
                        {
 
172
                                get { return m_dr; }
 
173
                        }
 
174
 
 
175
                        private readonly Form m_fContext;
 
176
                        public Form FormContext
 
177
                        {
 
178
                                get { return m_fContext; }
 
179
                        }
 
180
 
 
181
                        public MwaHandlerInfo(Delegate fnOrg, Delegate fnOvr, DialogResult dr,
 
182
                                Form fContext)
 
183
                        {
 
184
                                m_fnOrg = fnOrg;
 
185
                                m_fnOvr = fnOvr;
 
186
                                m_dr = dr;
 
187
                                m_fContext = fContext;
 
188
                        }
 
189
                }
 
190
 
 
191
                private static EventHandlerList GetEventHandlers(Component c,
 
192
                        out object objClickEvent)
 
193
                {
 
194
                        FieldInfo fi = typeof(Control).GetField("ClickEvent", // Mono
 
195
                                BindingFlags.Static | BindingFlags.NonPublic);
 
196
                        if(fi == null)
 
197
                                fi = typeof(Control).GetField("EventClick", // .NET
 
198
                                        BindingFlags.Static | BindingFlags.NonPublic);
 
199
                        if(fi == null) { Debug.Assert(false); objClickEvent = null; return null; }
 
200
 
 
201
                        objClickEvent = fi.GetValue(null);
 
202
                        if(objClickEvent == null) { Debug.Assert(false); return null; }
 
203
 
 
204
                        PropertyInfo pi = typeof(Component).GetProperty("Events",
 
205
                                BindingFlags.Instance | BindingFlags.NonPublic);
 
206
                        return (pi.GetValue(c, null) as EventHandlerList);
 
207
                }
 
208
 
 
209
                private static Dictionary<object, MwaHandlerInfo> m_dictHandlers =
 
210
                        new Dictionary<object, MwaHandlerInfo>();
 
211
                private static void ApplyToButton(Button btn, Form fContext)
 
212
                {
 
213
                        DialogResult dr = btn.DialogResult;
 
214
                        if(dr == DialogResult.None) return; // No workaround required
 
215
 
 
216
                        object objClickEvent;
 
217
                        EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent);
 
218
                        if(ehl == null) { Debug.Assert(false); return; }
 
219
                        Delegate fnClick = ehl[objClickEvent]; // May be null
 
220
 
 
221
                        EventHandler fnOvr = new EventHandler(MonoWorkarounds.OnButtonClick);
 
222
                        m_dictHandlers[btn] = new MwaHandlerInfo(fnClick, fnOvr, dr, fContext);
 
223
 
 
224
                        btn.DialogResult = DialogResult.None;
 
225
                        if(fnClick != null) ehl.RemoveHandler(objClickEvent, fnClick);
 
226
                        ehl[objClickEvent] = fnOvr;
 
227
                }
 
228
 
 
229
                private static void ReleaseControl(Control c, Form fContext)
 
230
                {
 
231
                        Button btn = (c as Button);
 
232
                        if(btn != null) ReleaseButton(btn, fContext);
 
233
                }
 
234
 
 
235
                private static void ReleaseButton(Button btn, Form fContext)
 
236
                {
 
237
                        MwaHandlerInfo hi;
 
238
                        m_dictHandlers.TryGetValue(btn, out hi);
 
239
                        if(hi == null) return;
 
240
 
 
241
                        object objClickEvent;
 
242
                        EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent);
 
243
                        if(ehl == null) { Debug.Assert(false); return; }
 
244
 
 
245
                        ehl.RemoveHandler(objClickEvent, hi.FunctionOverride);
 
246
                        if(hi.FunctionOriginal != null)
 
247
                                ehl[objClickEvent] = hi.FunctionOriginal;
 
248
 
 
249
                        btn.DialogResult = hi.Result;
 
250
                        m_dictHandlers.Remove(btn);
 
251
                }
 
252
 
 
253
                private static void OnButtonClick(object sender, EventArgs e)
 
254
                {
 
255
                        Button btn = (sender as Button);
 
256
                        if(btn == null) { Debug.Assert(false); return; }
 
257
 
 
258
                        MwaHandlerInfo hi;
 
259
                        m_dictHandlers.TryGetValue(btn, out hi);
 
260
                        if(hi == null) { Debug.Assert(false); return; }
 
261
 
 
262
                        Form f = hi.FormContext;
 
263
 
 
264
                        // Set current dialog result by setting the form's private
 
265
                        // variable; the DialogResult property can't be used,
 
266
                        // because it raises close events
 
267
                        FieldInfo fiRes = typeof(Form).GetField("dialog_result",
 
268
                                BindingFlags.Instance | BindingFlags.NonPublic);
 
269
                        if(fiRes == null) { Debug.Assert(false); return; }
 
270
                        if(f != null) fiRes.SetValue(f, hi.Result);
 
271
 
 
272
                        if(hi.FunctionOriginal != null)
 
273
                                hi.FunctionOriginal.Method.Invoke(hi.FunctionOriginal.Target,
 
274
                                        new object[] { btn, e });
 
275
 
 
276
                        // Raise close events, if the click event handler hasn't
 
277
                        // reset the dialog result
 
278
                        if((f != null) && (f.DialogResult == hi.Result))
 
279
                                f.DialogResult = hi.Result; // Raises close events
 
280
                }
 
281
 
 
282
                private static void SetWmClass(Form f)
 
283
                {
 
284
                        NativeMethods.SetWmClass(f, PwDefs.UnixName, PwDefs.ResClass);
 
285
                }
 
286
 
 
287
                private static void OnFormHandleCreated(object sender, EventArgs e)
 
288
                {
 
289
                        Form f = (sender as Form);
 
290
                        if(f == null) { Debug.Assert(false); return; }
 
291
 
 
292
                        if(!f.IsHandleCreated) return; // Prevent infinite loop
 
293
 
 
294
                        SetWmClass(f);
 
295
                }
 
296
 
 
297
                /// <summary>
 
298
                /// Set the value of the private <c>shown_raised</c> member
 
299
                /// variable of a form.
 
300
                /// </summary>
 
301
                /// <returns>Previous <c>shown_raised</c> value.</returns>
 
302
                internal static bool ExchangeFormShownRaised(Form f, bool bNewValue)
 
303
                {
 
304
                        if(f == null) { Debug.Assert(false); return true; }
 
305
 
 
306
                        try
 
307
                        {
 
308
                                FieldInfo fi = typeof(Form).GetField("shown_raised",
 
309
                                        BindingFlags.Instance | BindingFlags.NonPublic);
 
310
                                if(fi == null) { Debug.Assert(false); return true; }
 
311
 
 
312
                                bool bPrevious = (bool)fi.GetValue(f);
 
313
 
 
314
                                fi.SetValue(f, bNewValue);
 
315
 
 
316
                                return bPrevious;
 
317
                        }
 
318
                        catch(Exception) { Debug.Assert(false); }
 
319
 
 
320
                        return true;
 
321
                }
 
322
#endif
 
323
        }
 
324
}