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

Annotation of /sargasso2/sargasso.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 83 - (hide annotations) (download) (as text)
Mon Jul 6 01:59:16 2009 UTC (15 years, 5 months ago) by james
File MIME type: text/x-csrc
File size: 32378 byte(s)
Move rufl_init after wimp_initialise so that multi-tasking scanning is used. Fix LOG macro.

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

  ViewVC Help
Powered by ViewVC 1.1.26