ReactOS 0.4.16-dev-197-g92996da
syslink.c
Go to the documentation of this file.
1/*
2 * SysLink control
3 *
4 * Copyright 2004 - 2006 Thomas Weidenmueller <w3seek@reactos.com>
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#include <stdarg.h>
22#include <string.h>
23#include "windef.h"
24#include "winbase.h"
25#include "wingdi.h"
26#include "winuser.h"
27#include "winnls.h"
28#include "commctrl.h"
29#include "comctl32.h"
30#include "wine/debug.h"
31#include "wine/list.h"
32
34
35typedef struct
36{
37 int nChars;
38 int nSkip;
41
42#define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL)
43#define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED)
44
45typedef enum
46{
47 slText = 0,
48 slLink
50
51typedef struct _DOC_ITEM
52{
53 struct list entry;
54 UINT nText; /* Number of characters of the text */
55 SL_ITEM_TYPE Type; /* type of the item */
56 PDOC_TEXTBLOCK Blocks; /* Array of text blocks */
57 union
58 {
59 struct
60 {
61 UINT state; /* Link state */
62 WCHAR *szID; /* Link ID string */
63 WCHAR *szUrl; /* Link URL string */
65 struct
66 {
69 } u;
70 WCHAR Text[1]; /* Text of the document item */
72
73typedef struct
74{
75 HWND Self; /* The window handle for this control */
76 HWND Notify; /* The parent handle to receive notifications */
77 DWORD Style; /* Styles for this control */
78 struct list Items; /* Document items list */
79 BOOL HasFocus; /* Whether the control has the input focus */
80 int MouseDownID; /* ID of the link that the mouse button first selected */
81 HFONT Font; /* Handle to the font for text */
82 HFONT LinkFont; /* Handle to the font for links */
83 COLORREF TextColor; /* Color of the text */
84 COLORREF LinkColor; /* Color of links */
85 COLORREF VisitedColor; /* Color of visited links */
86 WCHAR BreakChar; /* Break Character for the current font */
87 BOOL IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */
89
90/* Control configuration constants */
91
92#define SL_LEFTMARGIN (0)
93#define SL_TOPMARGIN (0)
94#define SL_RIGHTMARGIN (0)
95#define SL_BOTTOMMARGIN (0)
96
97/***********************************************************************
98 * SYSLINK_FreeDocItem
99 * Frees all data and gdi objects associated with a document item
100 */
102{
103 if(DocItem->Type == slLink)
104 {
105 Free(DocItem->u.Link.szID);
106 Free(DocItem->u.Link.szUrl);
107 }
108
109 Free(DocItem->Blocks);
110
111 /* we don't free Text because it's just a pointer to a character in the
112 entire window text string */
113
114 Free(DocItem);
115}
116
117/***********************************************************************
118 * SYSLINK_AppendDocItem
119 * Create and append a new document item.
120 */
122 SL_ITEM_TYPE type, PDOC_ITEM LastItem)
123{
125
126 textlen = min(textlen, lstrlenW(Text));
127 Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1]));
128 if(Item == NULL)
129 {
130 ERR("Failed to alloc DOC_ITEM structure!\n");
131 return NULL;
132 }
133
134 Item->nText = textlen;
135 Item->Type = type;
136 Item->Blocks = NULL;
137 lstrcpynW(Item->Text, Text, textlen + 1);
138 if (LastItem)
139 list_add_after(&LastItem->entry, &Item->entry);
140 else
141 list_add_tail(&infoPtr->Items, &Item->entry);
142
143 return Item;
144}
145
146/***********************************************************************
147 * SYSLINK_ClearDoc
148 * Clears the document tree
149 */
151{
152 DOC_ITEM *Item, *Item2;
153
155 {
156 list_remove(&Item->entry);
158 }
159}
160
161/***********************************************************************
162 * SYSLINK_ParseText
163 * Parses the window text string and creates a document. Returns the
164 * number of document items created.
165 */
167{
168 static const WCHAR SL_LINKOPEN[] = { '<','a' };
169 static const WCHAR SL_HREF[] = { 'h','r','e','f','=','\"' };
170 static const WCHAR SL_ID[] = { 'i','d','=','\"' };
171 static const WCHAR SL_LINKCLOSE[] = { '<','/','a','>' };
172 LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL;
173 int taglen = 0, textlen = 0, linklen = 0, docitems = 0;
174 PDOC_ITEM Last = NULL;
175 SL_ITEM_TYPE CurrentType = slText;
176 LPCWSTR lpID, lpUrl;
177 UINT lenId, lenUrl;
178
179 TRACE("(%p %s)\n", infoPtr, debugstr_w(Text));
180
181 for(current = Text; *current != 0;)
182 {
183 if(*current == '<')
184 {
185 if(!wcsnicmp(current, SL_LINKOPEN, ARRAY_SIZE(SL_LINKOPEN)) && (CurrentType == slText))
186 {
187 BOOL ValidParam = FALSE, ValidLink = FALSE;
188
189 if(*(current + 2) == '>')
190 {
191 /* we just have to deal with a <a> tag */
192 taglen = 3;
193 ValidLink = TRUE;
194 ValidParam = TRUE;
195 firsttag = current;
196 linklen = 0;
197 lpID = NULL;
198 lpUrl = NULL;
199 }
200 else if(*(current + 2) == infoPtr->BreakChar)
201 {
202 /* we expect parameters, parse them */
203 LPCWSTR *CurrentParameter = NULL, tmp;
204 UINT *CurrentParameterLen = NULL;
205
206 taglen = 3;
207 tmp = current + taglen;
208 lpID = NULL;
209 lpUrl = NULL;
210
211CheckParameter:
212 /* compare the current position with all known parameters */
213 if(!wcsnicmp(tmp, SL_HREF, ARRAY_SIZE(SL_HREF)))
214 {
215 taglen += 6;
216 ValidParam = TRUE;
217 CurrentParameter = &lpUrl;
218 CurrentParameterLen = &lenUrl;
219 }
220 else if(!wcsnicmp(tmp, SL_ID, ARRAY_SIZE(SL_ID)))
221 {
222 taglen += 4;
223 ValidParam = TRUE;
224 CurrentParameter = &lpID;
225 CurrentParameterLen = &lenId;
226 }
227 else
228 {
229 ValidParam = FALSE;
230 }
231
232 if(ValidParam)
233 {
234 /* we got a known parameter, now search until the next " character.
235 If we can't find a " character, there's a syntax error and we just assume it's text */
236 ValidParam = FALSE;
237 *CurrentParameter = current + taglen;
238 *CurrentParameterLen = 0;
239
240 for(tmp = *CurrentParameter; *tmp != 0; tmp++)
241 {
242 taglen++;
243 if(*tmp == '\"')
244 {
245 ValidParam = TRUE;
246 tmp++;
247 break;
248 }
249 (*CurrentParameterLen)++;
250 }
251 }
252 if(ValidParam)
253 {
254 /* we're done with this parameter, now there are only 2 possibilities:
255 * 1. another parameter is coming, so expect a ' ' (space) character
256 * 2. the tag is being closed, so expect a '<' character
257 */
258 if(*tmp == infoPtr->BreakChar)
259 {
260 /* we expect another parameter, do the whole thing again */
261 taglen++;
262 tmp++;
263 goto CheckParameter;
264 }
265 else if(*tmp == '>')
266 {
267 /* the tag is being closed, we're done */
268 ValidLink = TRUE;
269 taglen++;
270 }
271 }
272 }
273
274 if(ValidLink && ValidParam)
275 {
276 /* the <a ...> tag appears to be valid. save all information
277 so we can add the link if we find a valid </a> tag later */
278 CurrentType = slLink;
279 linktext = current + taglen;
280 linklen = 0;
281 firsttag = current;
282 }
283 else
284 {
285 taglen = 1;
286 lpID = NULL;
287 lpUrl = NULL;
288 if(textstart == NULL)
289 {
290 textstart = current;
291 }
292 }
293 }
294 else if(!wcsnicmp(current, SL_LINKCLOSE, ARRAY_SIZE(SL_LINKCLOSE)) && (CurrentType == slLink) && firsttag)
295 {
296 /* there's a <a...> tag opened, first add the previous text, if present */
297 if(textstart != NULL && textlen > 0 && firsttag > textstart)
298 {
299 Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last);
300 if(Last == NULL)
301 {
302 ERR("Unable to create new document item!\n");
303 return docitems;
304 }
305 docitems++;
306 textstart = NULL;
307 textlen = 0;
308 }
309
310 /* now it's time to add the link to the document */
311 current += 4;
312 if(linktext != NULL && linklen > 0)
313 {
314 Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last);
315 if(Last == NULL)
316 {
317 ERR("Unable to create new document item!\n");
318 return docitems;
319 }
320 docitems++;
321 if(CurrentType == slLink)
322 {
323 int nc;
324
325 if(!(infoPtr->Style & WS_DISABLED))
326 {
327 Last->u.Link.state |= LIS_ENABLED;
328 }
329 /* Copy the tag parameters */
330 if(lpID != NULL)
331 {
332 nc = min(lenId, lstrlenW(lpID));
333 nc = min(nc, MAX_LINKID_TEXT - 1);
334 Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
335 if(Last->u.Link.szID != NULL)
336 {
337 lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
338 }
339 }
340 else
341 Last->u.Link.szID = NULL;
342 if(lpUrl != NULL)
343 {
344 nc = min(lenUrl, lstrlenW(lpUrl));
345 nc = min(nc, L_MAX_URL_LENGTH - 1);
346 Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
347 if(Last->u.Link.szUrl != NULL)
348 {
349 lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
350 }
351 }
352 else
353 Last->u.Link.szUrl = NULL;
354 }
355 linktext = NULL;
356 }
357 CurrentType = slText;
358 firsttag = NULL;
359 textstart = NULL;
360 continue;
361 }
362 else
363 {
364 /* we don't know what tag it is, so just continue */
365 taglen = 1;
366 linklen++;
367 if(CurrentType == slText && textstart == NULL)
368 {
369 textstart = current;
370 }
371 }
372
373 textlen += taglen;
374 current += taglen;
375 }
376 else
377 {
378 textlen++;
379 linklen++;
380
381 /* save the pointer of the current text item if we couldn't find a tag */
382 if(textstart == NULL && CurrentType == slText)
383 {
384 textstart = current;
385 }
386
387 current++;
388 }
389 }
390
391 if(textstart != NULL && textlen > 0)
392 {
393 Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last);
394 if(Last == NULL)
395 {
396 ERR("Unable to create new document item!\n");
397 return docitems;
398 }
399 if(CurrentType == slLink)
400 {
401 int nc;
402
403 if(!(infoPtr->Style & WS_DISABLED))
404 {
405 Last->u.Link.state |= LIS_ENABLED;
406 }
407 /* Copy the tag parameters */
408 if(lpID != NULL)
409 {
410 nc = min(lenId, lstrlenW(lpID));
411 nc = min(nc, MAX_LINKID_TEXT - 1);
412 Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
413 if(Last->u.Link.szID != NULL)
414 {
415 lstrcpynW(Last->u.Link.szID, lpID, nc + 1);
416 }
417 }
418 else
419 Last->u.Link.szID = NULL;
420 if(lpUrl != NULL)
421 {
422 nc = min(lenUrl, lstrlenW(lpUrl));
423 nc = min(nc, L_MAX_URL_LENGTH - 1);
424 Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
425 if(Last->u.Link.szUrl != NULL)
426 {
427 lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1);
428 }
429 }
430 else
431 Last->u.Link.szUrl = NULL;
432 }
433 docitems++;
434 }
435
436 if(linktext != NULL && linklen > 0)
437 {
438 /* we got an unclosed link, just display the text */
439 Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slText, Last);
440 if(Last == NULL)
441 {
442 ERR("Unable to create new document item!\n");
443 return docitems;
444 }
445 docitems++;
446 }
447
448 return docitems;
449}
450
451/***********************************************************************
452 * SYSLINK_RepaintLink
453 * Repaints a link.
454 */
455static VOID SYSLINK_RepaintLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
456{
458 int n;
459
460 if(DocItem->Type != slLink)
461 {
462 ERR("DocItem not a link!\n");
463 return;
464 }
465
466 bl = DocItem->Blocks;
467 if (bl != NULL)
468 {
469 n = DocItem->nText;
470
471 while(n > 0)
472 {
473 InvalidateRect(infoPtr->Self, &bl->rc, TRUE);
474 n -= bl->nChars + bl->nSkip;
475 bl++;
476 }
477 }
478}
479
480/***********************************************************************
481 * SYSLINK_GetLinkItemByIndex
482 * Retrieves a document link by its index
483 */
484static PDOC_ITEM SYSLINK_GetLinkItemByIndex (const SYSLINK_INFO *infoPtr, int iLink)
485{
486 DOC_ITEM *Current;
487
488 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
489 {
490 if ((Current->Type == slLink) && (iLink-- <= 0))
491 return Current;
492 }
493 return NULL;
494}
495
496/***********************************************************************
497 * SYSLINK_GetFocusLink
498 * Retrieves the link that has the LIS_FOCUSED bit
499 */
500static PDOC_ITEM SYSLINK_GetFocusLink (const SYSLINK_INFO *infoPtr, int *LinkId)
501{
502 DOC_ITEM *Current;
503 int id = 0;
504
505 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
506 {
507 if(Current->Type == slLink)
508 {
509 if(Current->u.Link.state & LIS_FOCUSED)
510 {
511 if(LinkId != NULL)
512 *LinkId = id;
513 return Current;
514 }
515 id++;
516 }
517 }
518
519 return NULL;
520}
521
522/***********************************************************************
523 * SYSLINK_GetNextLink
524 * Gets the next link
525 */
526static PDOC_ITEM SYSLINK_GetNextLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
527{
528 DOC_ITEM *Next;
529
530 LIST_FOR_EACH_ENTRY(Next, Current ? &Current->entry : &infoPtr->Items, DOC_ITEM, entry)
531 {
532 if (Next->Type == slLink)
533 {
534 return Next;
535 }
536 }
537 return NULL;
538}
539
540/***********************************************************************
541 * SYSLINK_GetPrevLink
542 * Gets the previous link
543 */
544static PDOC_ITEM SYSLINK_GetPrevLink (const SYSLINK_INFO *infoPtr, PDOC_ITEM Current)
545{
546 DOC_ITEM *Prev;
547
548 LIST_FOR_EACH_ENTRY_REV(Prev, Current ? &Current->entry : list_tail(&infoPtr->Items), DOC_ITEM, entry)
549 {
550 if (Prev->Type == slLink)
551 {
552 return Prev;
553 }
554 }
555
556 return NULL;
557}
558
559/***********************************************************************
560 * SYSLINK_WrapLine
561 * Tries to wrap a line.
562 */
563static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int x, int *LineLen,
564 int nFit, LPSIZE Extent)
565{
566 int i;
567
568 for (i = 0; i < nFit; i++) if (Text[i] == '\r' || Text[i] == '\n') break;
569
570 if (i == *LineLen) return FALSE;
571
572 /* check if we're in the middle of a word */
573 if (Text[i] != '\r' && Text[i] != '\n' && Text[i] != BreakChar)
574 {
575 /* search for the beginning of the word */
576 while (i && Text[i - 1] != BreakChar) i--;
577
578 if (i == 0)
579 {
580 Extent->cx = 0;
581 Extent->cy = 0;
582 if (x == SL_LEFTMARGIN) i = max( nFit, 1 );
583 }
584 }
585 *LineLen = i;
586 return TRUE;
587}
588
589/***********************************************************************
590 * SYSLINK_Render
591 * Renders the document in memory
592 */
593static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc, PRECT pRect)
594{
595 RECT rc;
596 PDOC_ITEM Current;
597 HGDIOBJ hOldFont;
598 int x, y, LineHeight;
599 SIZE szDoc;
601
602 szDoc.cx = szDoc.cy = 0;
603
604 rc = *pRect;
605 rc.right -= SL_RIGHTMARGIN;
607
608 if(rc.right - SL_LEFTMARGIN < 0)
609 rc.right = MAXLONG;
610 if (rc.bottom - SL_TOPMARGIN < 0)
611 rc.bottom = MAXLONG;
612
613 hOldFont = SelectObject(hdc, infoPtr->Font);
614
616 y = SL_TOPMARGIN;
618 LineHeight = tm.tmHeight + tm.tmExternalLeading;
619
620 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
621 {
622 int n, nBlocks;
623 LPWSTR tx;
624 PDOC_TEXTBLOCK bl, cbl;
625 INT nFit;
626 SIZE szDim;
627 int SkipChars = 0;
628
629 if(Current->nText == 0)
630 {
631 continue;
632 }
633
634 tx = Current->Text;
635 n = Current->nText;
636
637 Free(Current->Blocks);
638 Current->Blocks = NULL;
639 bl = NULL;
640 nBlocks = 0;
641
642 if(Current->Type == slText)
643 {
644 SelectObject(hdc, infoPtr->Font);
645 }
646 else if(Current->Type == slLink)
647 {
648 SelectObject(hdc, infoPtr->LinkFont);
649 }
650
651 while(n > 0)
652 {
653 /* skip break characters unless they're the first of the doc item */
654 if(tx != Current->Text || x == SL_LEFTMARGIN)
655 {
656 if (n && *tx == '\r')
657 {
658 tx++;
659 SkipChars++;
660 n--;
661 }
662 if (n && *tx == '\n')
663 {
664 tx++;
665 SkipChars++;
666 n--;
667 }
668 while(n > 0 && (*tx) == infoPtr->BreakChar)
669 {
670 tx++;
671 SkipChars++;
672 n--;
673 }
674 }
675
676 if((n == 0 && SkipChars != 0) ||
677 GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim))
678 {
679 int LineLen = n;
680 BOOL Wrap = FALSE;
681 PDOC_TEXTBLOCK nbl;
682
683 if(n != 0)
684 {
685 Wrap = SYSLINK_WrapLine(tx, infoPtr->BreakChar, x, &LineLen, nFit, &szDim);
686
687 if(LineLen == 0)
688 {
689 /* move one line down, the word didn't fit into the line */
691 y += LineHeight;
692 continue;
693 }
694
695 if(LineLen != n)
696 {
697 if(!GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim))
698 {
699 if(bl != NULL)
700 {
701 Free(bl);
702 bl = NULL;
703 nBlocks = 0;
704 }
705 break;
706 }
707 }
708 }
709
710 nbl = ReAlloc(bl, (nBlocks + 1) * sizeof(DOC_TEXTBLOCK));
711 if (nbl != NULL)
712 {
713 bl = nbl;
714 nBlocks++;
715
716 cbl = bl + nBlocks - 1;
717
718 cbl->nChars = LineLen;
719 cbl->nSkip = SkipChars;
720 SetRect(&cbl->rc, x, y, x + szDim.cx, y + szDim.cy);
721
722 if (cbl->rc.right > szDoc.cx)
723 szDoc.cx = cbl->rc.right;
724 if (cbl->rc.bottom > szDoc.cy)
725 szDoc.cy = cbl->rc.bottom;
726
727 if(LineLen != 0)
728 {
729 x += szDim.cx;
730 if(Wrap)
731 {
733 y += LineHeight;
734 }
735 }
736 }
737 else
738 {
739 Free(bl);
740 bl = NULL;
741 nBlocks = 0;
742
743 ERR("Failed to alloc DOC_TEXTBLOCK structure!\n");
744 break;
745 }
746 n -= LineLen;
747 tx += LineLen;
748 SkipChars = 0;
749 }
750 else
751 {
752 n--;
753 }
754 }
755
756 if(nBlocks != 0)
757 {
758 Current->Blocks = bl;
759 }
760 }
761
762 SelectObject(hdc, hOldFont);
763
764 pRect->right = pRect->left + szDoc.cx;
765 pRect->bottom = pRect->top + szDoc.cy;
766}
767
768/***********************************************************************
769 * SYSLINK_Draw
770 * Draws the SysLink control.
771 */
772static LRESULT SYSLINK_Draw (const SYSLINK_INFO *infoPtr, HDC hdc)
773{
774 RECT rc;
775 PDOC_ITEM Current;
776 HFONT hOldFont;
777 COLORREF OldTextColor, OldBkColor;
778 HBRUSH hBrush;
779 UINT text_flags = ETO_CLIPPED;
780 UINT mode = GetBkMode( hdc );
781
782 hOldFont = SelectObject(hdc, infoPtr->Font);
783 OldTextColor = SetTextColor(hdc, infoPtr->TextColor);
784 OldBkColor = SetBkColor(hdc, comctl32_color.clrWindow);
785
786 GetClientRect(infoPtr->Self, &rc);
789
790 if(rc.right < 0 || rc.bottom < 0) return 0;
791
792 hBrush = (HBRUSH)SendMessageW(infoPtr->Notify, WM_CTLCOLORSTATIC,
793 (WPARAM)hdc, (LPARAM)infoPtr->Self);
794 if (!(infoPtr->Style & LWS_TRANSPARENT))
795 {
796 FillRect(hdc, &rc, hBrush);
797 if (GetBkMode( hdc ) == OPAQUE) text_flags |= ETO_OPAQUE;
798 }
799 else SetBkMode( hdc, TRANSPARENT );
800
801#ifndef __REACTOS__
802 DeleteObject(hBrush);
803#endif
804
805 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
806 {
807 int n;
808 LPWSTR tx;
810
811 bl = Current->Blocks;
812 if(bl != NULL)
813 {
814 tx = Current->Text;
815 n = Current->nText;
816
817 if(Current->Type == slText)
818 {
819 SelectObject(hdc, infoPtr->Font);
820 SetTextColor(hdc, infoPtr->TextColor);
821 }
822 else
823 {
824 SelectObject(hdc, infoPtr->LinkFont);
825 SetTextColor(hdc, (!(Current->u.Link.state & LIS_VISITED) ? infoPtr->LinkColor : infoPtr->VisitedColor));
826 }
827
828 while(n > 0)
829 {
830 tx += bl->nSkip;
831 ExtTextOutW(hdc, bl->rc.left, bl->rc.top, text_flags, &bl->rc, tx, bl->nChars, NULL);
832 if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus)
833 {
834 COLORREF PrevTextColor;
835 PrevTextColor = SetTextColor(hdc, infoPtr->TextColor);
836 DrawFocusRect(hdc, &bl->rc);
837 SetTextColor(hdc, PrevTextColor);
838 }
839 tx += bl->nChars;
840 n -= bl->nChars + bl->nSkip;
841 bl++;
842 }
843 }
844 }
845
846 SetBkColor(hdc, OldBkColor);
847 SetTextColor(hdc, OldTextColor);
848 SelectObject(hdc, hOldFont);
850 return 0;
851}
852
853
854/***********************************************************************
855 * SYSLINK_Paint
856 * Handles the WM_PAINT message.
857 */
858static LRESULT SYSLINK_Paint (const SYSLINK_INFO *infoPtr, HDC hdcParam)
859{
860 HDC hdc;
861 PAINTSTRUCT ps;
862
863 hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps);
864 if (hdc)
865 {
866 SYSLINK_Draw (infoPtr, hdc);
867 if (!hdcParam) EndPaint (infoPtr->Self, &ps);
868 }
869 return 0;
870}
871
872/***********************************************************************
873 * SYSLINK_SetFont
874 * Set new Font for the SysLink control.
875 */
877{
878 HDC hdc;
879 LOGFONTW lf;
881 RECT rcClient;
882 HFONT hOldFont = infoPtr->Font;
883 infoPtr->Font = hFont;
884
885 /* free the underline font */
886 if(infoPtr->LinkFont != NULL)
887 {
888 DeleteObject(infoPtr->LinkFont);
889 infoPtr->LinkFont = NULL;
890 }
891
892 /* Render text position and word wrapping in memory */
893 if (GetClientRect(infoPtr->Self, &rcClient))
894 {
895 hdc = GetDC(infoPtr->Self);
896 if(hdc != NULL)
897 {
898 /* create a new underline font */
899 if(GetTextMetricsW(hdc, &tm) &&
900 GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf))
901 {
902 lf.lfUnderline = TRUE;
903 infoPtr->LinkFont = CreateFontIndirectW(&lf);
904 infoPtr->BreakChar = tm.tmBreakChar;
905 }
906 else
907 {
908 ERR("Failed to create link font!\n");
909 }
910
911 SYSLINK_Render(infoPtr, hdc, &rcClient);
912 ReleaseDC(infoPtr->Self, hdc);
913 }
914 }
915
916 if(bRedraw)
917 {
919 }
920
921 return hOldFont;
922}
923
924/***********************************************************************
925 * SYSLINK_SetText
926 * Set new text for the SysLink control.
927 */
929{
930 /* clear the document */
931 SYSLINK_ClearDoc(infoPtr);
932
933 if(Text == NULL || *Text == 0)
934 {
935 return TRUE;
936 }
937
938 /* let's parse the string and create a document */
939 if(SYSLINK_ParseText(infoPtr, Text) > 0)
940 {
941 RECT rcClient;
942
943 /* Render text position and word wrapping in memory */
944 if (GetClientRect(infoPtr->Self, &rcClient))
945 {
946 HDC hdc = GetDC(infoPtr->Self);
947 if (hdc != NULL)
948 {
949 SYSLINK_Render(infoPtr, hdc, &rcClient);
950 ReleaseDC(infoPtr->Self, hdc);
951
952 InvalidateRect(infoPtr->Self, NULL, TRUE);
953 }
954 }
955 }
956
957 return TRUE;
958}
959
960/***********************************************************************
961 * SYSLINK_SetFocusLink
962 * Updates the focus status bits and focuses the specified link.
963 * If no document item is specified, the focus bit will be removed from all links.
964 * Returns the previous focused item.
965 */
966static PDOC_ITEM SYSLINK_SetFocusLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
967{
968 PDOC_ITEM Current, PrevFocus = NULL;
969
970 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
971 {
972 if(Current->Type == slLink)
973 {
974 if((PrevFocus == NULL) && (Current->u.Link.state & LIS_FOCUSED))
975 {
976 PrevFocus = Current;
977 }
978
979 if(Current == DocItem)
980 {
981 Current->u.Link.state |= LIS_FOCUSED;
982 }
983 else
984 {
985 Current->u.Link.state &= ~LIS_FOCUSED;
986 }
987 }
988 }
989
990 return PrevFocus;
991}
992
993/***********************************************************************
994 * SYSLINK_SetItem
995 * Sets the states and attributes of a link item.
996 */
997static LRESULT SYSLINK_SetItem (const SYSLINK_INFO *infoPtr, const LITEM *Item)
998{
999 PDOC_ITEM di;
1000 int nc;
1001 PWSTR szId = NULL;
1002 PWSTR szUrl = NULL;
1003 BOOL Repaint = FALSE;
1004
1005 if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK)))
1006 {
1007 ERR("Invalid Flags!\n");
1008 return FALSE;
1009 }
1010
1011 di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink);
1012 if(di == NULL)
1013 {
1014 ERR("Link %d couldn't be found\n", Item->iLink);
1015 return FALSE;
1016 }
1017
1018 if(Item->mask & LIF_ITEMID)
1019 {
1020 nc = min(lstrlenW(Item->szID), MAX_LINKID_TEXT - 1);
1021 szId = Alloc((nc + 1) * sizeof(WCHAR));
1022 if(szId)
1023 {
1024 lstrcpynW(szId, Item->szID, nc + 1);
1025 }
1026 else
1027 {
1028 ERR("Unable to allocate memory for link id\n");
1029 return FALSE;
1030 }
1031 }
1032
1033 if(Item->mask & LIF_URL)
1034 {
1035 nc = min(lstrlenW(Item->szUrl), L_MAX_URL_LENGTH - 1);
1036 szUrl = Alloc((nc + 1) * sizeof(WCHAR));
1037 if(szUrl)
1038 {
1039 lstrcpynW(szUrl, Item->szUrl, nc + 1);
1040 }
1041 else
1042 {
1043 Free(szId);
1044
1045 ERR("Unable to allocate memory for link url\n");
1046 return FALSE;
1047 }
1048 }
1049
1050 if(Item->mask & LIF_ITEMID)
1051 {
1052 Free(di->u.Link.szID);
1053 di->u.Link.szID = szId;
1054 }
1055
1056 if(Item->mask & LIF_URL)
1057 {
1058 Free(di->u.Link.szUrl);
1059 di->u.Link.szUrl = szUrl;
1060 }
1061
1062 if(Item->mask & LIF_STATE)
1063 {
1064 UINT oldstate = di->u.Link.state;
1065 /* clear the masked bits */
1066 di->u.Link.state &= ~(Item->stateMask & LIS_MASK);
1067 /* copy the bits */
1068 di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK;
1069 Repaint = (oldstate != di->u.Link.state);
1070
1071 /* update the focus */
1072 SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL));
1073 }
1074
1075 if(Repaint)
1076 {
1077 SYSLINK_RepaintLink(infoPtr, di);
1078 }
1079
1080 return TRUE;
1081}
1082
1083/***********************************************************************
1084 * SYSLINK_GetItem
1085 * Retrieves the states and attributes of a link item.
1086 */
1088{
1089 PDOC_ITEM di;
1090
1091 if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK)))
1092 {
1093 ERR("Invalid Flags!\n");
1094 return FALSE;
1095 }
1096
1097 di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink);
1098 if(di == NULL)
1099 {
1100 ERR("Link %d couldn't be found\n", Item->iLink);
1101 return FALSE;
1102 }
1103
1104 if(Item->mask & LIF_STATE)
1105 {
1106 Item->state = (di->u.Link.state & Item->stateMask);
1107 if(!infoPtr->HasFocus)
1108 {
1109 /* remove the LIS_FOCUSED bit if the control doesn't have focus */
1110 Item->state &= ~LIS_FOCUSED;
1111 }
1112 }
1113
1114 if(Item->mask & LIF_ITEMID)
1115 {
1116 if(di->u.Link.szID)
1117 {
1118 lstrcpyW(Item->szID, di->u.Link.szID);
1119 }
1120 else
1121 {
1122 Item->szID[0] = 0;
1123 }
1124 }
1125
1126 if(Item->mask & LIF_URL)
1127 {
1128 if(di->u.Link.szUrl)
1129 {
1130 lstrcpyW(Item->szUrl, di->u.Link.szUrl);
1131 }
1132 else
1133 {
1134 Item->szUrl[0] = 0;
1135 }
1136 }
1137
1138 return TRUE;
1139}
1140
1141/***********************************************************************
1142 * SYSLINK_PtInDocItem
1143 * Determines if a point is in the region of a document item
1144 */
1145static BOOL SYSLINK_PtInDocItem (const DOC_ITEM *DocItem, POINT pt)
1146{
1147 PDOC_TEXTBLOCK bl;
1148 int n;
1149
1150 bl = DocItem->Blocks;
1151 if (bl != NULL)
1152 {
1153 n = DocItem->nText;
1154
1155 while(n > 0)
1156 {
1157 if (PtInRect(&bl->rc, pt))
1158 {
1159 return TRUE;
1160 }
1161 n -= bl->nChars + bl->nSkip;
1162 bl++;
1163 }
1164 }
1165
1166 return FALSE;
1167}
1168
1169/***********************************************************************
1170 * SYSLINK_HitTest
1171 * Determines the link the user clicked on.
1172 */
1173static LRESULT SYSLINK_HitTest (const SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest)
1174{
1175 PDOC_ITEM Current;
1176 int id = 0;
1177
1178 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1179 {
1180 if(Current->Type == slLink)
1181 {
1182 if(SYSLINK_PtInDocItem(Current, HitTest->pt))
1183 {
1184 HitTest->item.mask = 0;
1185 HitTest->item.iLink = id;
1186 HitTest->item.state = 0;
1187 HitTest->item.stateMask = 0;
1188 if(Current->u.Link.szID)
1189 {
1190 lstrcpyW(HitTest->item.szID, Current->u.Link.szID);
1191 }
1192 else
1193 {
1194 HitTest->item.szID[0] = 0;
1195 }
1196 if(Current->u.Link.szUrl)
1197 {
1198 lstrcpyW(HitTest->item.szUrl, Current->u.Link.szUrl);
1199 }
1200 else
1201 {
1202 HitTest->item.szUrl[0] = 0;
1203 }
1204 return TRUE;
1205 }
1206 id++;
1207 }
1208 }
1209
1210 return FALSE;
1211}
1212
1213/***********************************************************************
1214 * SYSLINK_GetIdealHeight
1215 * Returns the preferred height of a link at the current control's width.
1216 */
1218{
1219 HDC hdc = GetDC(infoPtr->Self);
1220 if(hdc != NULL)
1221 {
1224 HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font);
1225
1226 if(GetTextMetricsW(hdc, &tm))
1227 {
1228 height = tm.tmHeight;
1229 }
1230 else
1231 {
1232 height = 0;
1233 }
1234 SelectObject(hdc, hOldFont);
1235 ReleaseDC(infoPtr->Self, hdc);
1236
1237 return height;
1238 }
1239 return 0;
1240}
1241
1242/***********************************************************************
1243 * SYSLINK_SendParentNotify
1244 * Sends a WM_NOTIFY message to the parent window.
1245 */
1246static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink)
1247{
1248 NMLINK nml;
1249
1250 nml.hdr.hwndFrom = infoPtr->Self;
1251 nml.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID);
1252 nml.hdr.code = code;
1253
1254 nml.item.mask = 0;
1255 nml.item.iLink = iLink;
1256 nml.item.state = 0;
1257 nml.item.stateMask = 0;
1258 if(Link->u.Link.szID)
1259 {
1260 lstrcpyW(nml.item.szID, Link->u.Link.szID);
1261 }
1262 else
1263 {
1264 nml.item.szID[0] = 0;
1265 }
1266 if(Link->u.Link.szUrl)
1267 {
1268 lstrcpyW(nml.item.szUrl, Link->u.Link.szUrl);
1269 }
1270 else
1271 {
1272 nml.item.szUrl[0] = 0;
1273 }
1274
1275 return SendMessageW(infoPtr->Notify, WM_NOTIFY, nml.hdr.idFrom, (LPARAM)&nml);
1276}
1277
1278/***********************************************************************
1279 * SYSLINK_SetFocus
1280 * Handles receiving the input focus.
1281 */
1283{
1284 PDOC_ITEM Focus;
1285
1286 infoPtr->HasFocus = TRUE;
1287
1288 /* We always select the first link, even if we activated the control using
1289 SHIFT+TAB. This is the default behavior */
1290 Focus = SYSLINK_GetNextLink(infoPtr, NULL);
1291 if(Focus != NULL)
1292 {
1293 SYSLINK_SetFocusLink(infoPtr, Focus);
1294 SYSLINK_RepaintLink(infoPtr, Focus);
1295 }
1296 return 0;
1297}
1298
1299/***********************************************************************
1300 * SYSLINK_KillFocus
1301 * Handles losing the input focus.
1302 */
1304{
1305 PDOC_ITEM Focus;
1306
1307 infoPtr->HasFocus = FALSE;
1308 Focus = SYSLINK_GetFocusLink(infoPtr, NULL);
1309
1310 if(Focus != NULL)
1311 {
1312 SYSLINK_RepaintLink(infoPtr, Focus);
1313 }
1314
1315 return 0;
1316}
1317
1318/***********************************************************************
1319 * SYSLINK_LinkAtPt
1320 * Returns a link at the specified position
1321 */
1322static PDOC_ITEM SYSLINK_LinkAtPt (const SYSLINK_INFO *infoPtr, const POINT *pt, int *LinkId, BOOL MustBeEnabled)
1323{
1324 PDOC_ITEM Current;
1325 int id = 0;
1326
1327 LIST_FOR_EACH_ENTRY(Current, &infoPtr->Items, DOC_ITEM, entry)
1328 {
1329 if((Current->Type == slLink) && SYSLINK_PtInDocItem(Current, *pt) &&
1330 (!MustBeEnabled || (Current->u.Link.state & LIS_ENABLED)))
1331 {
1332 if(LinkId != NULL)
1333 {
1334 *LinkId = id;
1335 }
1336 return Current;
1337 }
1338 id++;
1339 }
1340
1341 return NULL;
1342}
1343
1344/***********************************************************************
1345 * SYSLINK_LButtonDown
1346 * Handles mouse clicks
1347 */
1349{
1350 PDOC_ITEM Current, Old;
1351 int id;
1352
1353 Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE);
1354 if(Current != NULL)
1355 {
1356 SetFocus(infoPtr->Self);
1357
1358 Old = SYSLINK_SetFocusLink(infoPtr, Current);
1359 if(Old != NULL && Old != Current)
1360 {
1361 SYSLINK_RepaintLink(infoPtr, Old);
1362 }
1363 infoPtr->MouseDownID = id;
1364 SYSLINK_RepaintLink(infoPtr, Current);
1365 }
1366
1367 return 0;
1368}
1369
1370/***********************************************************************
1371 * SYSLINK_LButtonUp
1372 * Handles mouse clicks
1373 */
1375{
1376 if(infoPtr->MouseDownID > -1)
1377 {
1378 PDOC_ITEM Current;
1379 int id;
1380
1381 Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE);
1382 if((Current != NULL) && (Current->u.Link.state & LIS_FOCUSED) && (infoPtr->MouseDownID == id))
1383 {
1384 SYSLINK_SendParentNotify(infoPtr, NM_CLICK, Current, id);
1385 }
1386 }
1387
1388 infoPtr->MouseDownID = -1;
1389
1390 return 0;
1391}
1392
1393/***********************************************************************
1394 * SYSLINK_OnEnter
1395 * Handles ENTER key events
1396 */
1397static BOOL SYSLINK_OnEnter (const SYSLINK_INFO *infoPtr)
1398{
1399 if(infoPtr->HasFocus && !infoPtr->IgnoreReturn)
1400 {
1401 PDOC_ITEM Focus;
1402 int id;
1403
1404 Focus = SYSLINK_GetFocusLink(infoPtr, &id);
1405 if(Focus)
1406 {
1407 SYSLINK_SendParentNotify(infoPtr, NM_RETURN, Focus, id);
1408 return TRUE;
1409 }
1410 }
1411 return FALSE;
1412}
1413
1414/***********************************************************************
1415 * SYSKEY_SelectNextPrevLink
1416 * Changes the currently focused link
1417 */
1419{
1420 if(infoPtr->HasFocus)
1421 {
1422 PDOC_ITEM Focus;
1423 int id;
1424
1425 Focus = SYSLINK_GetFocusLink(infoPtr, &id);
1426 if(Focus != NULL)
1427 {
1428 PDOC_ITEM NewFocus, OldFocus;
1429
1430 if(Prev)
1431 NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus);
1432 else
1433 NewFocus = SYSLINK_GetNextLink(infoPtr, Focus);
1434
1435 if(NewFocus != NULL)
1436 {
1437 OldFocus = SYSLINK_SetFocusLink(infoPtr, NewFocus);
1438
1439 if(OldFocus && OldFocus != NewFocus)
1440 {
1441 SYSLINK_RepaintLink(infoPtr, OldFocus);
1442 }
1443 SYSLINK_RepaintLink(infoPtr, NewFocus);
1444 return TRUE;
1445 }
1446 }
1447 }
1448 return FALSE;
1449}
1450
1451/***********************************************************************
1452 * SYSKEY_SelectNextPrevLink
1453 * Determines if there's a next or previous link to decide whether the control
1454 * should capture the tab key message
1455 */
1456static BOOL SYSLINK_NoNextLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
1457{
1458 PDOC_ITEM Focus, NewFocus;
1459
1460 Focus = SYSLINK_GetFocusLink(infoPtr, NULL);
1461 if(Prev)
1462 NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus);
1463 else
1464 NewFocus = SYSLINK_GetNextLink(infoPtr, Focus);
1465
1466 return NewFocus == NULL;
1467}
1468
1469/***********************************************************************
1470 * SYSLINK_GetIdealSize
1471 * Calculates the ideal size of a link control at a given maximum width.
1472 */
1473static LONG SYSLINK_GetIdealSize (const SYSLINK_INFO *infoPtr, int cxMaxWidth, SIZE *lpSize)
1474{
1475 RECT rc;
1476 HDC hdc;
1477
1478 rc.left = rc.top = rc.bottom = 0;
1479 rc.right = cxMaxWidth;
1480
1481 hdc = GetDC(infoPtr->Self);
1482 if (hdc != NULL)
1483 {
1484 HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font);
1485
1486 SYSLINK_Render(infoPtr, hdc, &rc);
1487
1488 SelectObject(hdc, hOldFont);
1489 ReleaseDC(infoPtr->Self, hdc);
1490
1491 lpSize->cx = rc.right;
1492 lpSize->cy = rc.bottom;
1493 }
1494
1495 return rc.bottom;
1496}
1497
1498/***********************************************************************
1499 * SysLinkWindowProc
1500 */
1503{
1504 SYSLINK_INFO *infoPtr;
1505
1506 TRACE("hwnd=%p msg=%04x wparam=%lx lParam=%lx\n", hwnd, message, wParam, lParam);
1507
1508 infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0);
1509
1510 if (!infoPtr && message != WM_CREATE)
1512
1513 switch(message) {
1514 case WM_PRINTCLIENT:
1515 case WM_PAINT:
1516 return SYSLINK_Paint (infoPtr, (HDC)wParam);
1517
1518 case WM_ERASEBKGND:
1519 if (!(infoPtr->Style & LWS_TRANSPARENT))
1520 {
1521 HDC hdc = (HDC)wParam;
1522 HBRUSH brush = CreateSolidBrush( comctl32_color.clrWindow );
1523 RECT rect;
1524
1525 GetClipBox( hdc, &rect );
1526 FillRect( hdc, &rect, brush );
1527 DeleteObject( brush );
1528 return 1;
1529 }
1530 return 0;
1531
1532 case WM_SETCURSOR:
1533 {
1535 DWORD mp = GetMessagePos();
1536
1537 ht.pt.x = (short)LOWORD(mp);
1538 ht.pt.y = (short)HIWORD(mp);
1539
1540 ScreenToClient(infoPtr->Self, &ht.pt);
1541 if(SYSLINK_HitTest (infoPtr, &ht))
1542 {
1544 return TRUE;
1545 }
1546
1548 }
1549
1550 case WM_SIZE:
1551 {
1552 RECT rcClient;
1553 if (GetClientRect(infoPtr->Self, &rcClient))
1554 {
1555 HDC hdc = GetDC(infoPtr->Self);
1556 if(hdc != NULL)
1557 {
1558 SYSLINK_Render(infoPtr, hdc, &rcClient);
1559 ReleaseDC(infoPtr->Self, hdc);
1560 }
1561 }
1562 return 0;
1563 }
1564
1565 case WM_GETFONT:
1566 return (LRESULT)infoPtr->Font;
1567
1568 case WM_SETFONT:
1569 return (LRESULT)SYSLINK_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
1570
1571 case WM_SETTEXT:
1572 SYSLINK_SetText(infoPtr, (LPWSTR)lParam);
1574
1575 case WM_LBUTTONDOWN:
1576 {
1577 POINT pt;
1578 pt.x = (short)LOWORD(lParam);
1579 pt.y = (short)HIWORD(lParam);
1580 return SYSLINK_LButtonDown(infoPtr, &pt);
1581 }
1582 case WM_LBUTTONUP:
1583 {
1584 POINT pt;
1585 pt.x = (short)LOWORD(lParam);
1586 pt.y = (short)HIWORD(lParam);
1587 return SYSLINK_LButtonUp(infoPtr, &pt);
1588 }
1589
1590 case WM_KEYDOWN:
1591 {
1592 switch(wParam)
1593 {
1594 case VK_RETURN:
1595 SYSLINK_OnEnter(infoPtr);
1596 return 0;
1597 case VK_TAB:
1598 {
1599 BOOL shift = GetKeyState(VK_SHIFT) & 0x8000;
1601 return 0;
1602 }
1603 default:
1605 }
1606 }
1607
1608 case WM_GETDLGCODE:
1609 {
1610 LRESULT Ret = DLGC_HASSETSEL;
1611 int vk = (lParam != 0 ? (int)((LPMSG)lParam)->wParam : 0);
1612 switch(vk)
1613 {
1614 case VK_RETURN:
1615 Ret |= DLGC_WANTMESSAGE;
1616 break;
1617 case VK_TAB:
1618 {
1619 BOOL shift = GetKeyState(VK_SHIFT) & 0x8000;
1620 if(!SYSLINK_NoNextLink(infoPtr, shift))
1621 {
1622 Ret |= DLGC_WANTTAB;
1623 }
1624 else
1625 {
1626 Ret |= DLGC_WANTCHARS;
1627 }
1628 break;
1629 }
1630 }
1631 return Ret;
1632 }
1633
1634 case WM_NCHITTEST:
1635 {
1636 POINT pt;
1637 RECT rc;
1638 pt.x = (short)LOWORD(lParam);
1639 pt.y = (short)HIWORD(lParam);
1640
1641 GetClientRect(infoPtr->Self, &rc);
1642 ScreenToClient(infoPtr->Self, &pt);
1643 if(pt.x < 0 || pt.y < 0 || pt.x > rc.right || pt.y > rc.bottom)
1644 {
1645 return HTNOWHERE;
1646 }
1647
1648 if(SYSLINK_LinkAtPt(infoPtr, &pt, NULL, FALSE))
1649 {
1650 return HTCLIENT;
1651 }
1652
1653 return HTTRANSPARENT;
1654 }
1655
1656 case LM_HITTEST:
1657 return SYSLINK_HitTest(infoPtr, (PLHITTESTINFO)lParam);
1658
1659 case LM_SETITEM:
1660 return SYSLINK_SetItem(infoPtr, (PLITEM)lParam);
1661
1662 case LM_GETITEM:
1663 return SYSLINK_GetItem(infoPtr, (PLITEM)lParam);
1664
1665 case LM_GETIDEALHEIGHT:
1666 if (lParam)
1667 return SYSLINK_GetIdealSize(infoPtr, (int)wParam, (SIZE *)lParam);
1668 else
1669 return SYSLINK_GetIdealHeight(infoPtr);
1670
1671 case WM_SETFOCUS:
1672 return SYSLINK_SetFocus(infoPtr);
1673
1674 case WM_KILLFOCUS:
1675 return SYSLINK_KillFocus(infoPtr);
1676
1677 case WM_ENABLE:
1678 infoPtr->Style &= ~WS_DISABLED;
1679 infoPtr->Style |= (wParam ? 0 : WS_DISABLED);
1680 InvalidateRect (infoPtr->Self, NULL, FALSE);
1681 return 0;
1682
1683 case WM_STYLECHANGED:
1684 if (wParam == GWL_STYLE)
1685 {
1686 infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew;
1687
1688 InvalidateRect(infoPtr->Self, NULL, TRUE);
1689 }
1690 return 0;
1691
1692 case WM_CREATE:
1693 {
1695
1696 /* allocate memory for info struct */
1697 infoPtr = Alloc (sizeof(SYSLINK_INFO));
1698 if (!infoPtr) return -1;
1699 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
1700
1701 /* initialize the info struct */
1702 infoPtr->Self = hwnd;
1703 infoPtr->Notify = cs->hwndParent;
1704 infoPtr->Style = cs->style;
1705 infoPtr->Font = 0;
1706 infoPtr->LinkFont = 0;
1707 list_init(&infoPtr->Items);
1708 infoPtr->HasFocus = FALSE;
1709 infoPtr->MouseDownID = -1;
1710 infoPtr->TextColor = comctl32_color.clrWindowText;
1711 infoPtr->LinkColor = comctl32_color.clrHighlight;
1712 infoPtr->VisitedColor = comctl32_color.clrHighlight;
1713 infoPtr->BreakChar = ' ';
1714 infoPtr->IgnoreReturn = infoPtr->Style & LWS_IGNORERETURN;
1715 TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd);
1716 SYSLINK_SetText(infoPtr, cs->lpszName);
1717 return 0;
1718 }
1719 case WM_DESTROY:
1720 TRACE("SysLink Ctrl destruction, hwnd=%p\n", hwnd);
1721 SYSLINK_ClearDoc(infoPtr);
1722 if(infoPtr->Font != 0) DeleteObject(infoPtr->Font);
1723 if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont);
1724 SetWindowLongPtrW(hwnd, 0, 0);
1725 Free (infoPtr);
1726 return 0;
1727
1728 case WM_SYSCOLORCHANGE:
1730 return 0;
1731
1732 default:
1734 {
1735 ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam );
1736 }
1738 }
1739}
1740
1741
1742/***********************************************************************
1743 * SYSLINK_Register [Internal]
1744 *
1745 * Registers the SysLink window class.
1746 */
1748{
1749 WNDCLASSW wndClass;
1750
1751 ZeroMemory (&wndClass, sizeof(wndClass));
1753 wndClass.lpfnWndProc = SysLinkWindowProc;
1754 wndClass.cbClsExtra = 0;
1755 wndClass.cbWndExtra = sizeof (SYSLINK_INFO *);
1756 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1757 wndClass.lpszClassName = WC_LINK;
1758
1759 RegisterClassW (&wndClass);
1760}
1761
1762
1763/***********************************************************************
1764 * SYSLINK_Unregister [Internal]
1765 *
1766 * Unregisters the SysLink window class.
1767 */
1769{
1771}
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
HFONT hFont
Definition: main.c:53
#define ARRAY_SIZE(A)
Definition: main.h:20
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_init(struct list_entry *head)
Definition: list.h:51
#define ERR(fmt,...)
Definition: precomp.h:57
PVOID ReAlloc(IN DWORD dwFlags, IN PVOID lpMem, IN SIZE_T dwBytes)
Definition: main.c:76
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
Definition: list.h:37
WPARAM wParam
Definition: combotst.c:138
char * Text
Definition: combotst.c:136
LPARAM lParam
Definition: combotst.c:139
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1755
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1593
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define wcsnicmp
Definition: compat.h:14
#define lstrcpyW
Definition: compat.h:749
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define pt(x, y)
Definition: drawing.c:79
#define WM_APP
Definition: eventvwr.h:73
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
pKey DeleteObject()
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLdouble n
Definition: glext.h:7729
GLenum mode
Definition: glext.h:6217
GLuint id
Definition: glext.h:5910
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static const struct newhuff ht[]
Definition: huffman.h:296
#define cs
Definition: i386-dis.c:442
uint32_t entry
Definition: isohybrid.c:63
#define debugstr_w
Definition: kernel32.h:32
struct task_struct * current
Definition: linux.c:32
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
#define shift
Definition: input.c:1755
WORD vk
Definition: input.c:77
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define LOWORD(l)
Definition: pedump.c:82
long LONG
Definition: pedump.c:60
#define WS_DISABLED
Definition: pedump.c:621
#define LIS_VISITED
Definition: commctrl.h:4754
#define LWS_TRANSPARENT
Definition: commctrl.h:4744
#define L_MAX_URL_LENGTH
Definition: commctrl.h:4740
#define LM_GETIDEALHEIGHT
Definition: commctrl.h:4776
#define LM_SETITEM
Definition: commctrl.h:4778
#define NM_CLICK
Definition: commctrl.h:130
#define WC_LINK
Definition: commctrl.h:4742
#define LM_HITTEST
Definition: commctrl.h:4775
#define LIS_FOCUSED
Definition: commctrl.h:4752
#define LIF_ITEMID
Definition: commctrl.h:4749
#define NM_RETURN
Definition: commctrl.h:132
#define LIF_URL
Definition: commctrl.h:4750
#define LIF_STATE
Definition: commctrl.h:4748
#define LM_GETITEM
Definition: commctrl.h:4779
#define LIF_ITEMINDEX
Definition: commctrl.h:4747
#define LIS_ENABLED
Definition: commctrl.h:4753
#define MAX_LINKID_TEXT
Definition: commctrl.h:4739
#define LWS_IGNORERETURN
Definition: commctrl.h:4745
#define WM_PRINTCLIENT
Definition: richedit.h:70
#define WM_NOTIFY
Definition: richedit.h:61
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define LIST_FOR_EACH_ENTRY_REV(elem, list, type, field)
Definition: list.h:222
__WINE_SERVER_LIST_INLINE void list_add_after(struct list *elem, struct list *to_add)
Definition: list.h:78
__WINE_SERVER_LIST_INLINE struct list * list_tail(const struct list *list)
Definition: list.h:137
#define TRACE(s)
Definition: solgame.cpp:4
& rect
Definition: startmenu.cpp:1413
COLORREF clrWindow
Definition: comctl32.h:182
COLORREF clrWindowText
Definition: comctl32.h:183
COLORREF clrHighlight
Definition: comctl32.h:175
int nChars
Definition: syslink.c:37
BYTE lfUnderline
Definition: dimm.idl:65
WCHAR * szUrl
Definition: syslink.c:63
union _DOC_ITEM::@337 u
struct _DOC_ITEM::@337::@338 Link
SL_ITEM_TYPE Type
Definition: syslink.c:55
struct list entry
Definition: syslink.c:53
struct _DOC_ITEM::@337::@339 Text
PDOC_TEXTBLOCK Blocks
Definition: syslink.c:56
UINT state
Definition: syslink.c:61
WCHAR * szID
Definition: syslink.c:62
UINT Dummy
Definition: syslink.c:67
UINT nText
Definition: syslink.c:54
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
LPCWSTR lpszClassName
Definition: winuser.h:3188
int cbClsExtra
Definition: winuser.h:3181
UINT style
Definition: winuser.h:3179
WNDPROC lpfnWndProc
Definition: winuser.h:3180
int cbWndExtra
Definition: winuser.h:3182
HCURSOR hCursor
Definition: winuser.h:3185
Definition: inflate.c:139
Definition: tftpd.h:60
WCHAR szUrl[L_MAX_URL_LENGTH]
Definition: commctrl.h:4762
UINT mask
Definition: commctrl.h:4757
UINT stateMask
Definition: commctrl.h:4760
WCHAR szID[MAX_LINKID_TEXT]
Definition: commctrl.h:4761
int iLink
Definition: commctrl.h:4758
UINT state
Definition: commctrl.h:4759
UINT_PTR idFrom
Definition: winuser.h:3161
UINT code
Definition: winuser.h:3162
HWND hwndFrom
Definition: winuser.h:3160
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
Definition: time.h:68
#define max(a, b)
Definition: svc.c:63
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t DWORD_PTR
Definition: typedefs.h:65
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
int32_t INT
Definition: typedefs.h:58
#define HIWORD(l)
Definition: typedefs.h:247
#define MAXLONG
Definition: umtypes.h:116
static int Link(const char **args)
Definition: vfdcmd.c:2414
_In_ WDFCOLLECTION _In_ WDFOBJECT Item
#define ZeroMemory
Definition: winbase.h:1736
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
DWORD COLORREF
Definition: windef.h:300
#define WINAPI
Definition: msvc.h:6
int WINAPI GetBkMode(_In_ HDC)
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
int WINAPI GetClipBox(_In_ HDC, _Out_ LPRECT)
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:999
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
#define TRANSPARENT
Definition: wingdi.h:950
#define ETO_CLIPPED
Definition: wingdi.h:648
BOOL WINAPI ExtTextOutW(_In_ HDC hdc, _In_ int x, _In_ int y, _In_ UINT options, _In_opt_ const RECT *lprect, _In_reads_opt_(c) LPCWSTR lpString, _In_ UINT c, _In_reads_opt_(c) const INT *lpDx)
#define ETO_OPAQUE
Definition: wingdi.h:647
#define OPAQUE
Definition: wingdi.h:949
BOOL WINAPI GetTextExtentExPointW(_In_ HDC hdc, _In_reads_(cchString) LPCWSTR lpszString, _In_ int cchString, _In_ int nMaxExtent, _Out_opt_ LPINT lpnFit, _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx, _Out_ LPSIZE lpSize)
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1056
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:918
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
#define WM_PAINT
Definition: winuser.h:1623
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define WM_ERASEBKGND
Definition: winuser.h:1628
#define CS_VREDRAW
Definition: winuser.h:658
#define WM_CTLCOLORSTATIC
Definition: winuser.h:1775
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define GetWindowLongPtrW
Definition: winuser.h:4832
#define VK_TAB
Definition: winuser.h:2202
#define WM_ENABLE
Definition: winuser.h:1618
DWORD WINAPI GetMessagePos(void)
Definition: message.c:1351
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_CREATE
Definition: winuser.h:1611
#define DLGC_WANTCHARS
Definition: winuser.h:2621
#define DLGC_WANTTAB
Definition: winuser.h:2614
#define WM_SIZE
Definition: winuser.h:1614
#define CS_HREDRAW
Definition: winuser.h:653
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define IDC_ARROW
Definition: winuser.h:687
#define WM_NCHITTEST
Definition: winuser.h:1689
#define WM_SETFOCUS
Definition: winuser.h:1616
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define RDW_UPDATENOW
Definition: winuser.h:1223
#define WM_LBUTTONDOWN
Definition: winuser.h:1779
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1629
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2157
#define WM_GETFONT
Definition: winuser.h:1654
struct tagSTYLESTRUCT * LPSTYLESTRUCT
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
#define WM_SETTEXT
Definition: winuser.h:1620
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
#define VK_RETURN
Definition: winuser.h:2204
HWND WINAPI SetFocus(_In_opt_ HWND)
#define WM_SETFONT
Definition: winuser.h:1653
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define HTCLIENT
Definition: winuser.h:2478
HDC WINAPI GetDC(_In_opt_ HWND)
#define HTNOWHERE
Definition: winuser.h:2477
#define WM_LBUTTONUP
Definition: winuser.h:1780
#define CS_GLOBALCLASS
Definition: winuser.h:652
#define HTTRANSPARENT
Definition: winuser.h:2476
#define GWLP_ID
Definition: winuser.h:863
#define WM_SETCURSOR
Definition: winuser.h:1639
#define WM_USER
Definition: winuser.h:1898
#define VK_SHIFT
Definition: winuser.h:2205
#define IDC_HAND
Definition: winuser.h:698
#define DLGC_WANTMESSAGE
Definition: winuser.h:2616
#define WM_DESTROY
Definition: winuser.h:1612
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
#define WM_KEYDOWN
Definition: winuser.h:1718
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
#define SetWindowLongPtrW
Definition: winuser.h:5358
#define GWL_STYLE
Definition: winuser.h:855
#define DLGC_HASSETSEL
Definition: winuser.h:2617
#define WM_KILLFOCUS
Definition: winuser.h:1617
#define RDW_INVALIDATE
Definition: winuser.h:1217
#define WM_GETDLGCODE
Definition: winuser.h:1692
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
SHORT WINAPI GetKeyState(_In_ int)
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:815
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185