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

Annotation of /sargasso2/sargasso.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 81 - (hide annotations) (download) (as text)
Sun Nov 26 16:57:32 2006 UTC (17 years, 11 months ago) by james
File MIME type: text/x-csrc
File size: 32300 byte(s)
Create Choices.Sargasso directory.

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

  ViewVC Help
Powered by ViewVC 1.1.26