1 /*
2   $Id: gtkmessage.c,v 1.10 2003/08/02 14:27:26 j_ali Exp $
3  */
4 /*
5   GTK+ NetHack Copyright (c) Issei Numata 1999-2000
6   GTK+ NetHack Copyright (c) Slash'EM Development Team 2000-2003
7   GTK+ NetHack may be freely redistributed.  See license for details.
8 */
9 
10 #include <sys/types.h>
11 #include <signal.h>
12 #include "winGTK.h"
13 #include <gtk/gtk.h>
14 #include <gdk/gdkkeysyms.h>
15 
16 static GtkWidget *message_text;
17 
18 extern int root_width;
19 extern int root_height;
20 
21 #if GTK_CHECK_VERSION(2,0,0)
22 # define USE_TEXTVIEW
23 #else	/* GTK_CHECK_VERSION */
24 # ifdef WIN32
25    /* ALI: Switching this on avoids strange scrolling effects (see bug 124233).
26     */
27 #  define FROZEN_INSERT
28 # endif
29 #endif	/* GTK_CHECK_VERSION */
30 
31 #ifdef USE_TEXTVIEW
32 GtkWidget *
nh_message_new()33 nh_message_new()
34 {
35     GtkWidget *message_h;
36     GtkWidget *sw;
37     GtkTextIter iter;
38     GtkTextBuffer *t;
39 
40     message_h = gtk_handle_box_new();
41     GTK_HANDLE_BOX(message_h)->shrink_on_detach = 1;
42 
43     message_text = gtk_text_view_new();
44     gtk_widget_show(message_text);
45     GTK_WIDGET_UNSET_FLAGS(message_text, GTK_CAN_FOCUS);
46     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(message_text), GTK_WRAP_WORD);
47     t = gtk_text_view_get_buffer(GTK_TEXT_VIEW(message_text));
48     gtk_text_buffer_create_tag(t, "warning", "foreground", "red", NULL);
49     gtk_text_buffer_get_end_iter(t, &iter);
50     gtk_text_buffer_create_mark(t, "nh_end", &iter, FALSE);
51 
52     sw = nh_gtk_new_and_add(gtk_scrolled_window_new(NULL, NULL), message_h, "");
53     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
54       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
55     gtk_container_add(GTK_CONTAINER(sw), message_text);
56 
57     return message_h;
58 }
59 
60 void
nh_message_putstr(const char * str)61 nh_message_putstr(const char *str)
62 {
63     int	len;
64     char *buf;
65     GtkTextIter iter, iter2;
66     GtkTextBuffer *t;
67 
68     if (!message_text)
69 	return;
70 
71     t = gtk_text_view_get_buffer(GTK_TEXT_VIEW(message_text));
72     gtk_text_buffer_get_end_iter(t, &iter);
73 
74     len = strlen(str);
75     buf = (char *)alloc(len + 2);
76 
77     sprintf(buf, "\n%s", str);
78 
79     if (nh_status_in_trouble())
80 	gtk_text_buffer_insert_with_tags_by_name(t, &iter, buf, len + 1,
81 	  "warning", NULL);
82     else
83 	gtk_text_buffer_insert(t, &iter, buf, len + 1);
84     free(buf);
85 
86     len = gtk_text_buffer_get_char_count(t);
87     if (len > NH_TEXT_REMEMBER) {
88 	gtk_text_buffer_get_iter_at_offset(t, &iter, len - NH_TEXT_REMEMBER);
89 	gtk_text_buffer_get_iter_at_line(t, &iter2,
90 	  gtk_text_iter_get_line(&iter) + 1);
91 	gtk_text_buffer_get_start_iter(t, &iter);
92 	gtk_text_buffer_delete(t, &iter, &iter2);
93     }
94 
95     gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(message_text),
96       gtk_text_buffer_get_mark(t, "nh_end"));
97 }
98 
99 #else	/* USE_TEXTVIEW */
100 
101 GtkWidget *
nh_message_new()102 nh_message_new()
103 {
104     GtkWidget *message_h;
105     GtkWidget *message_hbox;
106 
107     message_h = gtk_handle_box_new();
108     GTK_HANDLE_BOX(message_h)->shrink_on_detach = 1;
109 
110     message_hbox = nh_gtk_new_and_add(gtk_hbox_new(FALSE, 0), message_h, "");
111 
112     message_text = nh_gtk_new_and_pack(gtk_text_new(NULL, NULL),
113       message_hbox, "", TRUE, TRUE, NH_PAD);
114 
115     GTK_WIDGET_UNSET_FLAGS(message_text, GTK_CAN_FOCUS);
116     gtk_text_set_word_wrap((GtkText *) message_text, TRUE);
117 
118     (void)nh_gtk_new_and_pack(gtk_vscrollbar_new(GTK_TEXT(message_text)->vadj),
119       message_hbox, "", FALSE, FALSE, NH_PAD);
120 
121     return message_h;
122 }
123 
124 void
nh_message_putstr(const char * str)125 nh_message_putstr(const char *str)
126 {
127     int i;
128     int	len;
129     char *buf;
130     GtkText *t;
131 #ifdef FROZEN_INSERT
132     static int	freeze_count=0;
133 #endif
134 
135     if (!message_text)
136 	return;
137 
138     t = GTK_TEXT(message_text);
139 
140     len = strlen(str);
141     buf = (char *)alloc(len + 2);
142 
143     sprintf(buf, "\n%s", str);
144 
145 #ifdef FROZEN_INSERT
146     /* ALI: gimpwin 20001226 looks very bad if you update a text widget without
147      * freezing it (the text is displayed half-scrolled, with lines overlapping
148      * each other). This is not ideal (the text is redrawn each thaw), but it
149      * is an improvement. Due to a bug in gimpwin we can't trim text if we've
150      * frozen the widget, thus every so often we don't freeze but trim instead.
151      */
152     if (++freeze_count >= 50)	/* Trim text every 50 inserts */
153 	freeze_count = 0;
154     else
155 	gtk_text_freeze(t);
156 #endif
157 
158     if (nh_status_in_trouble())
159 	i = CLR_RED;
160     else
161 	i = MAP_BLACK;
162     gtk_text_insert(t, NULL, &nh_color[i], &nh_color[MAP_WHITE], buf, len + 1);
163 
164     len = gtk_text_get_length(t);
165 #ifdef FROZEN_INSERT
166     if (!freeze_count && len > NH_TEXT_REMEMBER) {
167 #else
168     if (len > NH_TEXT_REMEMBER) {
169 #endif
170 	gtk_text_freeze(t);
171 	for(i = 0; i < len && len > NH_TEXT_REMEMBER; i++)
172 	    if (GTK_TEXT_INDEX(t, i) == '\n') {
173 		i++;
174 		gtk_text_set_point(t, i);
175 		gtk_text_backward_delete(t, i);
176 		len -= i;
177 	    }
178 	gtk_text_set_point(t, len);
179 	gtk_text_thaw(t);
180     }
181 #ifdef FROZEN_INSERT
182     /* ALI: t->vadj->upper would be more correct, but causes gimpwin to crash */
183     if (freeze_count) {
184 	gtk_adjustment_set_value(t->vadj, t->vadj->upper - 1);
185 	gtk_text_thaw(t);
186     }
187 #endif
188 
189     free(buf);
190 }
191 
192 #endif	/* USE_TEXTVIEW */
193 
194 int
195 GTK_doprev_message()
196 {
197     return 0;
198 }
199 
200 void
201 nh_message_destroy(void)
202 {
203     message_text = NULL;
204 }
205