Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comctl32_v6/syslink.c
5968 views
1
/*
2
* SysLink control
3
*
4
* Copyright 2004 - 2006 Thomas Weidenmueller <[email protected]>
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#define COBJMACROS
22
#include <stdarg.h>
23
#include <string.h>
24
#include "windef.h"
25
#include "winbase.h"
26
#include "wingdi.h"
27
#include "winuser.h"
28
#include "winnls.h"
29
#include "commctrl.h"
30
#include "comctl32.h"
31
#include "oaidl.h"
32
#include "initguid.h"
33
#include "oleacc.h"
34
#include "wine/debug.h"
35
#include "wine/list.h"
36
37
WINE_DEFAULT_DEBUG_CHANNEL(syslink);
38
39
typedef struct
40
{
41
int nChars;
42
int nSkip;
43
RECT rc;
44
} DOC_TEXTBLOCK, *PDOC_TEXTBLOCK;
45
46
#define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL)
47
#define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED)
48
49
typedef enum
50
{
51
slText = 0,
52
slLink
53
} SL_ITEM_TYPE;
54
55
typedef struct _DOC_ITEM
56
{
57
struct list entry;
58
UINT nText; /* Number of characters of the text */
59
SL_ITEM_TYPE Type; /* type of the item */
60
PDOC_TEXTBLOCK Blocks; /* Array of text blocks */
61
union
62
{
63
struct
64
{
65
UINT state; /* Link state */
66
WCHAR *szID; /* Link ID string */
67
WCHAR *szUrl; /* Link URL string */
68
} Link;
69
struct
70
{
71
UINT Dummy;
72
} Text;
73
} u;
74
WCHAR Text[1]; /* Text of the document item */
75
} DOC_ITEM, *PDOC_ITEM;
76
77
typedef struct SYSLINK_INFO SYSLINK_INFO;
78
79
typedef struct
80
{
81
IAccessible IAccessible_iface;
82
IOleWindow IOleWindow_iface;
83
struct SYSLINK_INFO *infoPtr;
84
LONG refcount;
85
} SYSLINK_ACC;
86
87
struct SYSLINK_INFO
88
{
89
HWND Self; /* The window handle for this control */
90
HWND Notify; /* The parent handle to receive notifications */
91
DWORD Style; /* Styles for this control */
92
struct list Items; /* Document items list */
93
BOOL HasFocus; /* Whether the control has the input focus */
94
int MouseDownID; /* ID of the link that the mouse button first selected */
95
HFONT Font; /* Handle to the font for text */
96
HFONT LinkFont; /* Handle to the font for links */
97
COLORREF TextColor; /* Color of the text */
98
COLORREF LinkColor; /* Color of links */
99
COLORREF VisitedColor; /* Color of visited links */
100
WCHAR BreakChar; /* Break Character for the current font */
101
BOOL IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */
102
SYSLINK_ACC *AccessibleImpl; /* IAccessible implementation */
103
};
104
105
/* Control configuration constants */
106
107
#define SL_LEFTMARGIN (0)
108
#define SL_TOPMARGIN (0)
109
#define SL_RIGHTMARGIN (0)
110
#define SL_BOTTOMMARGIN (0)
111
112
static inline SYSLINK_ACC *impl_from_IAccessible(IAccessible *iface)
113
{
114
return CONTAINING_RECORD(iface, SYSLINK_ACC, IAccessible_iface);
115
}
116
117
static inline SYSLINK_ACC *impl_from_IOleWindow(IOleWindow *iface)
118
{
119
return CONTAINING_RECORD(iface, SYSLINK_ACC, IOleWindow_iface);
120
}
121
122
static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID iid, void **ppv)
123
{
124
SYSLINK_ACC *This = impl_from_IAccessible(iface);
125
TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
126
127
if (!ppv) return E_INVALIDARG;
128
129
if (IsEqualIID(&IID_IUnknown, iid) ||
130
IsEqualIID(&IID_IAccessible, iid))
131
{
132
*ppv = &This->IAccessible_iface;
133
}
134
else if (IsEqualIID(&IID_IOleWindow, iid))
135
{
136
*ppv = &This->IOleWindow_iface;
137
}
138
else
139
{
140
*ppv = NULL;
141
return E_NOINTERFACE;
142
}
143
144
IUnknown_AddRef((IUnknown*)*ppv);
145
return S_OK;
146
}
147
148
static ULONG WINAPI Accessible_AddRef(IAccessible *iface)
149
{
150
SYSLINK_ACC *This = impl_from_IAccessible(iface);
151
return InterlockedIncrement(&This->refcount);
152
}
153
154
static ULONG WINAPI Accessible_Release(IAccessible *iface)
155
{
156
SYSLINK_ACC *This = impl_from_IAccessible(iface);
157
ULONG ref = InterlockedDecrement(&This->refcount);
158
159
if (ref == 0)
160
Free(This);
161
162
return ref;
163
}
164
165
static HRESULT WINAPI Accessible_GetTypeInfo(IAccessible *iface, UINT index, LCID lcid, ITypeInfo **info)
166
{
167
FIXME("%p\n", iface);
168
return E_NOTIMPL;
169
}
170
171
static HRESULT WINAPI Accessible_GetIDsOfNames(IAccessible *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *dispid)
172
{
173
FIXME("%p\n", iface);
174
return E_NOTIMPL;
175
}
176
177
static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID dispid, REFIID iid, LCID lcid,
178
WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
179
{
180
FIXME("%p\n", iface);
181
return E_NOTIMPL;
182
}
183
184
static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *count)
185
{
186
FIXME("%p\n", iface);
187
return E_NOTIMPL;
188
}
189
190
static HRESULT Accessible_FindChild(SYSLINK_ACC *This, VARIANT childid, DOC_ITEM** result)
191
{
192
DOC_ITEM *current;
193
int index;
194
195
if (!This->infoPtr)
196
{
197
WARN("control was destroyed\n");
198
return E_FAIL;
199
}
200
201
if (V_VT(&childid) == VT_EMPTY)
202
index = 0;
203
else if (V_VT(&childid) == VT_I4)
204
index = V_I4(&childid);
205
else {
206
WARN("not implemented for vt %s\n", debugstr_vt(V_VT(&childid)));
207
return E_INVALIDARG;
208
}
209
210
if (index == 0)
211
{
212
*result = NULL;
213
return S_OK;
214
}
215
216
LIST_FOR_EACH_ENTRY(current, &This->infoPtr->Items, DOC_ITEM, entry)
217
{
218
if (current->Type != slLink)
219
continue;
220
if (!--index)
221
{
222
*result = current;
223
return S_OK;
224
}
225
}
226
227
WARN("index out of range\n");
228
return E_INVALIDARG;
229
}
230
231
static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch** disp)
232
{
233
FIXME("%p\n", iface);
234
return E_NOTIMPL;
235
}
236
237
static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *count)
238
{
239
SYSLINK_ACC *This = impl_from_IAccessible(iface);
240
DOC_ITEM *current;
241
LONG result = 0;
242
243
TRACE("%p\n", iface);
244
245
if (!This->infoPtr)
246
{
247
WARN("control was destroyed\n");
248
return E_FAIL;
249
}
250
251
LIST_FOR_EACH_ENTRY(current, &This->infoPtr->Items, DOC_ITEM, entry)
252
{
253
if (current->Type == slLink)
254
result++;
255
}
256
257
*count = result;
258
259
return S_OK;
260
}
261
262
static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT childid, IDispatch **disp)
263
{
264
SYSLINK_ACC *This = impl_from_IAccessible(iface);
265
HRESULT hr;
266
DOC_ITEM* item;
267
268
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
269
270
*disp = NULL;
271
272
hr = Accessible_FindChild(This, childid, &item);
273
if (FAILED(hr))
274
return hr;
275
276
if (item)
277
return S_FALSE;
278
else
279
return E_INVALIDARG;
280
}
281
282
static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT childid, BSTR *name)
283
{
284
SYSLINK_ACC *This = impl_from_IAccessible(iface);
285
HRESULT hr;
286
DOC_ITEM* item;
287
BSTR result;
288
289
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
290
291
if (!name)
292
return E_POINTER;
293
294
*name = NULL;
295
296
hr = Accessible_FindChild(This, childid, &item);
297
if (FAILED(hr))
298
return hr;
299
300
if (item)
301
{
302
result = SysAllocString(item->Text);
303
if (!result)
304
return E_OUTOFMEMORY;
305
}
306
else
307
{
308
UINT total_length = 0, i;
309
310
LIST_FOR_EACH_ENTRY(item, &This->infoPtr->Items, DOC_ITEM, entry)
311
{
312
total_length += item->nText;
313
}
314
315
result = SysAllocStringLen(NULL, total_length);
316
if (!result)
317
return E_OUTOFMEMORY;
318
319
i = 0;
320
LIST_FOR_EACH_ENTRY(item, &This->infoPtr->Items, DOC_ITEM, entry)
321
{
322
memcpy(&result[i], item->Text, item->nText * sizeof(*result));
323
i += item->nText;
324
}
325
}
326
327
*name = result;
328
329
return S_OK;
330
}
331
332
static HRESULT WINAPI Accessible_get_accValue(IAccessible *iface, VARIANT childid, BSTR *value)
333
{
334
FIXME("%p\n", iface);
335
return E_NOTIMPL;
336
}
337
338
static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT childid, BSTR *description)
339
{
340
FIXME("%p\n", iface);
341
return E_NOTIMPL;
342
}
343
344
static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT childid, VARIANT *role)
345
{
346
SYSLINK_ACC *This = impl_from_IAccessible(iface);
347
HRESULT hr;
348
DOC_ITEM* item;
349
350
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
351
352
hr = Accessible_FindChild(This, childid, &item);
353
if (FAILED(hr))
354
return hr;
355
356
V_VT(role) = VT_I4;
357
358
if (item)
359
V_I4(role) = ROLE_SYSTEM_LINK;
360
else
361
V_I4(role) = ROLE_SYSTEM_CLIENT;
362
363
return S_OK;
364
}
365
366
static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT childid, VARIANT *state)
367
{
368
SYSLINK_ACC *This = impl_from_IAccessible(iface);
369
HRESULT hr;
370
DOC_ITEM* item;
371
GUITHREADINFO info;
372
BOOL focused = 0;
373
374
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
375
376
hr = Accessible_FindChild(This, childid, &item);
377
if (FAILED(hr))
378
return hr;
379
380
V_VT(state) = VT_I4;
381
V_I4(state) = 0;
382
383
info.cbSize = sizeof(info);
384
if(GetGUIThreadInfo(0, &info) && info.hwndFocus == This->infoPtr->Self)
385
focused = 1;
386
387
if (item)
388
{
389
V_I4(state) |= STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED;
390
if (focused && (item->u.Link.state & LIS_FOCUSED) == LIS_FOCUSED)
391
V_I4(state) |= STATE_SYSTEM_FOCUSED;
392
}
393
else
394
{
395
LONG style = GetWindowLongW(This->infoPtr->Self, GWL_STYLE);
396
397
if (style & WS_DISABLED)
398
V_I4(state) |= STATE_SYSTEM_UNAVAILABLE;
399
else
400
V_I4(state) |= STATE_SYSTEM_FOCUSABLE;
401
if (!(style & WS_VISIBLE))
402
V_I4(state) |= STATE_SYSTEM_INVISIBLE;
403
if (focused)
404
V_I4(state) |= STATE_SYSTEM_FOCUSED;
405
}
406
407
return S_OK;
408
}
409
410
static HRESULT WINAPI Accessible_get_accHelp(IAccessible *iface, VARIANT childid, BSTR *help)
411
{
412
FIXME("%p\n", iface);
413
return E_NOTIMPL;
414
}
415
416
static HRESULT WINAPI Accessible_get_accHelpTopic(IAccessible *iface, BSTR *helpFile, VARIANT childid, LONG *topic)
417
{
418
FIXME("%p\n", iface);
419
return E_NOTIMPL;
420
}
421
422
static HRESULT WINAPI Accessible_get_accKeyboardShortcut(IAccessible *iface, VARIANT childid, BSTR *shortcut)
423
{
424
FIXME("%p\n", iface);
425
return E_NOTIMPL;
426
}
427
428
static HRESULT WINAPI Accessible_get_accFocus(IAccessible *iface, VARIANT *childid)
429
{
430
FIXME("%p\n", iface);
431
return E_NOTIMPL;
432
}
433
434
static HRESULT WINAPI Accessible_get_accSelection(IAccessible *iface, VARIANT *childid)
435
{
436
FIXME("%p\n", iface);
437
return E_NOTIMPL;
438
}
439
440
static HRESULT WINAPI Accessible_get_accDefaultAction(IAccessible *iface, VARIANT childid, BSTR *action)
441
{
442
SYSLINK_ACC *This = impl_from_IAccessible(iface);
443
HRESULT hr;
444
DOC_ITEM* item;
445
446
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
447
448
if (!action)
449
return E_POINTER;
450
451
*action = NULL;
452
453
hr = Accessible_FindChild(This, childid, &item);
454
if (FAILED(hr))
455
return hr;
456
457
if (item)
458
{
459
*action = SysAllocString(L"Click");
460
if (!*action)
461
return E_OUTOFMEMORY;
462
return S_OK;
463
}
464
else
465
{
466
return S_FALSE;
467
}
468
}
469
470
static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG flags, VARIANT childid)
471
{
472
FIXME("%p\n", iface);
473
return E_NOTIMPL;
474
}
475
476
static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *left, LONG *top, LONG *width, LONG *height, VARIANT childid)
477
{
478
SYSLINK_ACC *This = impl_from_IAccessible(iface);
479
HRESULT hr;
480
DOC_ITEM* item;
481
RECT rc = {0};
482
POINT point;
483
484
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
485
486
hr = Accessible_FindChild(This, childid, &item);
487
if (FAILED(hr))
488
return hr;
489
490
if (item)
491
{
492
int n = item->nText;
493
PDOC_TEXTBLOCK block = item->Blocks;
494
495
while (n > 0)
496
{
497
UnionRect(&rc, &rc, &block->rc);
498
n -= block->nChars + block->nSkip;
499
block++;
500
}
501
}
502
else
503
{
504
GetClientRect(This->infoPtr->Self, &rc);
505
}
506
507
point.x = rc.left;
508
point.y = rc.top;
509
MapWindowPoints(This->infoPtr->Self, NULL, &point, 1);
510
*left = point.x;
511
*top = point.y;
512
*width = rc.right - rc.left;
513
*height = rc.bottom - rc.top;
514
515
TRACE("<-- (%li,%li,%li,%li)\n", *left, *top, *width, *height);
516
517
return S_OK;
518
}
519
520
static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG dir, VARIANT start, VARIANT *end)
521
{
522
FIXME("%p\n", iface);
523
return E_NOTIMPL;
524
}
525
526
static HRESULT WINAPI Accessible_accHitTest(IAccessible *iface, LONG left, LONG top, VARIANT* childid)
527
{
528
FIXME("%p\n", iface);
529
return E_NOTIMPL;
530
}
531
532
static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink);
533
534
static HRESULT WINAPI Accessible_accDoDefaultAction(IAccessible *iface, VARIANT childid)
535
{
536
SYSLINK_ACC *This = impl_from_IAccessible(iface);
537
HRESULT hr;
538
DOC_ITEM* item;
539
540
TRACE("%p, %s\n", iface, debugstr_variant(&childid));
541
542
hr = Accessible_FindChild(This, childid, &item);
543
if (FAILED(hr))
544
return hr;
545
546
if (!item)
547
/* Not supported for whole control. */
548
return E_INVALIDARG;
549
550
SYSLINK_SendParentNotify(This->infoPtr, NM_CLICK, item, V_I4(&childid) - 1);
551
552
return S_OK;
553
}
554
555
static HRESULT WINAPI Accessible_put_accName(IAccessible *iface, VARIANT childid, BSTR name)
556
{
557
FIXME("%p\n", iface);
558
return E_NOTIMPL;
559
}
560
561
static HRESULT WINAPI Accessible_put_accValue(IAccessible *iface, VARIANT childid, BSTR value)
562
{
563
FIXME("%p\n", iface);
564
return E_NOTIMPL;
565
}
566
567
static const IAccessibleVtbl Accessible_Vtbl = {
568
Accessible_QueryInterface,
569
Accessible_AddRef,
570
Accessible_Release,
571
Accessible_GetTypeInfoCount,
572
Accessible_GetTypeInfo,
573
Accessible_GetIDsOfNames,
574
Accessible_Invoke,
575
Accessible_get_accParent,
576
Accessible_get_accChildCount,
577
Accessible_get_accChild,
578
Accessible_get_accName,
579
Accessible_get_accValue,
580
Accessible_get_accDescription,
581
Accessible_get_accRole,
582
Accessible_get_accState,
583
Accessible_get_accHelp,
584
Accessible_get_accHelpTopic,
585
Accessible_get_accKeyboardShortcut,
586
Accessible_get_accFocus,
587
Accessible_get_accSelection,
588
Accessible_get_accDefaultAction,
589
Accessible_accSelect,
590
Accessible_accLocation,
591
Accessible_accNavigate,
592
Accessible_accHitTest,
593
Accessible_accDoDefaultAction,
594
Accessible_put_accName,
595
Accessible_put_accValue
596
};
597
598
static HRESULT WINAPI Accessible_Window_QueryInterface(IOleWindow *iface, REFIID iid, void **ppv)
599
{
600
SYSLINK_ACC *This = impl_from_IOleWindow(iface);
601
return IAccessible_QueryInterface(&This->IAccessible_iface, iid, ppv);
602
}
603
604
static ULONG WINAPI Accessible_Window_AddRef(IOleWindow *iface)
605
{
606
SYSLINK_ACC *This = impl_from_IOleWindow(iface);
607
return IAccessible_AddRef(&This->IAccessible_iface);
608
}
609
610
static ULONG WINAPI Accessible_Window_Release(IOleWindow *iface)
611
{
612
SYSLINK_ACC *This = impl_from_IOleWindow(iface);
613
return IAccessible_Release(&This->IAccessible_iface);
614
}
615
616
static HRESULT WINAPI Accessible_GetWindow(IOleWindow *iface, HWND *hwnd)
617
{
618
SYSLINK_ACC *This = impl_from_IOleWindow(iface);
619
620
TRACE("%p\n", This);
621
622
if (!This->infoPtr)
623
return E_FAIL;
624
625
*hwnd = This->infoPtr->Self;
626
return S_OK;
627
}
628
629
static HRESULT WINAPI Accessible_ContextSensitiveHelp(IOleWindow *This, BOOL fEnterMode)
630
{
631
FIXME("%p\b", This);
632
return E_NOTIMPL;
633
}
634
635
static const IOleWindowVtbl Accessible_Window_Vtbl = {
636
Accessible_Window_QueryInterface,
637
Accessible_Window_AddRef,
638
Accessible_Window_Release,
639
Accessible_GetWindow,
640
Accessible_ContextSensitiveHelp
641
};
642
643
static void Accessible_Create(SYSLINK_INFO* infoPtr)
644
{
645
SYSLINK_ACC *This;
646
647
This = Alloc(sizeof(*This));
648
if (!This) return;
649
650
This->IAccessible_iface.lpVtbl = &Accessible_Vtbl;
651
This->IOleWindow_iface.lpVtbl = &Accessible_Window_Vtbl;
652
This->infoPtr = infoPtr;
653
This->refcount = 1;
654
infoPtr->AccessibleImpl = This;
655
}
656
657
static void Accessible_WindowDestroyed(SYSLINK_ACC *This)
658
{
659
This->infoPtr = NULL;
660
IAccessible_Release(&This->IAccessible_iface);
661
}
662
663
/***********************************************************************
664
* SYSLINK_FreeDocItem
665
* Frees all data and gdi objects associated with a document item
666
*/
667
static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem)
668
{
669
if(DocItem->Type == slLink)
670
{
671
Free(DocItem->u.Link.szID);
672
Free(DocItem->u.Link.szUrl);
673
}
674
675
Free(DocItem->Blocks);
676
677
/* we don't free Text because it's just a pointer to a character in the
678
entire window text string */
679
680
Free(DocItem);
681
}
682
683
/***********************************************************************
684
* SYSLINK_AppendDocItem
685
* Create and append a new document item.
686
*/
687
static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen,
688
SL_ITEM_TYPE type, PDOC_ITEM LastItem)
689
{
690
PDOC_ITEM Item;
691
692
textlen = min(textlen, lstrlenW(Text));
693
Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1]));
694
if(Item == NULL)
695
{
696
ERR("Failed to alloc DOC_ITEM structure!\n");
697
return NULL;
698
}
699
700
Item->nText = textlen;
701
Item->Type = type;
702
Item->Blocks = NULL;
703
lstrcpynW(Item->Text, Text, textlen + 1);
704
if (LastItem)
705
list_add_after(&LastItem->entry, &Item->entry);
706
else
707
list_add_tail(&infoPtr->Items, &Item->entry);
708
709
return Item;
710
}
711
712
/***********************************************************************
713
* SYSLINK_ClearDoc
714
* Clears the document tree
715
*/
716
static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr)
717
{
718
DOC_ITEM *Item, *Item2;
719
720
LIST_FOR_EACH_ENTRY_SAFE(Item, Item2, &infoPtr->Items, DOC_ITEM, entry)
721
{
722
list_remove(&Item->entry);
723
SYSLINK_FreeDocItem(Item);
724
}
725
}
726
727
/***********************************************************************
728
* SYSLINK_ParseText
729
* Parses the window text string and creates a document. Returns the
730
* number of document items created.
731
*/
732
static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
733
{
734
LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL;
735
int taglen = 0, textlen = 0, linklen = 0, docitems = 0;
736
PDOC_ITEM Last = NULL;
737
SL_ITEM_TYPE CurrentType = slText;
738
LPCWSTR lpID, lpUrl;
739
UINT lenId, lenUrl;
740
741
TRACE("(%p %s)\n", infoPtr, debugstr_w(Text));
742
743
for(current = Text; *current != 0;)
744
{
745
if(*current == '<')
746
{
747
if(!wcsnicmp(current, L"<a", 2) && (CurrentType == slText))
748
{
749
BOOL ValidParam = FALSE, ValidLink = FALSE;
750
751
if(*(current + 2) == '>')
752
{
753
/* we just have to deal with a <a> tag */
754
taglen = 3;
755
ValidLink = TRUE;
756
ValidParam = TRUE;
757
firsttag = current;
758
linklen = 0;
759
lpID = NULL;
760
lpUrl = NULL;
761
}
762
else if(*(current + 2) == infoPtr->BreakChar)
763
{
764
/* we expect parameters, parse them */
765
LPCWSTR *CurrentParameter = NULL, tmp;
766
UINT *CurrentParameterLen = NULL;
767
768
taglen = 3;
769
tmp = current + taglen;
770
lpID = NULL;
771
lpUrl = NULL;
772
773
CheckParameter:
774
/* compare the current position with all known parameters */
775
if(!wcsnicmp(tmp, L"href=\"", 6))
776
{
777
taglen += 6;
778
ValidParam = TRUE;
779
CurrentParameter = &lpUrl;
780
CurrentParameterLen = &lenUrl;
781
}
782
else if(!wcsnicmp(tmp, L"id=\"", 4))
783
{
784
taglen += 4;
785
ValidParam = TRUE;
786
CurrentParameter = &lpID;
787
CurrentParameterLen = &lenId;
788
}
789
else
790
{
791
ValidParam = FALSE;
792
}
793
794
if(ValidParam)
795
{
796
/* we got a known parameter, now search until the next " character.
797
If we can't find a " character, there's a syntax error and we just assume it's text */
798
ValidParam = FALSE;
799
*CurrentParameter = current + taglen;
800
*CurrentParameterLen = 0;
801
802
for(tmp = *CurrentParameter; *tmp != 0; tmp++)
803
{
804
taglen++;
805
if(*tmp == '\"')
806
{
807
ValidParam = TRUE;
808
tmp++;
809
break;
810
}
811
(*CurrentParameterLen)++;
812
}
813
}
814
if(ValidParam)
815
{
816
/* we're done with this parameter, now there are only 2 possibilities:
817
* 1. another parameter is coming, so expect a ' ' (space) character
818
* 2. the tag is being closed, so expect a '<' character
819
*/
820
if(*tmp == infoPtr->BreakChar)
821
{
822
/* we expect another parameter, do the whole thing again */
823
taglen++;
824
tmp++;
825
goto CheckParameter;
826
}
827
else if(*tmp == '>')
828
{
829
/* the tag is being closed, we're done */
830
ValidLink = TRUE;
831
taglen++;
832
}
833
}
834
}
835
836
if(ValidLink && ValidParam)
837
{
838
/* the <a ...> tag appears to be valid. save all information
839
so we can add the link if we find a valid </a> tag later */
840
CurrentType = slLink;
841
linktext = current + taglen;
842
linklen = 0;
843
firsttag = current;
844
}
845
else
846
{
847
taglen = 1;
848
lpID = NULL;
849
lpUrl = NULL;
850
if(textstart == NULL)
851
{
852
textstart = current;
853
}
854
}
855
}
856
else if (!wcsnicmp(current, L"</a>", 4) && (CurrentType == slLink) && firsttag)
857
{
858
/* there's a <a...> tag opened, first add the previous text, if present */
859
if(textstart != NULL && textlen > 0 && firsttag > textstart)
860
{
861
Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last);
862
if(Last == NULL)
863
{
864
ERR("Unable to create new document item!\n");
865
return docitems;
866
}
867
docitems++;
868
textstart = NULL;
869
textlen = 0;
870
}
871
872
/* now it's time to add the link to the document */
873
current += 4;
874
if(linktext != NULL && linklen > 0)
875
{
876
Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last);
877
if(Last == NULL)
878
{
879
ERR("Unable to create new document item!\n");
880
return docitems;
881
}
882
docitems++;
883
if(CurrentType == slLink)
884
{
885
int nc;
886
887
if(!(infoPtr->Style & WS_DISABLED))
888
{
889
Last->u.Link.state |= LIS_ENABLED;
890
}
891
/* Copy the tag parameters */
892
if(lpID != NULL)
893
{
894
nc = min(lenId, lstrlenW(lpID));
895
nc = min(nc, MAX_LINKID_TEXT - 1);
896
Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
897
if(Last->u.Link.szID != NULL)
898
{
899
lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
900
}
901
}
902
else
903
Last->u.Link.szID = NULL;
904
if(lpUrl != NULL)
905
{
906
nc = min(lenUrl, lstrlenW(lpUrl));
907
nc = min(nc, L_MAX_URL_LENGTH - 1);
908
Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
909
if(Last->u.Link.szUrl != NULL)
910
{
911
lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
912
}
913
}
914
else
915
Last->u.Link.szUrl = NULL;
916
}
917
linktext = NULL;
918
}
919
CurrentType = slText;
920
firsttag = NULL;
921
textstart = NULL;
922
continue;
923
}
924
else
925
{
926
/* we don't know what tag it is, so just continue */
927
taglen = 1;
928
linklen++;
929
if(CurrentType == slText && textstart == NULL)
930
{
931
textstart = current;
932
}
933
}
934
935
textlen += taglen;
936
current += taglen;
937
}
938
else
939
{
940
textlen++;
941
linklen++;
942
943
/* save the pointer of the current text item if we couldn't find a tag */
944
if(textstart == NULL && CurrentType == slText)
945
{
946
textstart = current;
947
}
948
949
current++;
950
}
951
}
952
953
if(textstart != NULL && textlen > 0)
954
{
955
Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last);
956
if(Last == NULL)
957
{
958
ERR("Unable to create new document item!\n");
959
return docitems;
960
}
961
if(CurrentType == slLink)
962
{
963
int nc;
964
965
if(!(infoPtr->Style & WS_DISABLED))
966
{
967
Last->u.Link.state |= LIS_ENABLED;
968
}
969
/* Copy the tag parameters */
970
if(lpID != NULL)
971
{
972
nc = min(lenId, lstrlenW(lpID));
973
nc = min(nc, MAX_LINKID_TEXT - 1);
974
Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
975
if(Last->u.Link.szID != NULL)
976
{
977
lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
978
}
979
}
980
else
981
Last->u.Link.szID = NULL;
982
if(lpUrl != NULL)
983
{
984
nc = min(lenUrl, lstrlenW(lpUrl));
985
nc = min(nc, L_MAX_URL_LENGTH - 1);
986
Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
987
if(Last->u.Link.szUrl != NULL)
988
{
989
lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
990
}
991
}
992
else
993
Last->u.Link.szUrl = NULL;
994
}
995
docitems++;
996
}
997
998
if(linktext != NULL && linklen > 0)
999
{
1000
/* we got an unclosed link, just display the text */
1001
Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slText, Last);
1002
if(Last == NULL)
1003
{
1004
ERR("Unable to create new document item!\n");
1005
return docitems;
1006
}
1007
docitems++;
1008
}
1009
1010
return docitems;
1011
}
1012
1013
/***********************************************************************
1014
* SYSLINK_RepaintLink
1015
* Repaints a link.
1016
*/
1017
static VOID SYSLINK_RepaintLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
1018
{
1019
PDOC_TEXTBLOCK bl;
1020
int n;
1021
1022
if(DocItem->Type != slLink)
1023
{
1024
ERR("DocItem not a link!\n");
1025
return;
1026
}
1027
1028
bl = DocItem->Blocks;
1029
if (bl != NULL)
1030
{
1031
n = DocItem->nText;
1032
1033
while(n > 0)
1034
{
1035
InvalidateRect(infoPtr->Self, &bl->rc, TRUE);
1036
n -= bl->nChars + bl->nSkip;
1037
bl++;
1038
}
1039
}
1040
}
1041
1042
/***********************************************************************
1043
* SYSLINK_GetLinkItemByIndex
1044
* Retrieves a document link by its index
1045
*/
1046
static PDOC_ITEM SYSLINK_GetLinkItemByIndex (const SYSLINK_INFO *infoPtr, int iLink)
1047
{
1048
DOC_ITEM *Current;
1049
1050
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1051
{
1052
if ((Current->Type == slLink) && (iLink-- <= 0))
1053
return Current;
1054
}
1055
return NULL;
1056
}
1057
1058
/***********************************************************************
1059
* SYSLINK_GetFocusLink
1060
* Retrieves the link that has the LIS_FOCUSED bit
1061
*/
1062
static PDOC_ITEM SYSLINK_GetFocusLink (const SYSLINK_INFO *infoPtr, int *LinkId)
1063
{
1064
DOC_ITEM *Current;
1065
int id = 0;
1066
1067
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1068
{
1069
if(Current->Type == slLink)
1070
{
1071
if(Current->u.Link.state & LIS_FOCUSED)
1072
{
1073
if(LinkId != NULL)
1074
*LinkId = id;
1075
return Current;
1076
}
1077
id++;
1078
}
1079
}
1080
1081
return NULL;
1082
}
1083
1084
/***********************************************************************
1085
* SYSLINK_GetNextLink
1086
* Gets the next link
1087
*/
1088
static PDOC_ITEM SYSLINK_GetNextLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
1089
{
1090
DOC_ITEM *Next;
1091
1092
LIST_FOR_EACH_ENTRY(Next, Current ? &Current->entry : &infoPtr->Items, DOC_ITEM, entry)
1093
{
1094
if (Next->Type == slLink)
1095
{
1096
return Next;
1097
}
1098
}
1099
return NULL;
1100
}
1101
1102
/***********************************************************************
1103
* SYSLINK_GetPrevLink
1104
* Gets the previous link
1105
*/
1106
static PDOC_ITEM SYSLINK_GetPrevLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
1107
{
1108
DOC_ITEM *Prev;
1109
1110
LIST_FOR_EACH_ENTRY_REV(Prev, Current ? &Current->entry : list_tail(&infoPtr->Items), DOC_ITEM, entry)
1111
{
1112
if (Prev->Type == slLink)
1113
{
1114
return Prev;
1115
}
1116
}
1117
1118
return NULL;
1119
}
1120
1121
/***********************************************************************
1122
* SYSLINK_WrapLine
1123
* Tries to wrap a line.
1124
*/
1125
static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int x, int *LineLen,
1126
int nFit, LPSIZE Extent)
1127
{
1128
int i;
1129
1130
for (i = 0; i < nFit; i++) if (Text[i] == '\r' || Text[i] == '\n') break;
1131
1132
if (i == *LineLen) return FALSE;
1133
1134
/* check if we're in the middle of a word */
1135
if (Text[i] != '\r' && Text[i] != '\n' && Text[i] != BreakChar)
1136
{
1137
/* search for the beginning of the word */
1138
while (i && Text[i - 1] != BreakChar) i--;
1139
1140
if (i == 0)
1141
{
1142
Extent->cx = 0;
1143
Extent->cy = 0;
1144
if (x == SL_LEFTMARGIN) i = max( nFit, 1 );
1145
}
1146
}
1147
*LineLen = i;
1148
return TRUE;
1149
}
1150
1151
/***********************************************************************
1152
* SYSLINK_Render
1153
* Renders the document in memory
1154
*/
1155
static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
1156
{
1157
RECT rc;
1158
PDOC_ITEM Current;
1159
HGDIOBJ hOldFont;
1160
int x, y, LineHeight;
1161
SIZE szDoc;
1162
TEXTMETRICW tm;
1163
1164
szDoc.cx = szDoc.cy = 0;
1165
1166
rc = *pRect;
1167
rc.right -= SL_RIGHTMARGIN;
1168
rc.bottom -= SL_BOTTOMMARGIN;
1169
1170
if(rc.right - SL_LEFTMARGIN < 0)
1171
rc.right = MAXLONG;
1172
if (rc.bottom - SL_TOPMARGIN < 0)
1173
rc.bottom = MAXLONG;
1174
1175
hOldFont = SelectObject(hdc, infoPtr->Font);
1176
1177
x = SL_LEFTMARGIN;
1178
y = SL_TOPMARGIN;
1179
GetTextMetricsW( hdc, &tm );
1180
LineHeight = tm.tmHeight + tm.tmExternalLeading;
1181
1182
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1183
{
1184
int n, nBlocks;
1185
LPWSTR tx;
1186
PDOC_TEXTBLOCK bl, cbl;
1187
INT nFit;
1188
SIZE szDim;
1189
int SkipChars = 0;
1190
1191
if(Current->nText == 0)
1192
{
1193
continue;
1194
}
1195
1196
tx = Current->Text;
1197
n = Current->nText;
1198
1199
Free(Current->Blocks);
1200
Current->Blocks = NULL;
1201
bl = NULL;
1202
nBlocks = 0;
1203
1204
if(Current->Type == slText)
1205
{
1206
SelectObject(hdc, infoPtr->Font);
1207
}
1208
else if(Current->Type == slLink)
1209
{
1210
SelectObject(hdc, infoPtr->LinkFont);
1211
}
1212
1213
while(n > 0)
1214
{
1215
/* skip break characters unless they're the first of the doc item */
1216
if(tx != Current->Text || x == SL_LEFTMARGIN)
1217
{
1218
if (n && *tx == '\r')
1219
{
1220
tx++;
1221
SkipChars++;
1222
n--;
1223
}
1224
if (n && *tx == '\n')
1225
{
1226
tx++;
1227
SkipChars++;
1228
n--;
1229
}
1230
while(n > 0 && (*tx) == infoPtr->BreakChar)
1231
{
1232
tx++;
1233
SkipChars++;
1234
n--;
1235
}
1236
}
1237
1238
if((n == 0 && SkipChars != 0) ||
1239
GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim))
1240
{
1241
int LineLen = n;
1242
BOOL Wrap = FALSE;
1243
PDOC_TEXTBLOCK nbl;
1244
1245
if(n != 0)
1246
{
1247
Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, x, &LineLen, nFit, &szDim);
1248
1249
if(LineLen == 0)
1250
{
1251
/* move one line down, the word didn't fit into the line */
1252
x = SL_LEFTMARGIN;
1253
y += LineHeight;
1254
continue;
1255
}
1256
1257
if(LineLen != n)
1258
{
1259
if(!GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim))
1260
{
1261
if(bl != NULL)
1262
{
1263
Free(bl);
1264
bl = NULL;
1265
nBlocks = 0;
1266
}
1267
break;
1268
}
1269
}
1270
}
1271
1272
nbl = ReAlloc(bl, (nBlocks + 1) * sizeof(DOC_TEXTBLOCK));
1273
if (nbl != NULL)
1274
{
1275
bl = nbl;
1276
nBlocks++;
1277
1278
cbl = bl + nBlocks - 1;
1279
1280
cbl->nChars = LineLen;
1281
cbl->nSkip = SkipChars;
1282
SetRect(&cbl->rc, x, y, x + szDim.cx, y + szDim.cy);
1283
1284
if (cbl->rc.right > szDoc.cx)
1285
szDoc.cx = cbl->rc.right;
1286
if (cbl->rc.bottom > szDoc.cy)
1287
szDoc.cy = cbl->rc.bottom;
1288
1289
if(LineLen != 0)
1290
{
1291
x += szDim.cx;
1292
if(Wrap)
1293
{
1294
x = SL_LEFTMARGIN;
1295
y += LineHeight;
1296
}
1297
}
1298
}
1299
else
1300
{
1301
Free(bl);
1302
bl = NULL;
1303
nBlocks = 0;
1304
1305
ERR("Failed to alloc DOC_TEXTBLOCK structure!\n");
1306
break;
1307
}
1308
n -= LineLen;
1309
tx += LineLen;
1310
SkipChars = 0;
1311
}
1312
else
1313
{
1314
n--;
1315
}
1316
}
1317
1318
if(nBlocks != 0)
1319
{
1320
Current->Blocks = bl;
1321
}
1322
}
1323
1324
SelectObject(hdc, hOldFont);
1325
1326
pRect->right = pRect->left + szDoc.cx;
1327
pRect->bottom = pRect->top + szDoc.cy;
1328
}
1329
1330
/***********************************************************************
1331
* SYSLINK_Draw
1332
* Draws the SysLink control.
1333
*/
1334
static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
1335
{
1336
RECT rc;
1337
PDOC_ITEM Current;
1338
HFONT hOldFont;
1339
COLORREF OldTextColor, OldBkColor;
1340
HBRUSH hBrush;
1341
UINT text_flags = ETO_CLIPPED;
1342
UINT mode = GetBkMode( hdc );
1343
1344
hOldFont = SelectObject(hdc, infoPtr->Font);
1345
OldTextColor = SetTextColor(hdc, infoPtr->TextColor);
1346
OldBkColor = SetBkColor(hdc, comctl32_color.clrWindow);
1347
1348
GetClientRect(infoPtr->Self, &rc);
1349
rc.right -= SL_RIGHTMARGIN + SL_LEFTMARGIN;
1350
rc.bottom -= SL_BOTTOMMARGIN + SL_TOPMARGIN;
1351
1352
if(rc.right < 0 || rc.bottom < 0) return 0;
1353
1354
hBrush = (HBRUSH)SendMessageW(infoPtr->Notify, WM_CTLCOLORSTATIC,
1355
(WPARAM)hdc, (LPARAM)infoPtr->Self);
1356
if (!(infoPtr->Style & LWS_TRANSPARENT))
1357
{
1358
FillRect(hdc, &rc, hBrush);
1359
if (GetBkMode( hdc ) == OPAQUE) text_flags |= ETO_OPAQUE;
1360
}
1361
else SetBkMode( hdc, TRANSPARENT );
1362
1363
DeleteObject(hBrush);
1364
1365
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1366
{
1367
int n;
1368
LPWSTR tx;
1369
PDOC_TEXTBLOCK bl;
1370
1371
bl = Current->Blocks;
1372
if(bl != NULL)
1373
{
1374
tx = Current->Text;
1375
n = Current->nText;
1376
1377
if(Current->Type == slText)
1378
{
1379
SelectObject(hdc, infoPtr->Font);
1380
SetTextColor(hdc, infoPtr->TextColor);
1381
}
1382
else
1383
{
1384
SelectObject(hdc, infoPtr->LinkFont);
1385
SetTextColor(hdc, (!(Current->u.Link.state & LIS_VISITED) ? infoPtr->LinkColor : infoPtr->VisitedColor));
1386
}
1387
1388
while(n > 0)
1389
{
1390
tx += bl->nSkip;
1391
ExtTextOutW(hdc, bl->rc.left, bl->rc.top, text_flags, &bl->rc, tx, bl->nChars, NULL);
1392
if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus)
1393
{
1394
COLORREF PrevTextColor;
1395
PrevTextColor = SetTextColor(hdc, infoPtr->TextColor);
1396
DrawFocusRect(hdc, &bl->rc);
1397
SetTextColor(hdc, PrevTextColor);
1398
}
1399
tx += bl->nChars;
1400
n -= bl->nChars + bl->nSkip;
1401
bl++;
1402
}
1403
}
1404
}
1405
1406
SetBkColor(hdc, OldBkColor);
1407
SetTextColor(hdc, OldTextColor);
1408
SelectObject(hdc, hOldFont);
1409
SetBkMode(hdc, mode);
1410
return 0;
1411
}
1412
1413
1414
/***********************************************************************
1415
* SYSLINK_Paint
1416
* Handles the WM_PAINT message.
1417
*/
1418
static LRESULT SYSLINK_Paint (const SYSLINK_INFO *infoPtr, HDC hdcParam)
1419
{
1420
HDC hdc;
1421
PAINTSTRUCT ps;
1422
1423
hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps);
1424
if (hdc)
1425
{
1426
SYSLINK_Draw (infoPtr, hdc);
1427
if (!hdcParam) EndPaint (infoPtr->Self, &ps);
1428
}
1429
return 0;
1430
}
1431
1432
/***********************************************************************
1433
* SYSLINK_SetFont
1434
* Set new Font for the SysLink control.
1435
*/
1436
static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
1437
{
1438
HDC hdc;
1439
LOGFONTW lf;
1440
TEXTMETRICW tm;
1441
RECT rcClient;
1442
HFONT hOldFont = infoPtr->Font;
1443
infoPtr->Font = hFont;
1444
1445
/* free the underline font */
1446
if(infoPtr->LinkFont != NULL)
1447
{
1448
DeleteObject(infoPtr->LinkFont);
1449
infoPtr->LinkFont = NULL;
1450
}
1451
1452
/* Render text position and word wrapping in memory */
1453
if (GetClientRect(infoPtr->Self, &rcClient))
1454
{
1455
hdc = GetDC(infoPtr->Self);
1456
if(hdc != NULL)
1457
{
1458
/* create a new underline font */
1459
if(GetTextMetricsW(hdc, &tm) &&
1460
GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf))
1461
{
1462
lf.lfUnderline = TRUE;
1463
infoPtr->LinkFont = CreateFontIndirectW(&lf);
1464
infoPtr->BreakChar = tm.tmBreakChar;
1465
}
1466
else
1467
{
1468
ERR("Failed to create link font!\n");
1469
}
1470
1471
SYSLINK_Render(infoPtr, hdc, &rcClient);
1472
ReleaseDC(infoPtr->Self, hdc);
1473
}
1474
}
1475
1476
if(bRedraw)
1477
{
1478
RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
1479
}
1480
1481
return hOldFont;
1482
}
1483
1484
/***********************************************************************
1485
* SYSLINK_SetText
1486
* Set new text for the SysLink control.
1487
*/
1488
static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
1489
{
1490
/* clear the document */
1491
SYSLINK_ClearDoc(infoPtr);
1492
1493
if(Text == NULL || *Text == 0)
1494
{
1495
return TRUE;
1496
}
1497
1498
/* let's parse the string and create a document */
1499
if(SYSLINK_ParseText(infoPtr, Text) > 0)
1500
{
1501
RECT rcClient;
1502
1503
/* Render text position and word wrapping in memory */
1504
if (GetClientRect(infoPtr->Self, &rcClient))
1505
{
1506
HDC hdc = GetDC(infoPtr->Self);
1507
if (hdc != NULL)
1508
{
1509
SYSLINK_Render(infoPtr, hdc, &rcClient);
1510
ReleaseDC(infoPtr->Self, hdc);
1511
1512
InvalidateRect(infoPtr->Self, NULL, TRUE);
1513
}
1514
}
1515
}
1516
1517
return TRUE;
1518
}
1519
1520
/***********************************************************************
1521
* SYSLINK_SetFocusLink
1522
* Updates the focus status bits and focuses the specified link.
1523
* If no document item is specified, the focus bit will be removed from all links.
1524
* Returns the previous focused item.
1525
*/
1526
static PDOC_ITEM SYSLINK_SetFocusLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
1527
{
1528
PDOC_ITEM Current, PrevFocus = NULL;
1529
1530
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1531
{
1532
if(Current->Type == slLink)
1533
{
1534
if((PrevFocus == NULL) && (Current->u.Link.state & LIS_FOCUSED))
1535
{
1536
PrevFocus = Current;
1537
}
1538
1539
if(Current == DocItem)
1540
{
1541
Current->u.Link.state |= LIS_FOCUSED;
1542
}
1543
else
1544
{
1545
Current->u.Link.state &= ~LIS_FOCUSED;
1546
}
1547
}
1548
}
1549
1550
return PrevFocus;
1551
}
1552
1553
/***********************************************************************
1554
* SYSLINK_SetItem
1555
* Sets the states and attributes of a link item.
1556
*/
1557
static LRESULT SYSLINK_SetItem (const SYSLINK_INFO *infoPtr, const LITEM *Item)
1558
{
1559
PDOC_ITEM di;
1560
int nc;
1561
PWSTR szId = NULL;
1562
PWSTR szUrl = NULL;
1563
BOOL Repaint = FALSE;
1564
1565
if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK)))
1566
{
1567
ERR("Invalid Flags!\n");
1568
return FALSE;
1569
}
1570
1571
di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink);
1572
if(di == NULL)
1573
{
1574
ERR("Link %d couldn't be found\n", Item->iLink);
1575
return FALSE;
1576
}
1577
1578
if(Item->mask & LIF_ITEMID)
1579
{
1580
nc = min(lstrlenW(Item->szID), MAX_LINKID_TEXT - 1);
1581
szId = Alloc((nc + 1) * sizeof(WCHAR));
1582
if(szId)
1583
{
1584
lstrcpynW(szId, Item->szID, nc + 1);
1585
}
1586
else
1587
{
1588
ERR("Unable to allocate memory for link id\n");
1589
return FALSE;
1590
}
1591
}
1592
1593
if(Item->mask & LIF_URL)
1594
{
1595
nc = min(lstrlenW(Item->szUrl), L_MAX_URL_LENGTH - 1);
1596
szUrl = Alloc((nc + 1) * sizeof(WCHAR));
1597
if(szUrl)
1598
{
1599
lstrcpynW(szUrl, Item->szUrl, nc + 1);
1600
}
1601
else
1602
{
1603
Free(szId);
1604
1605
ERR("Unable to allocate memory for link url\n");
1606
return FALSE;
1607
}
1608
}
1609
1610
if(Item->mask & LIF_ITEMID)
1611
{
1612
Free(di->u.Link.szID);
1613
di->u.Link.szID = szId;
1614
}
1615
1616
if(Item->mask & LIF_URL)
1617
{
1618
Free(di->u.Link.szUrl);
1619
di->u.Link.szUrl = szUrl;
1620
}
1621
1622
if(Item->mask & LIF_STATE)
1623
{
1624
UINT oldstate = di->u.Link.state;
1625
/* clear the masked bits */
1626
di->u.Link.state &= ~(Item->stateMask & LIS_MASK);
1627
/* copy the bits */
1628
di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK;
1629
Repaint = (oldstate != di->u.Link.state);
1630
1631
/* update the focus */
1632
SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL));
1633
}
1634
1635
if(Repaint)
1636
{
1637
SYSLINK_RepaintLink(infoPtr, di);
1638
}
1639
1640
return TRUE;
1641
}
1642
1643
/***********************************************************************
1644
* SYSLINK_GetItem
1645
* Retrieves the states and attributes of a link item.
1646
*/
1647
static LRESULT SYSLINK_GetItem (const SYSLINK_INFO *infoPtr, PLITEM Item)
1648
{
1649
PDOC_ITEM di;
1650
1651
if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK)))
1652
{
1653
ERR("Invalid Flags!\n");
1654
return FALSE;
1655
}
1656
1657
di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink);
1658
if(di == NULL)
1659
{
1660
ERR("Link %d couldn't be found\n", Item->iLink);
1661
return FALSE;
1662
}
1663
1664
if(Item->mask & LIF_STATE)
1665
{
1666
Item->state = (di->u.Link.state & Item->stateMask);
1667
if(!infoPtr->HasFocus)
1668
{
1669
/* remove the LIS_FOCUSED bit if the control doesn't have focus */
1670
Item->state &= ~LIS_FOCUSED;
1671
}
1672
}
1673
1674
if(Item->mask & LIF_ITEMID)
1675
{
1676
if(di->u.Link.szID)
1677
{
1678
lstrcpyW(Item->szID, di->u.Link.szID);
1679
}
1680
else
1681
{
1682
Item->szID[0] = 0;
1683
}
1684
}
1685
1686
if(Item->mask & LIF_URL)
1687
{
1688
if(di->u.Link.szUrl)
1689
{
1690
lstrcpyW(Item->szUrl, di->u.Link.szUrl);
1691
}
1692
else
1693
{
1694
Item->szUrl[0] = 0;
1695
}
1696
}
1697
1698
return TRUE;
1699
}
1700
1701
/***********************************************************************
1702
* SYSLINK_PtInDocItem
1703
* Determines if a point is in the region of a document item
1704
*/
1705
static BOOL SYSLINK_PtInDocItem (const DOC_ITEM *DocItem, POINT pt)
1706
{
1707
PDOC_TEXTBLOCK bl;
1708
int n;
1709
1710
bl = DocItem->Blocks;
1711
if (bl != NULL)
1712
{
1713
n = DocItem->nText;
1714
1715
while(n > 0)
1716
{
1717
if (PtInRect(&bl->rc, pt))
1718
{
1719
return TRUE;
1720
}
1721
n -= bl->nChars + bl->nSkip;
1722
bl++;
1723
}
1724
}
1725
1726
return FALSE;
1727
}
1728
1729
/***********************************************************************
1730
* SYSLINK_HitTest
1731
* Determines the link the user clicked on.
1732
*/
1733
static LRESULT SYSLINK_HitTest (const SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
1734
{
1735
PDOC_ITEM Current;
1736
int id = 0;
1737
1738
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1739
{
1740
if(Current->Type == slLink)
1741
{
1742
if(SYSLINK_PtInDocItem(Current, HitTest->pt))
1743
{
1744
HitTest->item.mask = 0;
1745
HitTest->item.iLink = id;
1746
HitTest->item.state = 0;
1747
HitTest->item.stateMask = 0;
1748
if(Current->u.Link.szID)
1749
{
1750
lstrcpyW(HitTest->item.szID, Current->u.Link.szID);
1751
}
1752
else
1753
{
1754
HitTest->item.szID[0] = 0;
1755
}
1756
if(Current->u.Link.szUrl)
1757
{
1758
lstrcpyW(HitTest->item.szUrl, Current->u.Link.szUrl);
1759
}
1760
else
1761
{
1762
HitTest->item.szUrl[0] = 0;
1763
}
1764
return TRUE;
1765
}
1766
id++;
1767
}
1768
}
1769
1770
return FALSE;
1771
}
1772
1773
/***********************************************************************
1774
* SYSLINK_GetIdealHeight
1775
* Returns the preferred height of a link at the current control's width.
1776
*/
1777
static LRESULT SYSLINK_GetIdealHeight (const SYSLINK_INFO *infoPtr)
1778
{
1779
HDC hdc = GetDC(infoPtr->Self);
1780
if(hdc != NULL)
1781
{
1782
LRESULT height;
1783
TEXTMETRICW tm;
1784
HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font);
1785
1786
if(GetTextMetricsW(hdc, &tm))
1787
{
1788
height = tm.tmHeight;
1789
}
1790
else
1791
{
1792
height = 0;
1793
}
1794
SelectObject(hdc, hOldFont);
1795
ReleaseDC(infoPtr->Self, hdc);
1796
1797
return height;
1798
}
1799
return 0;
1800
}
1801
1802
/***********************************************************************
1803
* SYSLINK_SendParentNotify
1804
* Sends a WM_NOTIFY message to the parent window.
1805
*/
1806
static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink)
1807
{
1808
NMLINK nml;
1809
1810
nml.hdr.hwndFrom = infoPtr->Self;
1811
nml.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID);
1812
nml.hdr.code = code;
1813
1814
nml.item.mask = 0;
1815
nml.item.iLink = iLink;
1816
nml.item.state = 0;
1817
nml.item.stateMask = 0;
1818
if(Link->u.Link.szID)
1819
{
1820
lstrcpyW(nml.item.szID, Link->u.Link.szID);
1821
}
1822
else
1823
{
1824
nml.item.szID[0] = 0;
1825
}
1826
if(Link->u.Link.szUrl)
1827
{
1828
lstrcpyW(nml.item.szUrl, Link->u.Link.szUrl);
1829
}
1830
else
1831
{
1832
nml.item.szUrl[0] = 0;
1833
}
1834
1835
return SendMessageW(infoPtr->Notify, WM_NOTIFY, nml.hdr.idFrom, (LPARAM)&nml);
1836
}
1837
1838
/***********************************************************************
1839
* SYSLINK_SetFocus
1840
* Handles receiving the input focus.
1841
*/
1842
static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr)
1843
{
1844
PDOC_ITEM Focus;
1845
1846
infoPtr->HasFocus = TRUE;
1847
1848
/* We always select the first link, even if we activated the control using
1849
SHIFT+TAB. This is the default behavior */
1850
Focus = SYSLINK_GetNextLink(infoPtr, NULL);
1851
if(Focus != NULL)
1852
{
1853
SYSLINK_SetFocusLink(infoPtr, Focus);
1854
SYSLINK_RepaintLink(infoPtr, Focus);
1855
}
1856
return 0;
1857
}
1858
1859
/***********************************************************************
1860
* SYSLINK_KillFocus
1861
* Handles losing the input focus.
1862
*/
1863
static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr)
1864
{
1865
PDOC_ITEM Focus;
1866
1867
infoPtr->HasFocus = FALSE;
1868
Focus = SYSLINK_GetFocusLink(infoPtr, NULL);
1869
1870
if(Focus != NULL)
1871
{
1872
SYSLINK_RepaintLink(infoPtr, Focus);
1873
}
1874
1875
return 0;
1876
}
1877
1878
/***********************************************************************
1879
* SYSLINK_LinkAtPt
1880
* Returns a link at the specified position
1881
*/
1882
static PDOC_ITEM SYSLINK_LinkAtPt (const SYSLINK_INFO *infoPtr, const POINT *pt, int *LinkId, BOOL MustBeEnabled)
1883
{
1884
PDOC_ITEM Current;
1885
int id = 0;
1886
1887
LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1888
{
1889
if(Current->Type == slLink)
1890
{
1891
if(SYSLINK_PtInDocItem(Current, *pt) && (!MustBeEnabled || (Current->u.Link.state & LIS_ENABLED)))
1892
{
1893
if(LinkId != NULL)
1894
{
1895
*LinkId = id;
1896
}
1897
return Current;
1898
}
1899
id++;
1900
}
1901
}
1902
1903
return NULL;
1904
}
1905
1906
/***********************************************************************
1907
* SYSLINK_LButtonDown
1908
* Handles mouse clicks
1909
*/
1910
static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, const POINT *pt)
1911
{
1912
PDOC_ITEM Current, Old;
1913
int id;
1914
1915
Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE);
1916
if(Current != NULL)
1917
{
1918
SetFocus(infoPtr->Self);
1919
1920
Old = SYSLINK_SetFocusLink(infoPtr, Current);
1921
if(Old != NULL && Old != Current)
1922
{
1923
SYSLINK_RepaintLink(infoPtr, Old);
1924
}
1925
infoPtr->MouseDownID = id;
1926
SYSLINK_RepaintLink(infoPtr, Current);
1927
}
1928
1929
return 0;
1930
}
1931
1932
/***********************************************************************
1933
* SYSLINK_LButtonUp
1934
* Handles mouse clicks
1935
*/
1936
static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, const POINT *pt)
1937
{
1938
if(infoPtr->MouseDownID > -1)
1939
{
1940
PDOC_ITEM Current;
1941
int id;
1942
1943
Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE);
1944
if((Current != NULL) && (Current->u.Link.state & LIS_FOCUSED) && (infoPtr->MouseDownID == id))
1945
{
1946
SYSLINK_SendParentNotify(infoPtr, NM_CLICK, Current, id);
1947
}
1948
}
1949
1950
infoPtr->MouseDownID = -1;
1951
1952
return 0;
1953
}
1954
1955
/***********************************************************************
1956
* SYSLINK_OnEnter
1957
* Handles ENTER key events
1958
*/
1959
static BOOL SYSLINK_OnEnter (const SYSLINK_INFO *infoPtr)
1960
{
1961
if(infoPtr->HasFocus && !infoPtr->IgnoreReturn)
1962
{
1963
PDOC_ITEM Focus;
1964
int id;
1965
1966
Focus = SYSLINK_GetFocusLink(infoPtr, &id);
1967
if(Focus)
1968
{
1969
SYSLINK_SendParentNotify(infoPtr, NM_RETURN, Focus, id);
1970
return TRUE;
1971
}
1972
}
1973
return FALSE;
1974
}
1975
1976
/***********************************************************************
1977
* SYSKEY_SelectNextPrevLink
1978
* Changes the currently focused link
1979
*/
1980
static BOOL SYSKEY_SelectNextPrevLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
1981
{
1982
if(infoPtr->HasFocus)
1983
{
1984
PDOC_ITEM Focus;
1985
int id;
1986
1987
Focus = SYSLINK_GetFocusLink(infoPtr, &id);
1988
if(Focus != NULL)
1989
{
1990
PDOC_ITEM NewFocus, OldFocus;
1991
1992
if(Prev)
1993
NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus);
1994
else
1995
NewFocus = SYSLINK_GetNextLink(infoPtr, Focus);
1996
1997
if(NewFocus != NULL)
1998
{
1999
OldFocus = SYSLINK_SetFocusLink(infoPtr, NewFocus);
2000
2001
if(OldFocus && OldFocus != NewFocus)
2002
{
2003
SYSLINK_RepaintLink(infoPtr, OldFocus);
2004
}
2005
SYSLINK_RepaintLink(infoPtr, NewFocus);
2006
return TRUE;
2007
}
2008
}
2009
}
2010
return FALSE;
2011
}
2012
2013
/***********************************************************************
2014
* SYSKEY_SelectNextPrevLink
2015
* Determines if there's a next or previous link to decide whether the control
2016
* should capture the tab key message
2017
*/
2018
static BOOL SYSLINK_NoNextLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
2019
{
2020
PDOC_ITEM Focus, NewFocus;
2021
2022
Focus = SYSLINK_GetFocusLink(infoPtr, NULL);
2023
if(Prev)
2024
NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus);
2025
else
2026
NewFocus = SYSLINK_GetNextLink(infoPtr, Focus);
2027
2028
return NewFocus == NULL;
2029
}
2030
2031
/***********************************************************************
2032
* SYSLINK_GetIdealSize
2033
* Calculates the ideal size of a link control at a given maximum width.
2034
*/
2035
static LONG SYSLINK_GetIdealSize (const SYSLINK_INFO *infoPtr, int cxMaxWidth, SIZE *lpSize)
2036
{
2037
RECT rc;
2038
HDC hdc;
2039
2040
rc.left = rc.top = rc.bottom = 0;
2041
rc.right = cxMaxWidth;
2042
2043
hdc = GetDC(infoPtr->Self);
2044
if (hdc != NULL)
2045
{
2046
HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font);
2047
2048
SYSLINK_Render(infoPtr, hdc, &rc);
2049
2050
SelectObject(hdc, hOldFont);
2051
ReleaseDC(infoPtr->Self, hdc);
2052
2053
lpSize->cx = rc.right;
2054
lpSize->cy = rc.bottom;
2055
}
2056
2057
return rc.bottom;
2058
}
2059
2060
/***********************************************************************
2061
* SysLinkWindowProc
2062
*/
2063
static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message,
2064
WPARAM wParam, LPARAM lParam)
2065
{
2066
SYSLINK_INFO *infoPtr;
2067
2068
TRACE("hwnd %p, msg %04x, wparam %Ix, lParam %Ix\n", hwnd, message, wParam, lParam);
2069
2070
infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0);
2071
2072
if (!infoPtr && message != WM_CREATE)
2073
return DefWindowProcW(hwnd, message, wParam, lParam);
2074
2075
switch(message) {
2076
case WM_PRINTCLIENT:
2077
case WM_PAINT:
2078
return SYSLINK_Paint (infoPtr, (HDC)wParam);
2079
2080
case WM_ERASEBKGND:
2081
if (!(infoPtr->Style & LWS_TRANSPARENT))
2082
{
2083
HDC hdc = (HDC)wParam;
2084
HBRUSH brush = CreateSolidBrush( comctl32_color.clrWindow );
2085
RECT rect;
2086
2087
GetClipBox( hdc, &rect );
2088
FillRect( hdc, &rect, brush );
2089
DeleteObject( brush );
2090
return 1;
2091
}
2092
return 0;
2093
2094
case WM_SETCURSOR:
2095
{
2096
LHITTESTINFO ht;
2097
DWORD mp = GetMessagePos();
2098
2099
ht.pt.x = (short)LOWORD(mp);
2100
ht.pt.y = (short)HIWORD(mp);
2101
2102
ScreenToClient(infoPtr->Self, &ht.pt);
2103
if(SYSLINK_HitTest (infoPtr, &ht))
2104
{
2105
SetCursor(LoadCursorW(0, (LPCWSTR)IDC_HAND));
2106
return TRUE;
2107
}
2108
2109
return DefWindowProcW(hwnd, message, wParam, lParam);
2110
}
2111
2112
case WM_SIZE:
2113
{
2114
RECT rcClient;
2115
if (GetClientRect(infoPtr->Self, &rcClient))
2116
{
2117
HDC hdc = GetDC(infoPtr->Self);
2118
if(hdc != NULL)
2119
{
2120
SYSLINK_Render(infoPtr, hdc, &rcClient);
2121
ReleaseDC(infoPtr->Self, hdc);
2122
}
2123
}
2124
return 0;
2125
}
2126
2127
case WM_GETFONT:
2128
return (LRESULT)infoPtr->Font;
2129
2130
case WM_SETFONT:
2131
return (LRESULT)SYSLINK_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
2132
2133
case WM_SETTEXT:
2134
SYSLINK_SetText(infoPtr, (LPWSTR)lParam);
2135
return DefWindowProcW(hwnd, message, wParam, lParam);
2136
2137
case WM_LBUTTONDOWN:
2138
{
2139
POINT pt;
2140
pt.x = (short)LOWORD(lParam);
2141
pt.y = (short)HIWORD(lParam);
2142
return SYSLINK_LButtonDown(infoPtr, &pt);
2143
}
2144
case WM_LBUTTONUP:
2145
{
2146
POINT pt;
2147
pt.x = (short)LOWORD(lParam);
2148
pt.y = (short)HIWORD(lParam);
2149
return SYSLINK_LButtonUp(infoPtr, &pt);
2150
}
2151
2152
case WM_KEYDOWN:
2153
{
2154
switch(wParam)
2155
{
2156
case VK_RETURN:
2157
SYSLINK_OnEnter(infoPtr);
2158
return 0;
2159
case VK_TAB:
2160
{
2161
BOOL shift = GetKeyState(VK_SHIFT) & 0x8000;
2162
SYSKEY_SelectNextPrevLink(infoPtr, shift);
2163
return 0;
2164
}
2165
default:
2166
return DefWindowProcW(hwnd, message, wParam, lParam);
2167
}
2168
}
2169
2170
case WM_GETDLGCODE:
2171
{
2172
LRESULT Ret = DLGC_HASSETSEL;
2173
int vk = (lParam != 0 ? (int)((LPMSG)lParam)->wParam : 0);
2174
switch(vk)
2175
{
2176
case VK_RETURN:
2177
Ret |= DLGC_WANTMESSAGE;
2178
break;
2179
case VK_TAB:
2180
{
2181
BOOL shift = GetKeyState(VK_SHIFT) & 0x8000;
2182
if(!SYSLINK_NoNextLink(infoPtr, shift))
2183
{
2184
Ret |= DLGC_WANTTAB;
2185
}
2186
else
2187
{
2188
Ret |= DLGC_WANTCHARS;
2189
}
2190
break;
2191
}
2192
}
2193
return Ret;
2194
}
2195
2196
case WM_NCHITTEST:
2197
{
2198
POINT pt;
2199
RECT rc;
2200
pt.x = (short)LOWORD(lParam);
2201
pt.y = (short)HIWORD(lParam);
2202
2203
GetClientRect(infoPtr->Self, &rc);
2204
ScreenToClient(infoPtr->Self, &pt);
2205
if(pt.x < 0 || pt.y < 0 || pt.x > rc.right || pt.y > rc.bottom)
2206
{
2207
return HTNOWHERE;
2208
}
2209
2210
if(SYSLINK_LinkAtPt(infoPtr, &pt, NULL, FALSE))
2211
{
2212
return HTCLIENT;
2213
}
2214
2215
return HTTRANSPARENT;
2216
}
2217
2218
case LM_HITTEST:
2219
return SYSLINK_HitTest(infoPtr, (PLHITTESTINFO)lParam);
2220
2221
case LM_SETITEM:
2222
return SYSLINK_SetItem(infoPtr, (PLITEM)lParam);
2223
2224
case LM_GETITEM:
2225
return SYSLINK_GetItem(infoPtr, (PLITEM)lParam);
2226
2227
case LM_GETIDEALHEIGHT:
2228
if (lParam)
2229
return SYSLINK_GetIdealSize(infoPtr, (int)wParam, (SIZE *)lParam);
2230
else
2231
return SYSLINK_GetIdealHeight(infoPtr);
2232
2233
case WM_SETFOCUS:
2234
return SYSLINK_SetFocus(infoPtr);
2235
2236
case WM_KILLFOCUS:
2237
return SYSLINK_KillFocus(infoPtr);
2238
2239
case WM_ENABLE:
2240
infoPtr->Style &= ~WS_DISABLED;
2241
infoPtr->Style |= (wParam ? 0 : WS_DISABLED);
2242
InvalidateRect (infoPtr->Self, NULL, FALSE);
2243
return 0;
2244
2245
case WM_STYLECHANGED:
2246
if (wParam == GWL_STYLE)
2247
infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew;
2248
return 0;
2249
2250
case WM_CREATE:
2251
{
2252
CREATESTRUCTW *cs = (CREATESTRUCTW*)lParam;
2253
2254
/* allocate memory for info struct */
2255
infoPtr = Alloc (sizeof(SYSLINK_INFO));
2256
if (!infoPtr) return -1;
2257
SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
2258
2259
/* initialize the info struct */
2260
infoPtr->Self = hwnd;
2261
infoPtr->Notify = cs->hwndParent;
2262
infoPtr->Style = cs->style;
2263
infoPtr->Font = 0;
2264
infoPtr->LinkFont = 0;
2265
list_init(&infoPtr->Items);
2266
infoPtr->HasFocus = FALSE;
2267
infoPtr->MouseDownID = -1;
2268
infoPtr->TextColor = comctl32_color.clrWindowText;
2269
infoPtr->LinkColor = comctl32_color.clrHighlight;
2270
infoPtr->VisitedColor = comctl32_color.clrHighlight;
2271
infoPtr->BreakChar = ' ';
2272
infoPtr->IgnoreReturn = infoPtr->Style & LWS_IGNORERETURN;
2273
TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd);
2274
SYSLINK_SetText(infoPtr, cs->lpszName);
2275
return 0;
2276
}
2277
case WM_DESTROY:
2278
TRACE("SysLink Ctrl destruction, hwnd=%p\n", hwnd);
2279
SYSLINK_ClearDoc(infoPtr);
2280
if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont);
2281
SetWindowLongPtrW(hwnd, 0, 0);
2282
if(infoPtr->AccessibleImpl) Accessible_WindowDestroyed(infoPtr->AccessibleImpl);
2283
Free (infoPtr);
2284
return 0;
2285
2286
case WM_GETOBJECT:
2287
{
2288
if ((DWORD)lParam == (DWORD)OBJID_CLIENT) {
2289
if (!infoPtr->AccessibleImpl)
2290
Accessible_Create(infoPtr);
2291
2292
if (infoPtr->AccessibleImpl)
2293
return LresultFromObject(&IID_IAccessible, wParam, (IUnknown*)&infoPtr->AccessibleImpl->IAccessible_iface);
2294
}
2295
return DefWindowProcW(hwnd, message, wParam, lParam);
2296
}
2297
2298
case WM_SYSCOLORCHANGE:
2299
COMCTL32_RefreshSysColors();
2300
return 0;
2301
2302
default:
2303
if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
2304
{
2305
ERR("unknown msg %04x, wp %Ix, lp %Ix\n", message, wParam, lParam );
2306
}
2307
return DefWindowProcW(hwnd, message, wParam, lParam);
2308
}
2309
}
2310
2311
2312
/***********************************************************************
2313
* SYSLINK_Register [Internal]
2314
*
2315
* Registers the SysLink window class.
2316
*/
2317
VOID SYSLINK_Register (void)
2318
{
2319
WNDCLASSW wndClass;
2320
2321
ZeroMemory (&wndClass, sizeof(wndClass));
2322
wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
2323
wndClass.lpfnWndProc = SysLinkWindowProc;
2324
wndClass.cbClsExtra = 0;
2325
wndClass.cbWndExtra = sizeof (SYSLINK_INFO *);
2326
wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2327
wndClass.lpszClassName = WC_LINK;
2328
2329
RegisterClassW (&wndClass);
2330
}
2331
2332
2333
/***********************************************************************
2334
* SYSLINK_Unregister [Internal]
2335
*
2336
* Unregisters the SysLink window class.
2337
*/
2338
VOID SYSLINK_Unregister (void)
2339
{
2340
UnregisterClassW (WC_LINK, NULL);
2341
}
2342
2343