ReactOS  0.4.13-dev-66-gc714b7f
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 
36 typedef 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 
46 typedef enum
47 {
48  slText = 0,
50 } SL_ITEM_TYPE;
51 
52 typedef 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 */
65  } Link;
66  struct
67  {
69  } Text;
70  } u;
71  WCHAR Text[1]; /* Text of the document item */
73 
74 typedef 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 */
89 } SYSLINK_INFO;
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 {
125  PDOC_ITEM Item;
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 
155  LIST_FOR_EACH_ENTRY_SAFE(Item, Item2, &infoPtr->Items, DOC_ITEM, entry)
156  {
157  list_remove(&Item->entry);
158  SYSLINK_FreeDocItem(Item);
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 
212 CheckParameter:
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  */
456 static VOID SYSLINK_RepaintLink (const SYSLINK_INFO *infoPtr, const DOC_ITEM *DocItem)
457 {
458  PDOC_TEXTBLOCK bl;
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  */
485 static 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  */
501 static 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  */
527 static 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  */
545 static 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  */
564 static 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  */
594 static 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;
601  TEXTMETRICW tm;
602 
603  szDoc.cx = szDoc.cy = 0;
604 
605  rc = *pRect;
606  rc.right -= SL_RIGHTMARGIN;
607  rc.bottom -= SL_BOTTOMMARGIN;
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 
616  x = SL_LEFTMARGIN;
617  y = SL_TOPMARGIN;
618  GetTextMetricsW( hdc, &tm );
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 */
685  x = SL_LEFTMARGIN;
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  {
727  x = SL_LEFTMARGIN;
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  */
767 static 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;
804  PDOC_TEXTBLOCK bl;
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);
844  SetBkMode(hdc, mode);
845  return 0;
846 }
847 
848 
849 /***********************************************************************
850  * SYSLINK_Paint
851  * Handles the WM_PAINT message.
852  */
853 static 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  */
871 static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
872 {
873  HDC hdc;
874  LOGFONTW lf;
875  TEXTMETRICW tm;
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  */
961 static 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  */
992 static 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  */
1082 static LRESULT SYSLINK_GetItem (const SYSLINK_INFO *infoPtr, PLITEM Item)
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  */
1140 static 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  */
1168 static 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  {
1217  LRESULT height;
1218  TEXTMETRICW tm;
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  */
1241 static 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  */
1317 static 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  */
1369 static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, const POINT *pt)
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  */
1392 static 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  */
1413 static BOOL SYSKEY_SelectNextPrevLink (const SYSLINK_INFO *infoPtr, BOOL Prev)
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  */
1451 static 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  */
1468 static 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  {
1529  LHITTESTINFO ht;
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;
1595  SYSKEY_SelectNextPrevLink(infoPtr, shift);
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));
1747  wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
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 }
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 WS_DISABLED
Definition: pedump.c:621
UINT nText
Definition: syslink.c:55
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1608
#define max(a, b)
Definition: svc.c:63
Definition: tftpd.h:59
#define HTTRANSPARENT
Definition: winuser.h:2427
#define TRUE
Definition: types.h:120
#define DLGC_WANTCHARS
Definition: winuser.h:2572
#define shift
Definition: input.c:1668
#define DLGC_WANTMESSAGE
Definition: winuser.h:2567
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
#define WC_LINK
Definition: commctrl.h:4708
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
UINT style
Definition: winuser.h:3129
#define WM_GETDLGCODE
Definition: winuser.h:1671
#define WM_LBUTTONDOWN
Definition: winuser.h:1752
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define MAXLONG
Definition: umtypes.h:116
#define LIS_FOCUSED
Definition: commctrl.h:4718
HDC WINAPI GetDC(_In_opt_ HWND)
#define LIF_ITEMINDEX
Definition: commctrl.h:4713
#define pt(x, y)
Definition: drawing.c:79
uint16_t * PWSTR
Definition: typedefs.h:54
__WINE_SERVER_LIST_INLINE void list_add_after(struct list *elem, struct list *to_add)
Definition: list.h:78
UINT state
Definition: commctrl.h:4725
#define WM_CTLCOLORSTATIC
Definition: winuser.h:1748
uint8_t entry
Definition: isohybrid.c:63
union _DOC_ITEM::@321 u
#define LIF_STATE
Definition: commctrl.h:4714
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
static HDC
Definition: imagelist.c:92
#define MAX_LINKID_TEXT
Definition: commctrl.h:4705
int iLink
Definition: commctrl.h:4724
GLdouble n
Definition: glext.h:7729
LONG top
Definition: windef.h:292
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define ZeroMemory
Definition: winbase.h:1635
#define CS_HREDRAW
Definition: winuser.h:648
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
int cbClsExtra
Definition: winuser.h:3131
HWND WINAPI SetFocus(_In_opt_ HWND)
UINT Dummy
Definition: syslink.c:68
#define WM_NCHITTEST
Definition: winuser.h:1668
UINT_PTR WPARAM
Definition: windef.h:207
#define VK_TAB
Definition: winuser.h:2153
DWORD WINAPI GetMessagePos(void)
Definition: message.c:1350
#define GetWindowLongPtrW
Definition: winuser.h:4698
LONG left
Definition: windef.h:291
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define strncmpiW(s1, s2, n)
Definition: unicode.h:40
__WINE_SERVER_LIST_INLINE struct list * list_tail(const struct list *list)
Definition: list.h:137
#define DLGC_WANTTAB
Definition: winuser.h:2565
UINT stateMask
Definition: commctrl.h:4726
LONG right
Definition: windef.h:293
#define lstrlenW
Definition: compat.h:407
WCHAR * szID
Definition: syslink.c:63
#define HTNOWHERE
Definition: winuser.h:2428
int32_t INT
Definition: typedefs.h:56
#define VK_RETURN
Definition: winuser.h:2155
static int Link(const char **args)
Definition: vfdcmd.c:2414
#define DLGC_HASSETSEL
Definition: winuser.h:2568
& rect
Definition: startmenu.cpp:1413
WPARAM wParam
Definition: combotst.c:138
#define LM_HITTEST
Definition: commctrl.h:4741
HFONT hFont
Definition: main.c:53
#define WM_ENABLE
Definition: winuser.h:1597
#define WM_PRINTCLIENT
Definition: richedit.h:70
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define lstrcpynW
Definition: compat.h:397
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:656
UINT code
Definition: winuser.h:3112
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:975
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
COLORREF clrWindowText
Definition: comctl32.h:169
struct _DOC_ITEM::@321::@322 Link
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:93
#define LIF_URL
Definition: commctrl.h:4716
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1032
uint32_t cs
Definition: isohybrid.c:75
struct list entry
Definition: syslink.c:54
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
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)
#define ETO_OPAQUE
Definition: wingdi.h:646
int nChars
Definition: syslink.c:38
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define WM_SETCURSOR
Definition: winuser.h:1618
UINT state
Definition: syslink.c:62
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
UINT_PTR idFrom
Definition: winuser.h:3111
#define debugstr_w
Definition: kernel32.h:32
WNDPROC lpfnWndProc
Definition: winuser.h:3130
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define TRANSPARENT
Definition: wingdi.h:949
#define VK_SHIFT
Definition: winuser.h:2156
smooth NULL
Definition: ftsmooth.c:416
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
#define WM_GETFONT
Definition: winuser.h:1633
LONG cx
Definition: windef.h:319
#define WM_KEYDOWN
Definition: winuser.h:1691
LPCWSTR lpszClassName
Definition: winuser.h:3138
LONG_PTR LPARAM
Definition: windef.h:208
#define LWS_IGNORERETURN
Definition: commctrl.h:4711
WCHAR szUrl[L_MAX_URL_LENGTH]
Definition: commctrl.h:4728
#define ETO_CLIPPED
Definition: wingdi.h:647
#define WM_SETTEXT
Definition: winuser.h:1599
#define LIS_ENABLED
Definition: commctrl.h:4719
#define WM_DESTROY
Definition: winuser.h:1591
SHORT WINAPI GetKeyState(_In_ int)
#define CS_VREDRAW
Definition: winuser.h:653
struct tagSTYLESTRUCT * LPSTYLESTRUCT
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
#define IDC_HAND
Definition: winuser.h:693
#define TRACE(s)
Definition: solgame.cpp:4
#define WM_KILLFOCUS
Definition: winuser.h:1596
WCHAR * szUrl
Definition: syslink.c:64
PVOID ReAlloc(IN DWORD dwFlags, IN PVOID lpMem, IN SIZE_T dwBytes)
Definition: main.c:76
int cbWndExtra
Definition: winuser.h:3132
#define LM_GETIDEALHEIGHT
Definition: commctrl.h:4742
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define WM_SIZE
Definition: winuser.h:1593
int WINAPI GetBkMode(_In_ HDC)
DWORD COLORREF
Definition: windef.h:285
#define CS_GLOBALCLASS
Definition: winuser.h:647
#define WINAPI
Definition: msvc.h:8
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
unsigned long DWORD
Definition: ntddk_ex.h:95
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2074
int WINAPI GetClipBox(_In_ HDC, _Out_ LPRECT)
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
#define WM_PAINT
Definition: winuser.h:1602
#define OPAQUE
Definition: wingdi.h:948
HDC hdc
Definition: main.c:9
PDOC_TEXTBLOCK Blocks
Definition: syslink.c:57
Definition: _list.h:228
#define WM_APP
Definition: eventvwr.h:70
Definition: time.h:76
HWND hwndFrom
Definition: winuser.h:3110
uint32_t DWORD_PTR
Definition: typedefs.h:63
GLenum mode
Definition: glext.h:6217
#define NM_CLICK
Definition: commctrl.h:130
int code
Definition: i386-dis.c:3591
#define WM_USER
Definition: winuser.h:1856
#define LM_SETITEM
Definition: commctrl.h:4744
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
#define LIF_ITEMID
Definition: commctrl.h:4715
HCURSOR hCursor
Definition: winuser.h:3135
#define ERR(fmt,...)
Definition: debug.h:109
#define GWL_STYLE
Definition: winuser.h:846
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:884
#define NM_RETURN
Definition: commctrl.h:132
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
#define L_MAX_URL_LENGTH
Definition: commctrl.h:4706
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define lstrcpyW
Definition: compat.h:406
SL_ITEM_TYPE Type
Definition: syslink.c:56
HCURSOR WINAPI SetCursor(_In_opt_ HCURSOR)
#define ARRAY_SIZE(a)
Definition: main.h:24
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_LBUTTONUP
Definition: winuser.h:1753
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
static const struct newhuff ht[]
Definition: huffman.h:296
#define LM_GETITEM
Definition: commctrl.h:4745
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
COLORREF clrHighlight
Definition: comctl32.h:161
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
#define WM_SETFONT
Definition: winuser.h:1632
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
struct _DOC_ITEM::@321::@323 Text
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
#define RDW_UPDATENOW
Definition: winuser.h:1206
#define IDC_ARROW
Definition: winuser.h:682
#define LIST_FOR_EACH_ENTRY_REV(elem, list, type, field)
Definition: list.h:222
#define WM_CREATE
Definition: winuser.h:1590
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
#define HIWORD(l)
Definition: typedefs.h:246
GLenum GLuint id
Definition: glext.h:5579
#define LWS_TRANSPARENT
Definition: commctrl.h:4710
LONG bottom
Definition: windef.h:294
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1748
#define LIS_VISITED
Definition: commctrl.h:4720
WCHAR szID[MAX_LINKID_TEXT]
Definition: commctrl.h:4727
#define SetWindowLongPtrW
Definition: winuser.h:5215
#define WM_ERASEBKGND
Definition: winuser.h:1607
#define WM_SETFOCUS
Definition: winuser.h:1595
#define HTCLIENT
Definition: winuser.h:2429
WCHAR * LPWSTR
Definition: xmlstorage.h:184
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
LONG_PTR LRESULT
Definition: windef.h:209
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
UINT mask
Definition: commctrl.h:4723
COLORREF clrWindow
Definition: comctl32.h:168
BYTE lfUnderline
Definition: dimm.idl:65
LONG cy
Definition: windef.h:320
LPARAM lParam
Definition: combotst.c:139
#define LOWORD(l)
Definition: pedump.c:82
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1586
#define GWLP_ID
Definition: winuser.h:854
#define WM_NOTIFY
Definition: richedit.h:61
char * Text
Definition: combotst.c:136
#define RDW_INVALIDATE
Definition: winuser.h:1200
struct task_struct * current
Definition: linux.c:32
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31