fixed hashtable crash bug with WMStringHashCallbacks
[wmaker-crm.git] / WINGs / wfontpanel.c
blob69c83b815fd7203fc2ff6f0918eb52f973bc3755
5 #include "WINGsP.h"
6 #include "WUtil.h"
8 #include <strings.h>
11 typedef struct W_FontPanel {
12 WMWindow *win;
14 WMFrame *upperF;
15 WMLabel *sampleL;
17 WMSplitView *split;
19 WMFrame *lowerF;
20 WMLabel *famL;
21 WMList *famLs;
22 WMLabel *typL;
23 WMList *typLs;
24 WMLabel *sizL;
25 WMTextField *sizT;
26 WMList *sizLs;
28 WMFrame *xlfdF;
29 WMTextField *xlfdT;
31 WMFrame *encF;
32 WMPopUpButton *encP;
34 WMButton *revertB;
35 WMButton *previewB;
36 WMButton *setB;
38 proplist_t fdb;
39 } FontPanel;
42 #define MIN_UPPER_HEIGHT 20
43 #define MIN_LOWER_HEIGHT 140
46 #define MAX_FONTS_TO_RETRIEVE 2000
49 #define MIN_WIDTH 250
50 #define MIN_HEIGHT MIN_UPPER_HEIGHT+MIN_LOWER_HEIGHT+70
53 static char *scalableFontSizes[] = {
54 "8",
55 "10",
56 "11",
57 "12",
58 "14",
59 "16",
60 "18",
61 "20",
62 "24",
63 "36",
64 "48",
65 "64"
67 */
72 static void arrangeLowerFrame(FontPanel *panel);
74 static void familyClick(WMWidget *, void *);
75 static void typefaceClick(WMWidget *, void *);
76 static void sizeClick(WMWidget *, void *);
79 static void listFamilies(WMScreen *scr, WMFontPanel *panel);
81 static void
82 splitViewConstrainCallback(WMSplitView *sPtr, int divIndex, int *min, int *max)
84 *min = MIN_UPPER_HEIGHT;
85 *max = WMWidgetHeight(sPtr)-WMGetSplitViewDividerThickness(sPtr)-MIN_LOWER_HEIGHT;
89 static void
90 notificationObserver(void *self, WMNotification *notif)
92 WMFontPanel *panel = (WMFontPanel*)self;
93 void *object = WMGetNotificationObject(notif);
95 if (WMGetNotificationName(notif) == WMViewSizeDidChangeNotification) {
96 if (object == WMWidgetView(panel->win)) {
97 int h = WMWidgetHeight(panel->win);
98 int w = WMWidgetWidth(panel->win);
100 WMResizeWidget(panel->split, w, h-40);
102 WMMoveWidget(panel->setB, w-80, h-35);
103 WMMoveWidget(panel->previewB, w-160, h-35);
104 WMMoveWidget(panel->revertB, w-240, h-35);
105 } else if (object == WMWidgetView(panel->upperF)) {
106 WMResizeWidget(panel->sampleL, WMWidgetWidth(panel->upperF)-20,
107 WMWidgetHeight(panel->upperF)-10);
108 } else if (object == WMWidgetView(panel->lowerF)) {
110 if (WMWidgetHeight(panel->lowerF) < MIN_LOWER_HEIGHT) {
111 int h;
113 h = WMWidgetHeight(panel->split)-MIN_LOWER_HEIGHT
114 - WMGetSplitViewDividerThickness(panel->split);
116 WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), h);
118 WMMoveWidget(panel->lowerF, 0, WMWidgetHeight(panel->upperF)
119 + WMGetSplitViewDividerThickness(panel->split));
120 WMResizeWidget(panel->lowerF, WMWidgetWidth(panel->lowerF),
121 MIN_LOWER_HEIGHT);
122 } else {
123 arrangeLowerFrame(panel);
131 static void
132 familyClick(WMWidget *w, void *data)
134 WMList *lPtr = (WMList*)w;
135 FontPanel *panel = (FontPanel*)data;
142 WMFontPanel*
143 WMGetFontPanel(WMScreen *scr)
145 FontPanel *panel;
146 WMColor *dark, *white;
147 WMFont *font;
148 int divThickness;
150 if (scr->sharedFontPanel)
151 return scr->sharedFontPanel;
154 panel = wmalloc(sizeof(FontPanel));
155 memset(panel, 0, sizeof(FontPanel));
157 panel->win = WMCreateWindow(scr, "fontPanel");
158 WMResizeWidget(panel->win, 320, 370);
159 WMSetWindowMinSize(panel->win, MIN_WIDTH, MIN_HEIGHT);
160 WMSetViewNotifySizeChanges(WMWidgetView(panel->win), True);
162 panel->split = WMCreateSplitView(panel->win);
163 WMResizeWidget(panel->split, 320, 330);
164 WMSetSplitViewConstrainProc(panel->split, splitViewConstrainCallback);
166 divThickness = WMGetSplitViewDividerThickness(panel->split);
168 panel->upperF = WMCreateFrame(panel->win);
169 WMSetFrameRelief(panel->upperF, WRFlat);
170 WMSetViewNotifySizeChanges(WMWidgetView(panel->upperF), True);
171 panel->lowerF = WMCreateFrame(panel->win);
172 WMSetFrameRelief(panel->lowerF, WRFlat);
173 WMSetViewNotifySizeChanges(WMWidgetView(panel->lowerF), True);
175 WMAddSplitViewSubview(panel->split, W_VIEW(panel->upperF));
176 WMAddSplitViewSubview(panel->split, W_VIEW(panel->lowerF));
178 WMResizeWidget(panel->upperF, 320, 60);
179 WMResizeWidget(panel->lowerF, 320, 330-60-divThickness);
180 WMMoveWidget(panel->lowerF, 0, 60+divThickness);
182 white = WMWhiteColor(scr);
183 dark = WMDarkGrayColor(scr);
185 panel->sampleL = WMCreateLabel(panel->upperF);
186 WMResizeWidget(panel->sampleL, 300, 50);
187 WMMoveWidget(panel->sampleL, 10, 10);
188 WMSetWidgetBackgroundColor(panel->sampleL, white);
189 WMSetLabelRelief(panel->sampleL, WRSunken);
190 WMSetLabelText(panel->sampleL, "It is not yet completed!!!");
192 font = WMBoldSystemFontOfSize(scr, 12);
194 panel->famL = WMCreateLabel(panel->lowerF);
195 WMSetWidgetBackgroundColor(panel->famL, dark);
196 WMSetLabelText(panel->famL, "Family");
197 WMSetLabelFont(panel->famL, font);
198 WMSetLabelTextColor(panel->famL, white);
199 WMSetLabelRelief(panel->famL, WRSunken);
200 WMSetLabelTextAlignment(panel->famL, WACenter);
202 panel->famLs = WMCreateList(panel->lowerF);
203 WMSetListAction(panel->famLs, familyClick, panel);
205 panel->typL = WMCreateLabel(panel->lowerF);
206 WMSetWidgetBackgroundColor(panel->typL, dark);
207 WMSetLabelText(panel->typL, "Typeface");
208 WMSetLabelFont(panel->typL, font);
209 WMSetLabelTextColor(panel->typL, white);
210 WMSetLabelRelief(panel->typL, WRSunken);
211 WMSetLabelTextAlignment(panel->typL, WACenter);
213 panel->typLs = WMCreateList(panel->lowerF);
214 WMSetListAction(panel->typLs, typefaceClick, panel);
216 panel->sizL = WMCreateLabel(panel->lowerF);
217 WMSetWidgetBackgroundColor(panel->sizL, dark);
218 WMSetLabelText(panel->sizL, "Size");
219 WMSetLabelFont(panel->sizL, font);
220 WMSetLabelTextColor(panel->sizL, white);
221 WMSetLabelRelief(panel->sizL, WRSunken);
222 WMSetLabelTextAlignment(panel->sizL, WACenter);
224 panel->sizT = WMCreateTextField(panel->lowerF);
226 panel->sizLs = WMCreateList(panel->lowerF);
227 WMSetListAction(panel->sizLs, sizeClick, panel);
229 WMReleaseFont(font);
230 WMReleaseColor(white);
231 WMReleaseColor(dark);
233 panel->encF = WMCreateFrame(panel->lowerF);
234 WMSetFrameTitle(panel->encF, "Encoding");
235 WMResizeWidget(panel->encF, 130, 50);
237 panel->encP = WMCreatePopUpButton(panel->encF);
238 WMMoveWidget(panel->encP, 10, 20);
239 WMResizeWidget(panel->encP, 112, 20);
241 WMMapSubwidgets(panel->encF);
243 panel->xlfdF = WMCreateFrame(panel->lowerF);
244 WMSetFrameTitle(panel->xlfdF, "Xtra Long Font Description");
246 panel->xlfdT = WMCreateTextField(panel->xlfdF);
247 WMMoveWidget(panel->xlfdT, 10, 20);
249 WMMapSubwidgets(panel->xlfdF);
251 arrangeLowerFrame(panel);
253 panel->setB = WMCreateCommandButton(panel->win);
254 WMResizeWidget(panel->setB, 70, 24);
255 WMMoveWidget(panel->setB, 240, 335);
256 WMSetButtonText(panel->setB, "Set");
258 panel->previewB = WMCreateCommandButton(panel->win);
259 WMResizeWidget(panel->previewB, 70, 24);
260 WMMoveWidget(panel->previewB, 160, 335);
261 WMSetButtonText(panel->previewB, "Preview");
263 panel->revertB = WMCreateCommandButton(panel->win);
264 WMResizeWidget(panel->revertB, 70, 24);
265 WMMoveWidget(panel->revertB, 80, 335);
266 WMSetButtonText(panel->revertB, "Revert");
268 WMRealizeWidget(panel->win);
270 WMMapSubwidgets(panel->upperF);
271 WMMapSubwidgets(panel->lowerF);
272 WMMapSubwidgets(panel->split);
273 WMMapSubwidgets(panel->win);
275 scr->sharedFontPanel = panel;
278 /* register notification observers */
279 WMAddNotificationObserver(notificationObserver, panel,
280 WMViewSizeDidChangeNotification,
281 WMWidgetView(panel->win));
282 WMAddNotificationObserver(notificationObserver, panel,
283 WMViewSizeDidChangeNotification,
284 WMWidgetView(panel->upperF));
285 WMAddNotificationObserver(notificationObserver, panel,
286 WMViewSizeDidChangeNotification,
287 WMWidgetView(panel->lowerF));
290 listFamilies(scr, panel);
293 return panel;
297 void
298 WMFreeFontPanel(WMFontPanel *panel)
300 if (panel == WMWidgetScreen(panel->win)->sharedFontPanel) {
301 WMWidgetScreen(panel->win)->sharedFontPanel = NULL;
303 WMRemoveNotificationObserver(panel);
304 WMUnmapWidget(panel->win);
305 WMDestroyWidget(panel->win);
306 free(panel);
310 void
311 WMShowFontPanel(WMFontPanel *panel)
313 WMMapWidget(panel->win);
317 void
318 WMHideFontPanel(WMFontPanel *panel)
320 WMUnmapWidget(panel->win);
324 void
325 WMSetFontPanelFont(WMFontPanel *panel, WMFont *font)
330 WMFont*
331 WMGetFontPanelFont(WMFontPanel *panel)
333 return NULL;
337 char*
338 WMGetFontPanelFontName(WMFontPanel *panel)
340 return NULL;
346 static void
347 arrangeLowerFrame(FontPanel *panel)
349 int width = WMWidgetWidth(panel->lowerF) - 55 - 30;
350 int height = WMWidgetHeight(panel->lowerF);
351 int oheight = 330-60-WMGetSplitViewDividerThickness(panel->split);
352 int fw, tw, sw;
353 int h;
355 height -= 20 + 3 + 10 + 50;
356 oheight -= 20 + 3 + 10 + 50;
358 fw = (125*width) / 235;
359 tw = (110*width) / 235;
360 sw = 55;
362 h = (174*height) / oheight;
364 WMMoveWidget(panel->famL, 10, 0);
365 WMResizeWidget(panel->famL, fw, 20);
367 WMMoveWidget(panel->famLs, 10, 23);
368 WMResizeWidget(panel->famLs, fw, h);
370 WMMoveWidget(panel->typL, 10+fw+3, 0);
371 WMResizeWidget(panel->typL, tw, 20);
373 WMMoveWidget(panel->typLs, 10+fw+3, 23);
374 WMResizeWidget(panel->typLs, tw, h);
376 WMMoveWidget(panel->sizL, 10+fw+3+tw+3, 0);
377 WMResizeWidget(panel->sizL, sw+4, 20);
379 WMMoveWidget(panel->sizT, 10+fw+3+tw+3, 23);
380 WMResizeWidget(panel->sizT, sw+4, 20);
382 WMMoveWidget(panel->sizLs, 10+fw+3+tw+3, 46);
383 WMResizeWidget(panel->sizLs, sw+4, h-22);
385 WMMoveWidget(panel->encF, 10, WMWidgetHeight(panel->lowerF)-55);
387 WMMoveWidget(panel->xlfdF, 145, WMWidgetHeight(panel->lowerF)-55);
388 WMResizeWidget(panel->xlfdF, WMWidgetWidth(panel->lowerF)-155, 50);
390 WMResizeWidget(panel->xlfdT, WMWidgetWidth(panel->lowerF)-155-20, 20);
396 #define ALL_FONTS_MASK "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
398 #define FOUNDRY 0
399 #define FAMILY 1
400 #define WEIGHT 2
401 #define SLANT 3
402 #define SETWIDTH 4
403 #define ADD_STYLE 5
404 #define PIXEL_SIZE 6
405 #define POINT_SIZE 7
406 #define RES_X 8
407 #define RES_Y 9
408 #define SPACING 10
409 #define AV_WIDTH 11
410 #define REGISTRY 12
411 #define ENCODING 13
413 #define NUM_FIELDS 14
416 #if 1
418 static Bool
419 parseFont(char *font, char values[NUM_FIELDS][256])
421 char *ptr;
422 int part;
423 char buffer[256], *bptr;
425 part = FOUNDRY;
426 ptr = font;
427 ptr++; /* skip first - */
428 bptr = buffer;
429 while (*ptr) {
430 if (*ptr == '-') {
431 *bptr = 0;
432 strcpy(values[part], buffer);
433 bptr = buffer;
434 part++;
435 } else {
436 *bptr++ = *ptr;
438 ptr++;
440 *bptr = 0;
441 strcpy(values[part], buffer);
443 return True;
448 static int
449 isXLFD(char *font, int *length_ret)
451 int c = 0;
453 *length_ret = 0;
454 while (*font) {
455 (*length_ret)++;
456 if (*font++ == '-')
457 c++;
460 return c==NUM_FIELDS;
466 typedef struct {
467 char *weight;
468 char *slant;
470 char *setWidth;
471 char *addStyle;
473 char showSetWidth; /* when duplicated */
474 char showAddStyle; /* when duplicated */
476 WMBag *sizes;
477 } Typeface;
480 typedef struct {
481 char *name;
483 char *foundry;
484 char *registry, *encoding;
486 char showFoundry; /* when duplicated */
487 char showRegistry; /* when duplicated */
489 WMBag *typefaces;
490 } Family;
494 static void
495 addTypefaceToFamily(Family *family, char fontFields[NUM_FIELDS][256])
497 Typeface *face;
498 int i;
500 if (family->typefaces) {
501 for (i = 0; i < WMGetBagItemCount(family->typefaces); i++) {
502 int size;
504 face = WMGetFromBag(family->typefaces, i);
506 if (strcmp(face->weight, fontFields[WEIGHT]) != 0) {
507 continue;
509 if (strcmp(face->slant, fontFields[SLANT]) != 0) {
510 continue;
513 size = atoi(fontFields[POINT_SIZE]);
514 WMPutInBag(face->sizes, (void*)size);
516 return;
518 } else {
519 family->typefaces = WMCreateBag(4);
522 face = wmalloc(sizeof(Typeface));
523 memset(face, 0, sizeof(Typeface));
525 face->weight = wstrdup(fontFields[WEIGHT]);
526 face->slant = wstrdup(fontFields[SLANT]);
527 face->setWidth = wstrdup(fontFields[SETWIDTH]);
528 face->addStyle = wstrdup(fontFields[ADD_STYLE]);
530 face->sizes = WMCreateBag(4);
531 WMPutInBag(face->sizes, (void*)atoi(fontFields[POINT_SIZE]));
533 WMPutInBag(family->typefaces, face);
539 * families (same family name) (Hashtable of family -> bag)
540 * registries (same family but different registries)
544 static void
545 addFontToFamily(WMHashTable *families, char fontFields[NUM_FIELDS][256])
547 int i;
548 Family *fam;
549 WMBag *family;
551 family = WMHashGet(families, fontFields[FAMILY]);
553 if (family) {
554 /* look for same encoding/registry and foundry */
555 for (i = 0; i < WMGetBagItemCount(family); i++) {
556 int enc, reg, found;
558 fam = WMGetFromBag(family, i);
560 enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0);
561 reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0);
562 found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0);
564 if (enc && reg && found) {
565 addTypefaceToFamily(fam, fontFields);
566 return;
569 /* look for same encoding/registry */
570 for (i = 0; i < WMGetBagItemCount(family); i++) {
571 int enc, reg;
573 fam = WMGetFromBag(family, i);
575 enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0);
576 reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0);
578 if (enc && reg) {
579 /* has the same encoding, but the foundry is different */
580 fam->showRegistry = 1;
582 fam = wmalloc(sizeof(Family));
583 memset(fam, 0, sizeof(Family));
585 fam->name = wstrdup(fontFields[FAMILY]);
586 fam->foundry = wstrdup(fontFields[FOUNDRY]);
587 fam->registry = wstrdup(fontFields[REGISTRY]);
588 fam->encoding = wstrdup(fontFields[ENCODING]);
589 fam->showRegistry = 1;
591 addTypefaceToFamily(fam, fontFields);
593 WMPutInBag(family, fam);
595 return;
598 /* look for same foundry */
599 for (i = 0; i < WMGetBagItemCount(family); i++) {
600 int found;
602 fam = WMGetFromBag(family, i);
604 found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0);
606 if (found) {
607 /* has the same foundry, but encoding is different */
608 fam->showFoundry = 1;
610 fam = wmalloc(sizeof(Family));
611 memset(fam, 0, sizeof(Family));
613 fam->name = wstrdup(fontFields[FAMILY]);
614 fam->foundry = wstrdup(fontFields[FOUNDRY]);
615 fam->registry = wstrdup(fontFields[REGISTRY]);
616 fam->encoding = wstrdup(fontFields[ENCODING]);
617 fam->showFoundry = 1;
619 addTypefaceToFamily(fam, fontFields);
621 WMPutInBag(family, fam);
623 return;
626 /* foundry and encoding do not match anything known */
627 fam = wmalloc(sizeof(Family));
628 memset(fam, 0, sizeof(Family));
630 fam->name = wstrdup(fontFields[FAMILY]);
631 fam->foundry = wstrdup(fontFields[FOUNDRY]);
632 fam->registry = wstrdup(fontFields[REGISTRY]);
633 fam->encoding = wstrdup(fontFields[ENCODING]);
634 fam->showFoundry = 1;
635 fam->showRegistry = 1;
637 addTypefaceToFamily(fam, fontFields);
639 WMPutInBag(family, fam);
641 return;
644 family = WMCreateBag(8);
646 fam = wmalloc(sizeof(Family));
647 memset(fam, 0, sizeof(Family));
649 fam->name = wstrdup(fontFields[FAMILY]);
650 fam->foundry = wstrdup(fontFields[FOUNDRY]);
651 fam->registry = wstrdup(fontFields[REGISTRY]);
652 fam->encoding = wstrdup(fontFields[ENCODING]);
654 addTypefaceToFamily(fam, fontFields);
656 WMPutInBag(family, fam);
658 WMHashInsert(families, fam->name, family);
663 static void
664 listFamilies(WMScreen *scr, WMFontPanel *panel)
666 char **fontList;
667 int count;
668 int i;
669 WMHashTable *families = WMCreateHashTable(WMStringHashCallbacks);
670 char fields[NUM_FIELDS][256];
671 WMHashEnumerator enumer;
672 WMBag *bag;
674 fontList = XListFonts(scr->display, ALL_FONTS_MASK, MAX_FONTS_TO_RETRIEVE,
675 &count);
676 if (!fontList) {
677 WMRunAlertPanel(scr, panel->win, "Error",
678 "Could not retrieve font list", "OK", NULL, NULL);
679 return;
682 for (i = 0; i < count; i++) {
683 int fname_len;
685 if (!isXLFD(fontList[i], &fname_len)) {
686 *fontList[i] = '\0';
687 continue;
689 if (fname_len > 255) {
690 wwarning("font name %s is longer than 256, which is invalid.",
691 fontList[i]);
692 *fontList[i] = '\0';
693 continue;
695 if (!parseFont(fontList[i], fields)) {
696 *fontList[i] = '\0';
697 continue;
699 addFontToFamily(families, fields);
702 enumer = WMEnumerateHashTable(families);
704 while ((bag = WMNextHashEnumeratorItem(&enumer))) {
705 int i;
706 Family *fam;
707 char buffer[256];
708 WMListItem *item;
710 for (i = 0; i < WMGetBagItemCount(bag); i++) {
711 fam = WMGetFromBag(bag, i);
713 strcpy(buffer, fam->name);
715 if (fam->showFoundry) {
716 strcat(buffer, " ");
717 strcat(buffer, fam->foundry);
718 strcat(buffer, " ");
720 if (fam->showRegistry) {
721 strcat(buffer, " (");
722 strcat(buffer, fam->registry);
723 strcat(buffer, "-");
724 strcat(buffer, fam->encoding);
725 strcat(buffer, ")");
727 item = WMAddSortedListItem(panel->famLs, buffer);
729 item->clientData = fam;
731 WMFreeBag(bag);
734 WMFreeHashTable(families);
739 static void
740 familyClick(WMWidget *w, void *data)
742 WMList *lPtr = (WMList*)w;
743 WMListItem *item;
744 Family *family;
745 FontPanel *panel = (FontPanel*)data;
746 Typeface *face;
747 int i;
749 item = WMGetListSelectedItem(lPtr);
750 family = (Family*)item->clientData;
752 WMClearList(panel->typLs);
755 for (i = 0; i < WMGetBagItemCount(family->typefaces); i++) {
756 char buffer[256];
758 face = WMGetFromBag(family->typefaces, i);
760 strcpy(buffer, face->weight);
761 strcat(buffer, " ");
762 strcat(buffer, face->slant);
764 WMAddListItem(panel->typLs, buffer);
770 static void
771 typefaceClick(WMWidget *w, void *data)
773 WMList *lPtr = (WMList*)w;
774 FontPanel *panel = (FontPanel*)data;
778 static void
779 sizeClick(WMWidget *w, void *data)
781 WMList *lPtr = (WMList*)w;
782 FontPanel *panel = (FontPanel*)data;
786 #endif