/[james]/sargasso2/sargasso.c
ViewVC logotype

Annotation of /sargasso2/sargasso.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 79 - (hide annotations) (download) (as text)
Sat Sep 30 21:35:19 2006 UTC (18 years, 1 month ago) by james
File MIME type: text/x-csrc
File size: 32203 byte(s)
Make fonts configurable.

1 james 77 /*
2     * This file is part of Sargasso, http://zamez.org/sargasso
3     * Licensed under the GNU General Public License,
4     * http://www.opensource.org/licenses/gpl-license
5     * Copyright 2006 James Bursa <james@zamez.org>
6     */
7    
8     #include <assert.h>
9     #include <errno.h>
10     #include <stdio.h>
11     #include <string.h>
12     #include <sys/stat.h>
13     #include <oslib/colourtrans.h>
14     #include <oslib/osfile.h>
15     #include <oslib/uri.h>
16     #include <oslib/wimp.h>
17     #include <oslib/wimpspriteop.h>
18     #include <rufl.h>
19     #include "feed.h"
20     #include "netsurf/utils/log.h"
21    
22    
23     #define MAX_LINES 20
24     #define MARGIN 10
25     #define FEEDS_READ "Choices:Sargasso.Feeds"
26     #define FEEDS_WRITE "<Choices$Write>.Sargasso.Feeds"
27     #define CHOICES_READ "Choices:Sargasso.Choices"
28     #define CHOICES_WRITE "<Choices$Write>.Sargasso.Choices"
29    
30     typedef void (*click_callback)(unsigned int i);
31    
32     struct paragraph {
33     int x0, y0, x1, y1;
34     int background, colour;
35     const char *font_family;
36     rufl_style font_style;
37     unsigned int font_size;
38     click_callback click;
39     unsigned int click_i;
40     unsigned int lines;
41     const char *text[MAX_LINES + 1];
42     struct paragraph *next;
43     };
44    
45     bool quit = false;
46     int interval = 30 * 60;
47     os_t last_update = 0;
48    
49     wimp_t task;
50     wimp_w info_window, main_window, feed_window, add_feed_window,
51     warning_window = 0, choices_window;
52     osspriteop_area *sprites;
53     struct paragraph *main_window_paragraphs = 0;
54     struct paragraph *feed_window_paragraphs = 0;
55     unsigned int current_feed = 0;
56 james 79 char font_headings[100] = "Homerton";
57     char font_summaries[100] = "NewHall";
58     char font_links[100] = "Homerton";
59 james 77
60     #define ICON_FLAGS (wimp_ICON_TEXT | \
61     (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT))
62     wimp_MENU(4) iconbar_menu = { { "Sargasso" }, wimp_COLOUR_BLACK,
63     wimp_COLOUR_LIGHT_GREY, wimp_COLOUR_BLACK, wimp_COLOUR_WHITE,
64     200, 44, 0,
65     { { 0, 0, ICON_FLAGS, { "Info" } },
66     { 0, 0, ICON_FLAGS, { "Choices..." } },
67     { 0, 0, ICON_FLAGS, { "Update feeds" } },
68     { wimp_MENU_LAST, 0, ICON_FLAGS, { "Quit" } } } };
69     wimp_MENU(2) main_menu = { { "Sargasso" }, wimp_COLOUR_BLACK,
70     wimp_COLOUR_LIGHT_GREY, wimp_COLOUR_BLACK, wimp_COLOUR_WHITE,
71     200, 44, 0,
72     { { 0, 0, ICON_FLAGS, { "Add feed..." } },
73     { wimp_MENU_LAST, 0, ICON_FLAGS, { "Remove feed" } } } };
74     wimp_menu *current_menu;
75     unsigned int current_removing = 0;
76 james 79 wimp_i current_font_menu;
77 james 77
78     const char *default_feeds[] = {
79     "http://news.google.co.uk/?output=rss",
80     "http://www.ft.com/rss/home/uk",
81     "http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml",
82     "http://rss.cnn.com/rss/edition.rss",
83     "http://feeds.chicagotribune.com/chicagotribune/news/",
84     "http://www.drobe.co.uk/rss.php",
85     "http://www.theregister.co.uk/feeds/latest.rdf",
86     "http://www.snackspot.org.uk/rss/rss.xml",
87     "http://www.mode7games.com/blog/?feed=rss2",
88     "http://cia.navi.cx/stats/project/NetSurf/.rss",
89     };
90    
91     void gui_init(void);
92     void gui_quit(void);
93     wimp_w create_window(const char *name);
94     void gui_poll(void);
95     void mouse_click(wimp_w w, wimp_i i, int x, int y,
96     wimp_mouse_state buttons);
97     void set_pointer(const char *name, int x, int y);
98     void reset_pointer(void);
99     void key_pressed(wimp_key *key);
100     void menu_selection(wimp_selection *selection);
101     void open_window(wimp_w w);
102     void close_window(wimp_w w);
103     void open_menu(wimp_menu *menu, int x, int y);
104     void update_main_window(void);
105     void set_extent(wimp_w w, int y);
106     void click_main_window(unsigned int i);
107     void update_feed_window(unsigned int i);
108     void click_feed_link(unsigned int i);
109     void click_item_link(unsigned int j);
110     struct paragraph *add_paragraph(struct paragraph **paragraph_list,
111     int x0, int y0, int x1, int background, int colour,
112     const char *font_family, rufl_style font_style,
113     unsigned int font_size, const char *text,
114     click_callback click, unsigned int click_i);
115     void free_paragraph_list(struct paragraph **paragraph_list);
116     void redraw_window(wimp_draw *redraw, struct paragraph *paragraphs);
117     void fill_rectangle(int x0, int y0, int x1, int y1, int colour);
118     void choices_save(void);
119     void choices_load(void);
120     void die(const char *error);
121     void warn(const char *warning);
122     char *get_icon_string(wimp_w w, wimp_i i);
123     void set_icon_string(wimp_w w, wimp_i i, const char *text);
124    
125    
126     int main(int argc, char *argv[])
127     {
128     char error[200];
129     struct stat s;
130    
131 james 79 /* memdebug_memdebug("memdump"); */
132 james 77
133     if (!feed_init())
134     die(feed_error);
135    
136     interval = (30 + time(0) % 20) * 60;
137     choices_load();
138     gui_init();
139    
140     if (stat(FEEDS_READ, &s)) {
141     warn("Welcome to Sargasso! A selection of feeds have been "
142     "added. To add more feeds, use the main menu.");
143     for (unsigned int i = 0; i != sizeof default_feeds /
144     sizeof default_feeds[0]; i++)
145     feed_add(default_feeds[i]);
146     feed_list_save(FEEDS_WRITE);
147     } else if (!feed_list_load(FEEDS_READ)) {
148     snprintf(error, sizeof error, "Unable to load feed list: %s",
149     feed_error);
150     warn(error);
151     }
152    
153     update_main_window();
154     open_window(main_window);
155    
156     last_update = os_read_monotonic_time();
157    
158     while (!quit)
159     gui_poll();
160    
161     gui_quit();
162     feed_quit();
163    
164     return 0;
165     }
166    
167    
168     void gui_init(void)
169     {
170     rufl_code code;
171     const wimp_MESSAGE_LIST(1) messages = { { message_QUIT } };
172     int size;
173     fileswitch_object_type obj_type;
174     wimp_icon_create icon = {
175     wimp_ICON_BAR_RIGHT,
176     { { 0, 0, 68, 68 },
177     wimp_ICON_SPRITE | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED |
178     (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT),
179     { "!sargasso" } } };
180     os_error *error;
181    
182     code = rufl_init();
183     if (code != rufl_OK) {
184     LOG(("rufl_init: %i", code));
185     die("Failed to initialise Unicode font library");
186     }
187    
188     error = xwimp_initialise(wimp_VERSION_RO3, "Sargasso",
189     (const wimp_message_list *) &messages, 0, &task);
190     if (error) {
191     LOG(("xwimp_initialise: 0x%x: %s",
192     error->errnum, error->errmess));
193     die(error->errmess);
194     }
195    
196     error = xosfile_read_stamped_no_path("<Sargasso$Dir>.Sprites",
197     &obj_type, 0, 0, &size, 0, 0);
198     if (error) {
199     LOG(("xosfile_read_stamped_no_path: 0x%x: %s",
200     error->errnum, error->errmess));
201     die(error->errmess);
202     }
203     if (obj_type != fileswitch_IS_FILE)
204     die("Sprites file missing");
205     sprites = malloc(size + 4);
206     if (!sprites)
207     die("Out of memory");
208     sprites->size = size + 4;
209     sprites->sprite_count = 0;
210     sprites->first = 16;
211     sprites->used = 16;
212     error = xosspriteop_load_sprite_file(osspriteop_USER_AREA,
213     sprites, "<Sargasso$Dir>.Sprites");
214     if (error) {
215     LOG(("xosspriteop_load_sprite_file: 0x%x: %s",
216     error->errnum, error->errmess));
217     die(error->errmess);
218     }
219    
220     error = xwimp_create_icon(&icon, 0);
221     if (error) {
222     LOG(("xwimp_create_icon: 0x%x: %s",
223     error->errnum, error->errmess));
224     die(error->errmess);
225     }
226    
227     error = xwimp_open_template("<Sargasso$Dir>.Templates");
228     if (error) {
229     LOG(("xwimp_open_template: 0x%x: %s",
230     error->errnum, error->errmess));
231     die(error->errmess);
232     }
233    
234     info_window = create_window("info");
235     main_window = create_window("main");
236     feed_window = create_window("main");
237     add_feed_window = create_window("add_feed");
238     warning_window = create_window("warning");
239     choices_window = create_window("choices");
240    
241     iconbar_menu.entries[0].sub_menu = (wimp_menu *) info_window;
242    
243     error = xwimp_close_template();
244     if (error) {
245     LOG(("xwimp_close_template: 0x%x: %s",
246     error->errnum, error->errmess));
247     die(error->errmess);
248     }
249     }
250    
251    
252     void gui_quit(void)
253     {
254     free_paragraph_list(&main_window_paragraphs);
255     free_paragraph_list(&feed_window_paragraphs);
256     rufl_quit();
257     }
258    
259    
260     wimp_w create_window(const char *name)
261     {
262     char name_buf[12];
263     int window_size;
264     int data_size;
265     wimp_window *window;
266     char *data;
267     wimp_w w;
268     os_error *error;
269    
270     assert(strlen(name) < 12);
271    
272     strncpy(name_buf, name, sizeof name_buf);
273    
274     error = xwimp_load_template(wimp_GET_SIZE, 0, 0, wimp_NO_FONTS,
275     name_buf, 0, &window_size, &data_size, 0);
276     if (error) {
277     LOG(("xwimp_load_template: 0x%x: %s",
278     error->errnum, error->errmess));
279     die(error->errmess);
280     }
281    
282     window = malloc(window_size);
283     data = malloc(data_size);
284     if (!window || !data)
285     die("Out of memory");
286    
287     error = xwimp_load_template(window, data, data + data_size,
288     wimp_NO_FONTS, name_buf, 0, 0, 0, 0);
289     if (error) {
290     LOG(("xwimp_load_template: 0x%x: %s",
291     error->errnum, error->errmess));
292     die(error->errmess);
293     }
294    
295     error = xwimp_create_window(window, &w);
296     if (error) {
297     LOG(("xwimp_create_window: 0x%x: %s",
298     error->errnum, error->errmess));
299     die(error->errmess);
300     }
301    
302     return w;
303     }
304    
305    
306     void gui_poll(void)
307     {
308     static bool in_window = false;
309     os_t t;
310     wimp_block block;
311     wimp_event_no event;
312     wimp_pointer pointer;
313     osbool more;
314     os_error *error;
315    
316     t = os_read_monotonic_time();
317    
318     error = xwimp_poll_idle(0,
319     &block,
320     feed_work_needed || in_window ? t + 5 : t + 100,
321     0, &event);
322     if (error) {
323     LOG(("xwimp_poll: 0x%x: %s", error->errnum, error->errmess));
324     warn(error->errmess);
325     }
326    
327     switch (event) {
328     case wimp_NULL_REASON_CODE:
329     if (feed_work_needed) {
330     if (feed_work()) {
331     update_main_window();
332     if (feed_count && feeds[current_feed].updated)
333     update_feed_window(current_feed);
334     }
335     }
336    
337     t = os_read_monotonic_time();
338     if (last_update + interval * 100 <= t) {
339     LOG(("updating"));
340     last_update = t;
341     feed_update();
342     }
343    
344     error = xwimp_get_pointer_info(&pointer);
345     if (error) {
346     LOG(("xwimp_get_pointer_info: 0x%x: %s",
347     error->errnum, error->errmess));
348     warn(error->errmess);
349     }
350     mouse_click(pointer.w, pointer.i,
351     pointer.pos.x, pointer.pos.y, 0);
352     break;
353    
354     case wimp_REDRAW_WINDOW_REQUEST:
355     error = xwimp_redraw_window(&block.redraw, &more);
356     if (error) {
357     LOG(("xwimp_redraw_window: 0x%x: %s",
358     error->errnum, error->errmess));
359     break;
360     }
361     while (more) {
362     if (block.redraw.w == main_window)
363     redraw_window(&block.redraw,
364     main_window_paragraphs);
365     else if (block.redraw.w == feed_window)
366     redraw_window(&block.redraw,
367     feed_window_paragraphs);
368     error = xwimp_get_rectangle(&block.redraw, &more);
369     if (error) {
370     LOG(("xwimp_get_rectangle: 0x%x: %s",
371     error->errnum, error->errmess));
372     break;
373     }
374     }
375     break;
376    
377     case wimp_OPEN_WINDOW_REQUEST:
378     error = xwimp_open_window(&block.open);
379     if (error) {
380     LOG(("xwimp_open_window: 0x%x: %s",
381     error->errnum, error->errmess));
382     warn(error->errmess);
383     }
384     break;
385    
386     case wimp_CLOSE_WINDOW_REQUEST:
387     error = xwimp_close_window(block.close.w);
388     if (error) {
389     LOG(("xwimp_close_window: 0x%x: %s",
390     error->errnum, error->errmess));
391     warn(error->errmess);
392     }
393     break;
394    
395     case wimp_POINTER_LEAVING_WINDOW:
396     reset_pointer();
397     in_window = false;
398     break;
399    
400     case wimp_POINTER_ENTERING_WINDOW:
401     in_window = true;
402     break;
403    
404     case wimp_MOUSE_CLICK:
405     mouse_click(block.pointer.w, block.pointer.i,
406     block.pointer.pos.x, block.pointer.pos.y,
407     block.pointer.buttons);
408     break;
409    
410     case wimp_KEY_PRESSED:
411     key_pressed(&block.key);
412     break;
413    
414     case wimp_MENU_SELECTION:
415     menu_selection(&block.selection);
416     break;
417    
418     case wimp_USER_MESSAGE:
419     case wimp_USER_MESSAGE_RECORDED:
420     switch (block.message.action) {
421     case message_QUIT:
422     quit = true;
423     break;
424     }
425     break;
426     }
427     }
428    
429    
430     void mouse_click(wimp_w w, wimp_i i, int x, int y,
431     wimp_mouse_state buttons)
432     {
433     wimp_window_state state;
434     int wx, wy;
435     struct paragraph *p = 0;
436     char minutes[10];
437     int mins;
438     os_error *error;
439    
440     if (w == wimp_ICON_BAR) {
441     if (buttons == wimp_CLICK_MENU)
442     open_menu((wimp_menu *) &iconbar_menu,
443     x - 64, 96 + 44 * 4);
444     else if (buttons == wimp_CLICK_SELECT ||
445     buttons == wimp_CLICK_ADJUST)
446     open_window(main_window);
447    
448     } else if (w == main_window || w == feed_window) {
449     state.w = w;
450     error = xwimp_get_window_state(&state);
451     if (error) {
452     LOG(("xwimp_get_window_state: 0x%x: %s",
453     error->errnum, error->errmess));
454     warn(error->errmess);
455     }
456     wx = x - (state.visible.x0 - state.xscroll);
457     wy = -(y - (state.visible.y1 - state.yscroll));
458     if (w == main_window)
459     p = main_window_paragraphs;
460     else
461     p = feed_window_paragraphs;
462     for (; p; p = p->next) {
463     if (p->x0 <= wx && wx <= p->x1 &&
464     p->y0 <= wy && wy <= p->y1 &&
465     p->click)
466     break;
467     }
468     if (p && buttons == wimp_CLICK_SELECT)
469     p->click(p->click_i);
470     else if (buttons == wimp_CLICK_MENU &&
471     w == main_window) {
472     if (p)
473     main_menu.entries[1].icon_flags &=
474     ~wimp_ICON_SHADED;
475     else
476     main_menu.entries[1].icon_flags |=
477     wimp_ICON_SHADED;
478     open_menu((wimp_menu *) &main_menu, x - 64, y);
479     current_removing = p ? p->click_i : 0;
480     } else if (buttons == 0) {
481     if (p)
482     set_pointer("ptr_point", 6, 0);
483     else
484     reset_pointer();
485     }
486    
487     } else if (w == add_feed_window && buttons) {
488     if (i == 1) {
489     feed_add(get_icon_string(add_feed_window, 0));
490     update_main_window();
491     if (!feed_list_save(FEEDS_WRITE))
492     warn(feed_error);
493     if (buttons == wimp_CLICK_SELECT)
494     close_window(add_feed_window);
495     } else if (i == 2) {
496     close_window(add_feed_window);
497     }
498    
499     } else if (w == warning_window && buttons) {
500     if (i == 1)
501     close_window(warning_window);
502    
503     } else if (w == choices_window && buttons) {
504     if (i == 6) {
505     mins = atoi(get_icon_string(choices_window, 1));
506     if (mins < 15) {
507     mins = 15;
508     warn("To avoid overloading feed providers, "
509     "the minimum update interval "
510     "is 15 minutes.");
511     }
512     interval = mins * 60;
513     choices_save();
514     if (buttons == wimp_CLICK_SELECT)
515     close_window(choices_window);
516     } else if (i == 5) {
517     close_window(choices_window);
518     } else if (i == 2 || i == 3) {
519     mins = atoi(get_icon_string(choices_window, 1));
520     if ((i == 2 && buttons == wimp_CLICK_SELECT) ||
521     (i == 3 && buttons == wimp_CLICK_ADJUST))
522     mins -= 3;
523     else
524     mins += 3;
525     if (mins < 15)
526     mins = 15;
527     else if (999 < mins)
528     mins = 999;
529     snprintf(minutes, sizeof minutes, "%i", mins);
530     set_icon_string(choices_window, 1, minutes);
531     xwimp_set_caret_position(choices_window, 1,
532     0, 0, -1, strlen(minutes));
533 james 79 } else if (i == 7 || i == 8 ||
534     i == 10 || i == 11 ||
535     i == 13 || i == 14) {
536     if (i == 8 || i == 11 || i == 14)
537     i--;
538     wimp_window_state state;
539     wimp_icon_state icon_state;
540     state.w = w;
541     xwimp_get_window_state(&state);
542     icon_state.w = w;
543     icon_state.i = i;
544     xwimp_get_icon_state(&icon_state);
545     open_menu((wimp_menu *) rufl_family_menu,
546     state.visible.x0 + icon_state.icon.extent.x1,
547     state.visible.y1 + icon_state.icon.extent.y1);
548     current_font_menu = i;
549 james 77 }
550     }
551     }
552    
553    
554     void set_pointer(const char *name, int x, int y)
555     {
556     os_error *error;
557     error = xosspriteop_set_pointer_shape(osspriteop_USER_AREA, sprites,
558     (osspriteop_id) name, 1, x, y, 0, 0);
559     if (error) {
560     LOG(("xosspriteop_set_pointer_shape: 0x%x: %s",
561     error->errnum, error->errmess));
562     warn(error->errmess);
563     }
564     }
565    
566    
567     void reset_pointer(void)
568     {
569     os_error *error;
570     error = xwimpspriteop_set_pointer_shape("ptr_default", 1, 0, 0, 0, 0);
571     if (error) {
572     LOG(("xwimpspriteop_set_pointer_shape: 0x%x: %s",
573     error->errnum, error->errmess));
574     warn(error->errmess);
575     }
576     }
577    
578    
579     void key_pressed(wimp_key *key)
580     {
581     os_error *error;
582    
583     if (key->w == add_feed_window) {
584     if (key->c == wimp_KEY_ESCAPE) {
585     mouse_click(key->w, 2, 0, 0, wimp_CLICK_SELECT);
586     return;
587     } else if (key->c == wimp_KEY_RETURN) {
588     mouse_click(key->w, 1, 0, 0, wimp_CLICK_SELECT);
589     return;
590     }
591    
592     } else if (key->w == choices_window) {
593     if (key->c == wimp_KEY_ESCAPE) {
594     mouse_click(key->w, 5, 0, 0, wimp_CLICK_SELECT);
595     return;
596     } else if (key->c == wimp_KEY_RETURN) {
597     mouse_click(key->w, 6, 0, 0, wimp_CLICK_SELECT);
598     return;
599     } else if (key->c == wimp_KEY_DOWN) {
600     mouse_click(key->w, 2, 0, 0, wimp_CLICK_SELECT);
601     return;
602     } else if (key->c == wimp_KEY_UP) {
603     mouse_click(key->w, 3, 0, 0, wimp_CLICK_SELECT);
604     return;
605     }
606    
607     } else if (key->w == warning_window) {
608     if (key->c == wimp_KEY_ESCAPE ||
609     key->c == wimp_KEY_RETURN) {
610     close_window(warning_window);
611     }
612     }
613    
614     error = xwimp_process_key(key->c);
615     if (error) {
616     LOG(("xwimp_process_key: 0x%x: %s",
617     error->errnum, error->errmess));
618     warn(error->errmess);
619     }
620     }
621    
622    
623     void menu_selection(wimp_selection *selection)
624     {
625     char minutes[10];
626 james 79 wimp_pointer pointer;
627 james 77
628 james 79 xwimp_get_pointer_info(&pointer);
629    
630 james 77 if (current_menu == (wimp_menu *) &iconbar_menu) {
631     switch (selection->items[0]) {
632     case 1:
633     snprintf(minutes, sizeof minutes, "%i", interval / 60);
634     set_icon_string(choices_window, 1, minutes);
635 james 79 set_icon_string(choices_window, 8, font_headings);
636     set_icon_string(choices_window, 11, font_summaries);
637     set_icon_string(choices_window, 14, font_links);
638 james 77 open_window(choices_window);
639     xwimp_set_caret_position(choices_window, 1,
640     0, 0, -1, strlen(minutes));
641     break;
642     case 2:
643     last_update = os_read_monotonic_time();
644     feed_update();
645     break;
646     case 3:
647     quit = true;
648     break;
649     }
650    
651     } else if (current_menu == (wimp_menu *) &main_menu) {
652     switch (selection->items[0]) {
653     case 0:
654     set_icon_string(add_feed_window, 0, "http://");
655     open_window(add_feed_window);
656     xwimp_set_caret_position(add_feed_window, 0,
657     0, 0, -1, 7);
658     break;
659     case 1:
660     feed_remove(current_removing);
661     update_main_window();
662     close_window(feed_window);
663     if (!feed_list_save(FEEDS_WRITE))
664     warn(feed_error);
665     break;
666     }
667 james 79 } else if (current_menu == (wimp_menu *) rufl_family_menu) {
668     char *font = ((wimp_menu *) rufl_family_menu)->
669     entries[selection->items[0]].data.indirected_text.text;
670     if (current_font_menu == 7)
671     strncpy(font_headings, font, sizeof font_headings);
672     else if (current_font_menu == 10)
673     strncpy(font_summaries, font, sizeof font_summaries);
674     else if (current_font_menu == 13)
675     strncpy(font_links, font, sizeof font_links);
676     set_icon_string(choices_window, 8, font_headings);
677     set_icon_string(choices_window, 11, font_summaries);
678     set_icon_string(choices_window, 14, font_links);
679     update_main_window();
680     if (feed_count)
681     update_feed_window(current_feed);
682 james 77 }
683 james 79
684     if (pointer.buttons == wimp_CLICK_ADJUST)
685     xwimp_create_menu(current_menu, pointer.pos.x, pointer.pos.y);
686 james 77 }
687    
688    
689     void open_window(wimp_w w)
690     {
691     const os_VDU_VAR_LIST(5) vars = { { os_MODEVAR_XWIND_LIMIT,
692     os_MODEVAR_YWIND_LIMIT, os_MODEVAR_XEIG_FACTOR,
693     os_MODEVAR_YEIG_FACTOR, os_VDUVAR_END_LIST } };
694     int vals[4];
695     int width, height;
696     wimp_window_state state;
697     int dx, dy;
698     os_error *error;
699    
700     error = xos_read_vdu_variables((const os_vdu_var_list *) &vars, vals);
701     if (error) {
702     LOG(("xos_read_vdu_variables: 0x%x: %s",
703     error->errnum, error->errmess));
704     warn(error->errmess);
705     return;
706     }
707     width = (vals[0] + 1) << vals[2];
708     height = (vals[1] + 1) << vals[3];
709    
710     state.w = w;
711     error = xwimp_get_window_state(&state);
712     if (error) {
713     LOG(("xwimp_get_window_state: 0x%x: %s",
714     error->errnum, error->errmess));
715     warn(error->errmess);
716     return;
717     }
718    
719     dx = (state.visible.x1 - state.visible.x0) / 2;
720     dy = (state.visible.y1 - state.visible.y0) / 2;
721     state.visible.x0 = width / 2 - dx;
722     state.visible.y0 = height / 2 - dy;
723     state.visible.x1 = width / 2 + dx;
724     state.visible.y1 = height / 2 + dy;
725     state.xscroll = 0;
726     state.yscroll = 0;
727     state.next = wimp_TOP;
728    
729     error = xwimp_open_window((wimp_open *) &state);
730     if (error) {
731     LOG(("xwimp_open_window: 0x%x: %s",
732     error->errnum, error->errmess));
733     warn(error->errmess);
734     }
735     }
736    
737    
738     void close_window(wimp_w w)
739     {
740     os_error *error;
741    
742     error = xwimp_close_window(w);
743     if (error) {
744     LOG(("xwimp_close_window: 0x%x: %s",
745     error->errnum, error->errmess));
746     warn(error->errmess);
747     }
748     }
749    
750    
751     void open_menu(wimp_menu *menu, int x, int y)
752     {
753     os_error *error;
754    
755     error = xwimp_create_menu(menu, x, y);
756     if (error) {
757     LOG(("xwimp_create_menu: 0x%x: %s",
758     error->errnum, error->errmess));
759     warn(error->errmess);
760     }
761     current_menu = menu;
762     }
763    
764    
765     void update_main_window(void)
766     {
767     static char *status = 0;
768     int y = 0;
769     int y1;
770     unsigned int i;
771     unsigned int j;
772     unsigned int new_items;
773     rufl_style style;
774     struct paragraph *p;
775    
776     free_paragraph_list(&main_window_paragraphs);
777     free(status);
778    
779     status = malloc(feed_count * 40);
780     if (!status) {
781     LOG(("out of memory"));
782     return;
783     }
784    
785     for (i = 0; i != feed_count; i++) {
786     new_items = 0;
787     for (j = 0; j != feeds[i].item_count; j++)
788     if (feeds[i].item[j].new_item)
789     new_items++;
790     style = new_items ? rufl_WEIGHT_900 : rufl_WEIGHT_400;
791    
792     p = add_paragraph(&main_window_paragraphs, 0, y, 700,
793     0xffaa99, 0x000000,
794 james 79 font_headings, style, 200,
795 james 77 feeds[i].title ? (char *) feeds[i].title :
796     feeds[i].url,
797     click_main_window, i);
798     y1 = p->y1;
799    
800     switch (feeds[i].status) {
801     case FEED_NEW:
802     case FEED_FETCHING:
803     case FEED_UPDATE:
804     snprintf(status + i * 40, 40, "Fetching");
805     break;
806     case FEED_OK:
807     if (new_items)
808     snprintf(status + i * 40, 40,
809     "%i items (%i new)",
810     feeds[i].item_count,
811     new_items);
812     else
813     snprintf(status + i * 40, 40,
814     "%i items",
815     feeds[i].item_count);
816     break;
817     case FEED_ERROR:
818     snprintf(status + i * 40, 40, "Failed");
819     break;
820     }
821     p = add_paragraph(&main_window_paragraphs, 700, y, 1000,
822     0xffaa99, 0x000000,
823 james 79 font_headings, style, 200,
824 james 77 status + i * 40,
825     click_main_window, i);
826     y = p->y1 = y1;
827    
828     if (feeds[i].error) {
829     p = add_paragraph(&main_window_paragraphs, 0, y, 1000,
830     0, 0x0000a0,
831 james 79 font_summaries, style, 200,
832 james 77 feeds[i].error,
833     click_main_window, i);
834     y = p->y1;
835     }
836    
837     if (feeds[i].description) {
838     p = add_paragraph(&main_window_paragraphs, 0, y, 1000,
839     0, 0x000000,
840 james 79 font_summaries, rufl_WEIGHT_400, 200,
841 james 77 feeds[i].description,
842     click_main_window, i);
843     y = p->y1;
844     }
845    
846     y += MARGIN;
847     }
848    
849     set_extent(main_window, y);
850     }
851    
852    
853     void set_extent(wimp_w w, int y)
854     {
855     os_box extent = { 0, 0, 1000, 0 };
856     wimp_window_state state;
857     os_error *error;
858    
859     extent.y0 = -y;
860     error = xwimp_set_extent(w, &extent);
861     if (error) {
862     LOG(("xwimp_set_extent: 0x%x: %s",
863     error->errnum, error->errmess));
864     warn(error->errmess);
865     }
866    
867     state.w = w;
868     error = xwimp_get_window_state(&state);
869     if (error) {
870     LOG(("xwimp_get_window_state: 0x%x: %s",
871     error->errnum, error->errmess));
872     warn(error->errmess);
873     }
874    
875     if (state.flags & wimp_WINDOW_OPEN) {
876     error = xwimp_close_window(w);
877     if (error) {
878     LOG(("xwimp_close_window: 0x%x: %s",
879     error->errnum, error->errmess));
880     warn(error->errmess);
881     }
882    
883     /*state.visible.y0 = 100;
884     state.visible.y1 = 100 + y;*/
885     error = xwimp_open_window((wimp_open *) &state);
886     if (error) {
887     LOG(("xwimp_open_window: 0x%x: %s",
888     error->errnum, error->errmess));
889     warn(error->errmess);
890     }
891     }
892     }
893    
894    
895     void click_main_window(unsigned int i)
896     {
897     unsigned int j;
898    
899     update_feed_window(i);
900     open_window(feed_window);
901    
902     for (j = 0; j != feeds[i].item_count; j++)
903     feeds[i].item[j].new_item = false;
904     update_main_window();
905     }
906    
907    
908     void update_feed_window(unsigned int i)
909     {
910     int y = 0;
911     int y1;
912     unsigned int j;
913     struct paragraph *p;
914     rufl_style style;
915    
916     current_feed = i;
917    
918     free_paragraph_list(&feed_window_paragraphs);
919    
920     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
921     0xffaa99, 0x000000,
922 james 79 font_headings, rufl_WEIGHT_400, 200,
923 james 77 feeds[i].title ? (char *) feeds[i].title : feeds[i].url,
924     0, 0);
925     y = p->y1;
926    
927     if (feeds[i].link) {
928     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
929     0, 0xff0000,
930 james 79 font_links, rufl_WEIGHT_400, 160,
931 james 77 feeds[i].link,
932     click_feed_link, i);
933     y = p->y1;
934     }
935     if (feeds[i].pub_date) {
936     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
937     0, 0x0060ee,
938 james 79 font_summaries, rufl_WEIGHT_400 | rufl_SLANTED,
939     160,
940 james 77 feeds[i].pub_date,
941     0, 0);
942     y = p->y1;
943     }
944     if (feeds[i].description) {
945     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
946     0, 0x000000,
947 james 79 font_summaries, rufl_WEIGHT_400, 200,
948 james 77 feeds[i].description,
949     0, 0);
950     y = p->y1;
951     }
952     if (feeds[i].copyright) {
953     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
954     0, 0x666666,
955 james 79 font_summaries, rufl_WEIGHT_400 | rufl_SLANTED, 160,
956 james 77 feeds[i].copyright,
957     0, 0);
958     y = p->y1;
959     }
960    
961     y += MARGIN;
962    
963     for (j = 0; j != feeds[i].item_count; j++) {
964     style = feeds[i].item[j].new_item ? rufl_WEIGHT_900 :
965     rufl_WEIGHT_400;
966    
967     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
968     0xa0dddd, 0x000000,
969 james 79 font_headings, style, 200,
970 james 77 feeds[i].item[j].title ?
971     (char *) feeds[i].item[j].title : "",
972     0, j);
973     y1 = y = p->y1;
974    
975     if (feeds[i].item[j].pub_date) {
976     p = add_paragraph(&feed_window_paragraphs, 0, y, 420,
977     0, 0x0060ee,
978 james 79 font_summaries,
979 james 77 rufl_WEIGHT_400 | rufl_SLANTED, 160,
980     feeds[i].item[j].pub_date,
981     0, j);
982     if (y1 < p->y1)
983     y1 = p->y1;
984     }
985     if (feeds[i].item[j].author) {
986     p = add_paragraph(&feed_window_paragraphs, 420, y, 720,
987     0, 0x666666,
988 james 79 font_summaries,
989 james 77 rufl_WEIGHT_400 | rufl_SLANTED, 160,
990     feeds[i].item[j].author,
991     0, j);
992     if (y1 < p->y1)
993     y1 = p->y1;
994     }
995     if (feeds[i].item[j].category) {
996     p = add_paragraph(&feed_window_paragraphs, 720, y, 1000,
997     0, 0xee6000,
998 james 79 font_summaries, rufl_WEIGHT_400, 160,
999 james 77 feeds[i].item[j].category,
1000     0, j);
1001     if (y1 < p->y1)
1002     y1 = p->y1;
1003     }
1004     y = y1;
1005    
1006     if (feeds[i].item[j].link) {
1007     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
1008     0, 0xff0000,
1009 james 79 font_links, rufl_WEIGHT_400, 160,
1010 james 77 feeds[i].item[j].link,
1011     click_item_link, j);
1012     y = p->y1;
1013     }
1014    
1015     if (feeds[i].item[j].description) {
1016     p = add_paragraph(&feed_window_paragraphs, 0, y, 1000,
1017     0, 0x000000,
1018 james 79 font_summaries, rufl_WEIGHT_400, 180,
1019 james 77 feeds[i].item[j].description,
1020     0, j);
1021     y = p->y1;
1022     }
1023    
1024     y += MARGIN;
1025     }
1026    
1027     set_extent(feed_window, y);
1028     }
1029    
1030    
1031     void click_feed_link(unsigned int i)
1032     {
1033     os_error *error;
1034     error = xuri_dispatch(0, feeds[i].link, task, 0, 0, 0);
1035     if (error) {
1036     LOG(("xuri_dispatch: 0x%x: %s",
1037     error->errnum, error->errmess));
1038     }
1039     }
1040    
1041    
1042     void click_item_link(unsigned int j)
1043     {
1044     os_error *error;
1045     error = xuri_dispatch(0, feeds[current_feed].item[j].link, task,
1046     0, 0, 0);
1047     if (error) {
1048     LOG(("xuri_dispatch: 0x%x: %s",
1049     error->errnum, error->errmess));
1050     }
1051     }
1052    
1053    
1054     struct paragraph *add_paragraph(struct paragraph **paragraph_list,
1055     int x0, int y0, int x1, int background, int colour,
1056     const char *font_family, rufl_style font_style,
1057     unsigned int font_size, const char *text,
1058     click_callback click, unsigned int click_i)
1059     {
1060     struct paragraph *p;
1061     const char *t;
1062     size_t len = strlen(text);
1063     unsigned int lines = 0;
1064     size_t char_offset;
1065     int actual_x;
1066     rufl_code code;
1067    
1068     p = malloc(sizeof *p);
1069     if (!p)
1070     return 0;
1071    
1072     p->x0 = x0;
1073     p->y0 = y0;
1074     p->x1 = x1;
1075     p->background = background;
1076     p->colour = colour;
1077     p->font_family = font_family;
1078     p->font_style = font_style;
1079     p->font_size = font_size;
1080     p->click = click;
1081     p->click_i = click_i;
1082     p->lines = 0;
1083     p->text[0] = text;
1084    
1085     t = text;
1086     while (len && lines != MAX_LINES) {
1087     code = rufl_split(font_family, font_style, font_size, t, len,
1088     x1 - x0 - MARGIN - MARGIN,
1089     &char_offset, &actual_x);
1090     if (code != rufl_OK) {
1091     LOG(("rufl_split: %i", code));
1092     break;
1093     }
1094     if (char_offset != len) {
1095     size_t space;
1096     for (space = char_offset; space && t[space] != ' ';
1097     space--)
1098     continue;
1099     if (space)
1100     char_offset = space + 1;
1101     }
1102     len -= char_offset;
1103     t += char_offset;
1104     p->text[++lines] = t;
1105     }
1106    
1107     p->y1 = p->y0 + MARGIN + lines * font_size * 0.2 + MARGIN;
1108     p->lines = lines;
1109    
1110     p->next = *paragraph_list;
1111     *paragraph_list = p;
1112    
1113     return p;
1114     }
1115    
1116    
1117     void free_paragraph_list(struct paragraph **paragraph_list)
1118     {
1119     struct paragraph *p = *paragraph_list;
1120     struct paragraph *next;
1121    
1122     while (p) {
1123     next = p->next;
1124     free(p);
1125     p = next;
1126     }
1127    
1128     *paragraph_list = 0;
1129     }
1130    
1131    
1132     void redraw_window(wimp_draw *redraw, struct paragraph *paragraphs)
1133     {
1134     int ox = redraw->box.x0 - redraw->xscroll;
1135     int oy = redraw->box.y1 - redraw->yscroll;
1136     int clip_x0 = redraw->clip.x0 - ox;
1137     int clip_y0 = oy - redraw->clip.y1;
1138     int clip_x1 = redraw->clip.x1 - ox;
1139     int clip_y1 = oy - redraw->clip.y0;
1140     struct paragraph *p;
1141     unsigned int i;
1142     os_error *error;
1143     rufl_code code;
1144    
1145     for (p = paragraphs; p; p = p->next) {
1146     if (p->x1 < clip_x0 || clip_x1 < p->x0 ||
1147     p->y1 < clip_y0 || clip_y1 < p->y0)
1148     continue;
1149     if (p->background)
1150     fill_rectangle(ox + p->x0, oy - p->y1,
1151     ox + p->x1, oy - p->y0,
1152     p->background);
1153     for (i = 0; i != p->lines; i++) {
1154     error = xcolourtrans_set_font_colours(font_CURRENT,
1155     p->background << 8, p->colour << 8,
1156     14, 0, 0, 0);
1157     if (error) {
1158     LOG(("xcolourtrans_set_font_colours: 0x%x: %s",
1159     error->errnum, error->errmess));
1160     return;
1161     }
1162     code = rufl_paint(p->font_family, p->font_style,
1163     p->font_size, p->text[i],
1164     p->text[i + 1] - p->text[i],
1165     ox + p->x0 + MARGIN,
1166     oy - p->y0 - MARGIN -
1167     i * p->font_size * 0.2 -
1168     p->font_size * 0.15,
1169     rufl_BLEND_FONT);
1170     if (code != rufl_OK) {
1171     LOG(("rufl_paint: %i", code));
1172     return;
1173     }
1174     }
1175     }
1176     }
1177    
1178    
1179     void fill_rectangle(int x0, int y0, int x1, int y1, int colour)
1180     {
1181     os_error *error;
1182    
1183     error = xcolourtrans_set_gcol(colour << 8, colourtrans_USE_ECFS,
1184     os_ACTION_OVERWRITE, 0, 0);
1185     if (error) {
1186     LOG(("xcolourtrans_set_gcol: 0x%x: %s",
1187     error->errnum, error->errmess));
1188     return;
1189     }
1190    
1191     error = xos_plot(os_MOVE_TO, x0, y0);
1192     if (error) {
1193     LOG(("xos_plot: 0x%x: %s", error->errnum, error->errmess));
1194     return;
1195     }
1196    
1197     error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO, x1, y1);
1198     if (error) {
1199     LOG(("xos_plot: 0x%x: %s", error->errnum, error->errmess));
1200     return;
1201     }
1202     }
1203    
1204    
1205     void choices_save(void)
1206     {
1207     FILE *choices;
1208     char error[200];
1209    
1210     choices = fopen(CHOICES_WRITE, "w");
1211     if (!choices) {
1212     LOG(("fopen: %i: %s", errno, strerror(errno)));
1213     snprintf(error, sizeof error, "Unable to save choices: %s",
1214     strerror(errno));
1215     warn(error);
1216     return;
1217     }
1218     fprintf(choices, "interval: %i\n", interval);
1219 james 79 fprintf(choices, "font_headings: %s\n", font_headings);
1220     fprintf(choices, "font_summaries: %s\n", font_summaries);
1221     fprintf(choices, "font_links: %s\n", font_links);
1222 james 77 fclose(choices);
1223     }
1224    
1225    
1226     void choices_load(void)
1227     {
1228     FILE *choices;
1229     char error[200];
1230     char s[100];
1231    
1232     choices = fopen(CHOICES_READ, "r");
1233     if (!choices) {
1234     LOG(("fopen: %i: %s", errno, strerror(errno)));
1235     if (errno != ENOENT) {
1236     snprintf(error, sizeof error,
1237     "Unable to read choices: %s",
1238     strerror(errno));
1239     warn(error);
1240     }
1241     return;
1242     }
1243     while (fgets(s, sizeof s, choices)) {
1244     sscanf(s, "interval: %i", &interval);
1245 james 79 sscanf(s, "font_headings: %s", font_headings);
1246     sscanf(s, "font_summaries: %s", font_summaries);
1247     sscanf(s, "font_links: %s", font_links);
1248 james 77 }
1249     fclose(choices);
1250     }
1251    
1252    
1253     /**
1254     * Display an error and exit.
1255     */
1256    
1257     void die(const char *error)
1258     {
1259     os_error warn_error;
1260    
1261     warn_error.errnum = 1;
1262     strncpy(warn_error.errmess, error, sizeof warn_error.errmess - 1);
1263     warn_error.errmess[sizeof warn_error.errmess - 1] = '\0';
1264     xwimp_report_error_by_category(&warn_error,
1265     wimp_ERROR_BOX_OK_ICON |
1266     wimp_ERROR_BOX_GIVEN_CATEGORY |
1267     wimp_ERROR_BOX_CATEGORY_ERROR <<
1268     wimp_ERROR_BOX_CATEGORY_SHIFT,
1269     "Sargasso", "!sargasso",
1270     (osspriteop_area *) 1, 0, 0);
1271     exit(EXIT_FAILURE);
1272     }
1273    
1274    
1275     void warn(const char *warning)
1276     {
1277     os_error error;
1278    
1279     LOG(("%s", warning));
1280    
1281     if (warning_window) {
1282     set_icon_string(warning_window, 0, warning);
1283     open_window(warning_window);
1284     xwimp_set_caret_position(warning_window, wimp_ICON_WINDOW,
1285     -100, -100, 1, 0);
1286     xos_bell();
1287     } else {
1288     strncpy(error.errmess, warning, sizeof error.errmess);
1289     error.errmess[sizeof error.errmess - 1] = 0;
1290     xwimp_report_error_by_category(&error,
1291     wimp_ERROR_BOX_OK_ICON |
1292     wimp_ERROR_BOX_GIVEN_CATEGORY |
1293     wimp_ERROR_BOX_CATEGORY_ERROR <<
1294     wimp_ERROR_BOX_CATEGORY_SHIFT,
1295     "Sargasso", "!sargasso",
1296     (osspriteop_area *) 1, 0, 0);
1297     }
1298     }
1299    
1300    
1301     char *get_icon_string(wimp_w w, wimp_i i)
1302     {
1303     wimp_icon_state icon_state = {w, i};
1304     os_error *error;
1305    
1306     error = xwimp_get_icon_state(&icon_state);
1307     if (error) {
1308     LOG(("xwimp_get_icon_state: 0x%x: %s",
1309     error->errnum, error->errmess));
1310     return "";
1311     }
1312    
1313     return icon_state.icon.data.indirected_text.text;
1314     }
1315    
1316    
1317     void set_icon_string(wimp_w w, wimp_i i, const char *text)
1318     {
1319     wimp_icon_state icon_state = {w, i};
1320     unsigned int size;
1321     os_error *error;
1322    
1323     error = xwimp_get_icon_state(&icon_state);
1324     if (error) {
1325     LOG(("xwimp_get_icon_state: 0x%x: %s",
1326     error->errnum, error->errmess));
1327     return;
1328     }
1329     size = (unsigned int) icon_state.icon.data.indirected_text.size;
1330    
1331     if (!strncmp(icon_state.icon.data.indirected_text.text, text, size))
1332     return;
1333    
1334     strncpy(icon_state.icon.data.indirected_text.text, text, size);
1335     icon_state.icon.data.indirected_text.text[size - 1] = '\0';
1336    
1337     xwimp_set_icon_state(w, i, 0, 0);
1338     }

  ViewVC Help
Powered by ViewVC 1.1.26