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