1 /*
2  * GNT - The GLib Ncurses Toolkit
3  *
4  * GNT is the legal property of its developers, whose names are too numerous
5  * to list here.  Please refer to the COPYRIGHT file distributed with this
6  * source distribution.
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
21  */
22 
23 /* Stuff brutally ripped from Gflib */
24 
25 #include "gntinternal.h"
26 #include "gntwidget.h"
27 #include "gntstyle.h"
28 #include "gntmarshal.h"
29 #include "gntutils.h"
30 #include "gnt.h"
31 
32 enum
33 {
34 	SIG_DESTROY,
35 	SIG_DRAW,
36 	SIG_HIDE,
37 	SIG_GIVE_FOCUS,
38 	SIG_LOST_FOCUS,
39 	SIG_KEY_PRESSED,
40 	SIG_MAP,
41 	SIG_ACTIVATE,
42 	SIG_EXPOSE,
43 	SIG_SIZE_REQUEST,
44 	SIG_CONFIRM_SIZE,
45 	SIG_SIZE_CHANGED,
46 	SIG_POSITION,
47 	SIG_CLICKED,
48 	SIG_CONTEXT_MENU,
49 	SIGS
50 };
51 
52 static GObjectClass *parent_class = NULL;
53 static guint signals[SIGS] = { 0 };
54 
55 static void init_widget(GntWidget *widget);
56 
57 static void
gnt_widget_init(GTypeInstance * instance,gpointer class)58 gnt_widget_init(GTypeInstance *instance, gpointer class)
59 {
60 	GntWidget *widget = GNT_WIDGET(instance);
61 	widget->priv.name = NULL;
62 	GNTDEBUG;
63 }
64 
65 static void
gnt_widget_map(GntWidget * widget)66 gnt_widget_map(GntWidget *widget)
67 {
68 	/* Get some default size for the widget */
69 	GNTDEBUG;
70 	g_signal_emit(widget, signals[SIG_MAP], 0);
71 	gnt_widget_set_mapped(widget, TRUE);
72 }
73 
74 static void
gnt_widget_dispose(GObject * obj)75 gnt_widget_dispose(GObject *obj)
76 {
77 	GntWidget *self = GNT_WIDGET(obj);
78 	g_signal_emit(self, signals[SIG_DESTROY], 0);
79 	parent_class->dispose(obj);
80 	GNTDEBUG;
81 }
82 
83 static void
gnt_widget_focus_change(GntWidget * widget)84 gnt_widget_focus_change(GntWidget *widget)
85 {
86 	if (gnt_widget_get_mapped(widget)) {
87 		gnt_widget_draw(widget);
88 	}
89 }
90 
91 static gboolean
gnt_widget_dummy_confirm_size(GntWidget * widget,int width,int height)92 gnt_widget_dummy_confirm_size(GntWidget *widget, int width, int height)
93 {
94 	gboolean shadow;
95 	if (width < widget->priv.minw || height < widget->priv.minh) {
96 		return FALSE;
97 	}
98 
99 	shadow = gnt_widget_has_shadow(widget);
100 	if (widget->priv.width + shadow != width &&
101 	    !gnt_widget_get_grow_x(widget)) {
102 		return FALSE;
103 	}
104 	if (widget->priv.height + shadow != height &&
105 	    !gnt_widget_get_grow_y(widget)) {
106 		return FALSE;
107 	}
108 
109 	return TRUE;
110 }
111 
112 static gboolean
context_menu(GntBindable * bind,GList * null)113 context_menu(GntBindable *bind, GList *null)
114 {
115 	gboolean ret = FALSE;
116 	g_signal_emit(bind, signals[SIG_CONTEXT_MENU], 0, &ret);
117 	return ret;
118 }
119 
120 static void
gnt_widget_class_init(GntWidgetClass * klass)121 gnt_widget_class_init(GntWidgetClass *klass)
122 {
123 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
124 
125 	parent_class = g_type_class_peek_parent(klass);
126 
127 	obj_class->dispose = gnt_widget_dispose;
128 
129 	klass->destroy = gnt_widget_destroy;
130 	klass->show = gnt_widget_show;
131 	klass->draw = gnt_widget_draw;
132 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
133 	klass->expose = gnt_widget_expose;
134 G_GNUC_END_IGNORE_DEPRECATIONS
135 	klass->map = gnt_widget_map;
136 	klass->lost_focus = gnt_widget_focus_change;
137 	klass->gained_focus = gnt_widget_focus_change;
138 	klass->confirm_size = gnt_widget_dummy_confirm_size;
139 
140 	klass->key_pressed = NULL;
141 	klass->activate = NULL;
142 	klass->clicked = NULL;
143 
144 	signals[SIG_DESTROY] =
145 		g_signal_new("destroy",
146 					 G_TYPE_FROM_CLASS(klass),
147 					 G_SIGNAL_RUN_LAST,
148 					 G_STRUCT_OFFSET(GntWidgetClass, destroy),
149 					 NULL, NULL,
150 					 g_cclosure_marshal_VOID__VOID,
151 					 G_TYPE_NONE, 0);
152 	signals[SIG_GIVE_FOCUS] =
153 		g_signal_new("gained-focus",
154 					 G_TYPE_FROM_CLASS(klass),
155 					 G_SIGNAL_RUN_LAST,
156 					 G_STRUCT_OFFSET(GntWidgetClass, gained_focus),
157 					 NULL, NULL,
158 					 g_cclosure_marshal_VOID__VOID,
159 					 G_TYPE_NONE, 0);
160 	signals[SIG_LOST_FOCUS] =
161 		g_signal_new("lost-focus",
162 					 G_TYPE_FROM_CLASS(klass),
163 					 G_SIGNAL_RUN_LAST,
164 					 G_STRUCT_OFFSET(GntWidgetClass, lost_focus),
165 					 NULL, NULL,
166 					 g_cclosure_marshal_VOID__VOID,
167 					 G_TYPE_NONE, 0);
168 	signals[SIG_ACTIVATE] =
169 		g_signal_new("activate",
170 					 G_TYPE_FROM_CLASS(klass),
171 					 G_SIGNAL_RUN_LAST,
172 					 G_STRUCT_OFFSET(GntWidgetClass, activate),
173 					 NULL, NULL,
174 					 g_cclosure_marshal_VOID__VOID,
175 					 G_TYPE_NONE, 0);
176 	signals[SIG_MAP] =
177 		g_signal_new("map",
178 					 G_TYPE_FROM_CLASS(klass),
179 					 G_SIGNAL_RUN_LAST,
180 					 G_STRUCT_OFFSET(GntWidgetClass, map),
181 					 NULL, NULL,
182 					 g_cclosure_marshal_VOID__VOID,
183 					 G_TYPE_NONE, 0);
184 	signals[SIG_DRAW] =
185 		g_signal_new("draw",
186 					 G_TYPE_FROM_CLASS(klass),
187 					 G_SIGNAL_RUN_LAST,
188 					 G_STRUCT_OFFSET(GntWidgetClass, draw),
189 					 NULL, NULL,
190 					 g_cclosure_marshal_VOID__VOID,
191 					 G_TYPE_NONE, 0);
192 	signals[SIG_HIDE] =
193 		g_signal_new("hide",
194 					 G_TYPE_FROM_CLASS(klass),
195 					 G_SIGNAL_RUN_LAST,
196 					 G_STRUCT_OFFSET(GntWidgetClass, hide),
197 					 NULL, NULL,
198 					 g_cclosure_marshal_VOID__VOID,
199 					 G_TYPE_NONE, 0);
200 	signals[SIG_EXPOSE] =
201 		g_signal_new("expose",
202 					 G_TYPE_FROM_CLASS(klass),
203 					 G_SIGNAL_RUN_LAST,
204 					 G_STRUCT_OFFSET(GntWidgetClass, expose),
205 					 NULL, NULL,
206 					 gnt_closure_marshal_VOID__INT_INT_INT_INT,
207 					 G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
208 	signals[SIG_POSITION] =
209 		g_signal_new("position-set",
210 					 G_TYPE_FROM_CLASS(klass),
211 					 G_SIGNAL_RUN_LAST,
212 					 G_STRUCT_OFFSET(GntWidgetClass, set_position),
213 					 NULL, NULL,
214 					 gnt_closure_marshal_VOID__INT_INT,
215 					 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
216 	signals[SIG_SIZE_REQUEST] =
217 		g_signal_new("size_request",
218 					 G_TYPE_FROM_CLASS(klass),
219 					 G_SIGNAL_RUN_LAST,
220 					 G_STRUCT_OFFSET(GntWidgetClass, size_request),
221 					 NULL, NULL,
222 					 g_cclosure_marshal_VOID__VOID,
223 					 G_TYPE_NONE, 0);
224 	signals[SIG_SIZE_CHANGED] =
225 		g_signal_new("size_changed",
226 					 G_TYPE_FROM_CLASS(klass),
227 					 G_SIGNAL_RUN_LAST,
228 					 G_STRUCT_OFFSET(GntWidgetClass, size_changed),
229 					 NULL, NULL,
230 					 gnt_closure_marshal_VOID__INT_INT,
231 					 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
232 	signals[SIG_CONFIRM_SIZE] =
233 		g_signal_new("confirm_size",
234 					 G_TYPE_FROM_CLASS(klass),
235 					 G_SIGNAL_RUN_LAST,
236 					 G_STRUCT_OFFSET(GntWidgetClass, confirm_size),
237 					 NULL, NULL,
238 					 gnt_closure_marshal_BOOLEAN__INT_INT,
239 					 G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_INT);
240 	signals[SIG_KEY_PRESSED] =
241 		g_signal_new("key_pressed",
242 					 G_TYPE_FROM_CLASS(klass),
243 					 G_SIGNAL_RUN_LAST,
244 					 G_STRUCT_OFFSET(GntWidgetClass, key_pressed),
245 					 g_signal_accumulator_true_handled, NULL,
246 					 gnt_closure_marshal_BOOLEAN__STRING,
247 					 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
248 
249 	signals[SIG_CLICKED] =
250 		g_signal_new("clicked",
251 					 G_TYPE_FROM_CLASS(klass),
252 					 G_SIGNAL_RUN_LAST,
253 					 G_STRUCT_OFFSET(GntWidgetClass, clicked),
254 					 g_signal_accumulator_true_handled, NULL,
255 					 gnt_closure_marshal_BOOLEAN__INT_INT_INT,
256 					 G_TYPE_BOOLEAN, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
257 
258 	signals[SIG_CONTEXT_MENU] =
259 		g_signal_new("context-menu",
260 					 G_TYPE_FROM_CLASS(klass),
261 					 G_SIGNAL_RUN_LAST,
262 					 0,
263 					 g_signal_accumulator_true_handled, NULL,
264 					 gnt_closure_marshal_BOOLEAN__VOID,
265 					 G_TYPE_BOOLEAN, 0);
266 
267 	/* This is relevant for all widgets */
268 	gnt_bindable_class_register_action(GNT_BINDABLE_CLASS(klass), "context-menu", context_menu,
269 				GNT_KEY_POPUP, NULL);
270 	gnt_bindable_register_binding(GNT_BINDABLE_CLASS(klass), "context-menu", GNT_KEY_F11, NULL);
271 	gnt_bindable_register_binding(GNT_BINDABLE_CLASS(klass), "context-menu", GNT_KEY_CTRL_X, NULL);
272 
273 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
274 	GNTDEBUG;
275 }
276 
277 /******************************************************************************
278  * GntWidget API
279  *****************************************************************************/
280 GType
gnt_widget_get_gtype(void)281 gnt_widget_get_gtype(void)
282 {
283 	static GType type = 0;
284 
285 	if(type == 0) {
286 		static const GTypeInfo info = {
287 			sizeof(GntWidgetClass),
288 			NULL,					/* base_init		*/
289 			NULL,					/* base_finalize	*/
290 			(GClassInitFunc)gnt_widget_class_init,
291 			NULL,
292 			NULL,					/* class_data		*/
293 			sizeof(GntWidget),
294 			0,						/* n_preallocs		*/
295 			gnt_widget_init,					/* instance_init	*/
296 			NULL					/* value_table		*/
297 		};
298 
299 		type = g_type_register_static(GNT_TYPE_BINDABLE,
300 									  "GntWidget",
301 									  &info, G_TYPE_FLAG_ABSTRACT);
302 	}
303 
304 	return type;
305 }
306 
gnt_widget_set_take_focus(GntWidget * widget,gboolean can)307 void gnt_widget_set_take_focus(GntWidget *widget, gboolean can)
308 {
309 	if (can)
310 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS);
311 	else
312 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS);
313 }
314 
315 gboolean
gnt_widget_get_take_focus(GntWidget * widget)316 gnt_widget_get_take_focus(GntWidget *widget)
317 {
318 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
319 
320 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS);
321 }
322 
323 void
gnt_widget_destroy(GntWidget * obj)324 gnt_widget_destroy(GntWidget *obj)
325 {
326 	g_return_if_fail(GNT_IS_WIDGET(obj));
327 
328 	if (!gnt_widget_in_destruction(obj)) {
329 		GNT_WIDGET_SET_FLAGS(obj, GNT_WIDGET_DESTROYING);
330 		gnt_widget_hide(obj);
331 		g_clear_pointer(&obj->window, delwin);
332 		g_object_run_dispose(G_OBJECT(obj));
333 	}
334 	GNTDEBUG;
335 }
336 
337 void
gnt_widget_show(GntWidget * widget)338 gnt_widget_show(GntWidget *widget)
339 {
340 	g_return_if_fail(widget != NULL);
341 
342 	gnt_widget_draw(widget);
343 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
344 	gnt_screen_occupy(widget);
345 G_GNUC_END_IGNORE_DEPRECATIONS
346 }
347 
348 void
gnt_widget_draw(GntWidget * widget)349 gnt_widget_draw(GntWidget *widget)
350 {
351 	/* Draw the widget */
352 	if (gnt_widget_get_drawing(widget))
353 		return;
354 
355 	gnt_widget_set_drawing(widget, TRUE);
356 	if (!gnt_widget_get_mapped(widget)) {
357 		gnt_widget_map(widget);
358 	}
359 
360 	if (widget->window == NULL)
361 	{
362 #if 0
363 		int x, y, maxx, maxy, w, h;
364 		int oldw, oldh;
365 		gboolean shadow = TRUE;
366 
367 		if (!gnt_widget_has_shadow(widget))
368 			shadow = FALSE;
369 
370 		x = widget->priv.x;
371 		y = widget->priv.y;
372 		w = oldw = widget->priv.width + shadow;
373 		h = oldh = widget->priv.height + shadow;
374 
375 		getmaxyx(stdscr, maxy, maxx);
376 		maxy -= 1;		/* room for the taskbar */
377 
378 		x = MAX(0, x);
379 		y = MAX(0, y);
380 		if (x + w >= maxx)
381 			x = MAX(0, maxx - w);
382 		if (y + h >= maxy)
383 			y = MAX(0, maxy - h);
384 
385 		w = MIN(w, maxx);
386 		h = MIN(h, maxy);
387 
388 		widget->priv.x = x;
389 		widget->priv.y = y;
390 		if (w != oldw || h != oldh) {
391 			widget->priv.width = w - shadow;
392 			widget->priv.height = h - shadow;
393 			g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh);
394 		}
395 #else
396 		widget->window = newpad(widget->priv.height + 20, widget->priv.width + 20);  /* XXX: */
397 #endif
398 		init_widget(widget);
399 	}
400 
401 	g_signal_emit(widget, signals[SIG_DRAW], 0);
402 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
403 	gnt_widget_queue_update(widget);
404 G_GNUC_END_IGNORE_DEPRECATIONS
405 	gnt_widget_set_drawing(widget, FALSE);
406 }
407 
408 gboolean
gnt_widget_key_pressed(GntWidget * widget,const char * keys)409 gnt_widget_key_pressed(GntWidget *widget, const char *keys)
410 {
411 	gboolean ret;
412 	if (!gnt_widget_get_take_focus(widget))
413 		return FALSE;
414 
415 	if (!gnt_widget_get_disable_actions(widget) &&
416 	    gnt_bindable_perform_action_key(GNT_BINDABLE(widget), keys)) {
417 		return TRUE;
418 	}
419 
420 	keys = gnt_bindable_remap_keys(GNT_BINDABLE(widget), keys);
421 	g_signal_emit(widget, signals[SIG_KEY_PRESSED], 0, keys, &ret);
422 	return ret;
423 }
424 
425 gboolean
gnt_widget_clicked(GntWidget * widget,GntMouseEvent event,int x,int y)426 gnt_widget_clicked(GntWidget *widget, GntMouseEvent event, int x, int y)
427 {
428 	gboolean ret;
429 	g_signal_emit(widget, signals[SIG_CLICKED], 0, event, x, y, &ret);
430 	if (!ret && event == GNT_RIGHT_MOUSE_DOWN)
431 		ret = gnt_bindable_perform_action_named(GNT_BINDABLE(widget), "context-menu", NULL);
432 	return ret;
433 }
434 
435 void
gnt_widget_expose(GntWidget * widget,int x,int y,int width,int height)436 gnt_widget_expose(GntWidget *widget, int x, int y, int width, int height)
437 {
438 	g_signal_emit(widget, signals[SIG_EXPOSE], 0, x, y, width, height);
439 }
440 
441 void
gnt_widget_hide(GntWidget * widget)442 gnt_widget_hide(GntWidget *widget)
443 {
444 	g_signal_emit(widget, signals[SIG_HIDE], 0);
445 	if (widget->window) {
446 		wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_NORMAL));
447 	}
448 #if 0
449 	/* XXX: I have no clue why, but this seemed to be necessary. */
450 	if (gnt_widget_has_shadow(widget))
451 		mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height);
452 #endif
453 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
454 	gnt_screen_release(widget);
455 G_GNUC_END_IGNORE_DEPRECATIONS
456 	gnt_widget_set_visible(widget, FALSE);
457 	gnt_widget_set_mapped(widget, FALSE);
458 }
459 
460 GntWidget *
gnt_widget_get_parent(GntWidget * widget)461 gnt_widget_get_parent(GntWidget *widget)
462 {
463 	g_return_val_if_fail(GNT_IS_WIDGET(widget), NULL);
464 
465 	return widget->parent;
466 }
467 
468 GntWidget *
gnt_widget_get_toplevel(GntWidget * widget)469 gnt_widget_get_toplevel(GntWidget *widget)
470 {
471 	g_return_val_if_fail(GNT_IS_WIDGET(widget), NULL);
472 
473 	while (widget->parent) {
474 		widget = widget->parent;
475 	}
476 
477 	return widget;
478 }
479 
480 void
gnt_widget_set_position(GntWidget * wid,int x,int y)481 gnt_widget_set_position(GntWidget *wid, int x, int y)
482 {
483 	g_signal_emit(wid, signals[SIG_POSITION], 0, x, y);
484 	/* XXX: Need to install properties for these and g_object_notify */
485 	wid->priv.x = x;
486 	wid->priv.y = y;
487 }
488 
489 void
gnt_widget_get_position(GntWidget * wid,int * x,int * y)490 gnt_widget_get_position(GntWidget *wid, int *x, int *y)
491 {
492 	if (x)
493 		*x = wid->priv.x;
494 	if (y)
495 		*y = wid->priv.y;
496 }
497 
498 void
gnt_widget_size_request(GntWidget * widget)499 gnt_widget_size_request(GntWidget *widget)
500 {
501 	g_signal_emit(widget, signals[SIG_SIZE_REQUEST], 0);
502 }
503 
504 void
gnt_widget_get_size(GntWidget * wid,int * width,int * height)505 gnt_widget_get_size(GntWidget *wid, int *width, int *height)
506 {
507 	gboolean shadow = TRUE;
508 	if (!gnt_widget_has_shadow(wid))
509 		shadow = FALSE;
510 
511 	if (width)
512 		*width = wid->priv.width + shadow;
513 	if (height)
514 		*height = wid->priv.height + shadow;
515 }
516 
517 static void
init_widget(GntWidget * widget)518 init_widget(GntWidget *widget)
519 {
520 	gboolean shadow = TRUE;
521 
522 	if (!gnt_widget_has_shadow(widget))
523 		shadow = FALSE;
524 
525 	wbkgd(widget->window, gnt_color_pair(GNT_COLOR_NORMAL));
526 	werase(widget->window);
527 
528 	if (gnt_widget_get_has_border(widget)) {
529 		/* - This is ugly. */
530 		/* - What's your point? */
531 		mvwvline(widget->window, 0, 0, ACS_VLINE | gnt_color_pair(GNT_COLOR_NORMAL), widget->priv.height);
532 		mvwvline(widget->window, 0, widget->priv.width - 1,
533 				ACS_VLINE | gnt_color_pair(GNT_COLOR_NORMAL), widget->priv.height);
534 		mvwhline(widget->window, widget->priv.height - 1, 0,
535 				ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL), widget->priv.width);
536 		mvwhline(widget->window, 0, 0, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL), widget->priv.width);
537 		mvwaddch(widget->window, 0, 0, ACS_ULCORNER | gnt_color_pair(GNT_COLOR_NORMAL));
538 		mvwaddch(widget->window, 0, widget->priv.width - 1,
539 				ACS_URCORNER | gnt_color_pair(GNT_COLOR_NORMAL));
540 		mvwaddch(widget->window, widget->priv.height - 1, 0,
541 				ACS_LLCORNER | gnt_color_pair(GNT_COLOR_NORMAL));
542 		mvwaddch(widget->window, widget->priv.height - 1, widget->priv.width - 1,
543 				ACS_LRCORNER | gnt_color_pair(GNT_COLOR_NORMAL));
544 	}
545 
546 	if (shadow)
547 	{
548 		wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_SHADOW));
549 		mvwvline(widget->window, 1, widget->priv.width, ' ', widget->priv.height);
550 		mvwhline(widget->window, widget->priv.height, 1, ' ', widget->priv.width);
551 	}
552 }
553 
554 gboolean
gnt_widget_set_size(GntWidget * widget,int width,int height)555 gnt_widget_set_size(GntWidget *widget, int width, int height)
556 {
557 	gboolean ret = TRUE;
558 
559 	if (gnt_widget_has_shadow(widget))
560 	{
561 		width--;
562 		height--;
563 	}
564 	if (width <= 0)
565 		width = widget->priv.width;
566 	if (height <= 0)
567 		height = widget->priv.height;
568 
569 	if (gnt_widget_get_mapped(widget)) {
570 		ret = gnt_widget_confirm_size(widget, width, height);
571 	}
572 
573 	if (ret)
574 	{
575 		gboolean shadow = TRUE;
576 		int oldw, oldh;
577 
578 		if (!gnt_widget_has_shadow(widget))
579 			shadow = FALSE;
580 
581 		oldw = widget->priv.width;
582 		oldh = widget->priv.height;
583 
584 		widget->priv.width = width;
585 		widget->priv.height = height;
586 		if (width + shadow >= getmaxx(widget->window) || height + shadow >= getmaxy(widget->window)) {
587 			delwin(widget->window);
588 			widget->window = newpad(height + 20, width + 20);
589 		}
590 
591 		g_signal_emit(widget, signals[SIG_SIZE_CHANGED], 0, oldw, oldh);
592 
593 		if (widget->window)
594 		{
595 			init_widget(widget);
596 		}
597 		if (gnt_widget_get_mapped(widget)) {
598 			init_widget(widget);
599 		} else {
600 			gnt_widget_set_mapped(widget, TRUE);
601 		}
602 	}
603 
604 	return ret;
605 }
606 
607 gboolean
gnt_widget_set_focus(GntWidget * widget,gboolean set)608 gnt_widget_set_focus(GntWidget *widget, gboolean set)
609 {
610 	if (!gnt_widget_get_take_focus(widget))
611 		return FALSE;
612 
613 	if (set && !gnt_widget_get_has_focus(widget)) {
614 		gnt_widget_set_has_focus(widget, TRUE);
615 		g_signal_emit(widget, signals[SIG_GIVE_FOCUS], 0);
616 	} else if (!set && gnt_widget_get_has_focus(widget)) {
617 		gnt_widget_set_has_focus(widget, FALSE);
618 		g_signal_emit(widget, signals[SIG_LOST_FOCUS], 0);
619 	} else {
620 		return FALSE;
621 	}
622 
623 	return TRUE;
624 }
625 
gnt_widget_set_name(GntWidget * widget,const char * name)626 void gnt_widget_set_name(GntWidget *widget, const char *name)
627 {
628 	g_free(widget->priv.name);
629 	widget->priv.name = g_strdup(name);
630 }
631 
gnt_widget_get_name(GntWidget * widget)632 const char *gnt_widget_get_name(GntWidget *widget)
633 {
634 	return widget->priv.name;
635 }
636 
gnt_widget_activate(GntWidget * widget)637 void gnt_widget_activate(GntWidget *widget)
638 {
639 	g_signal_emit(widget, signals[SIG_ACTIVATE], 0);
640 }
641 
642 static gboolean
update_queue_callback(gpointer data)643 update_queue_callback(gpointer data)
644 {
645 	GntWidget *widget = GNT_WIDGET(data);
646 
647 	if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update"))
648 		return FALSE;
649 	if (gnt_widget_get_mapped(widget)) {
650 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
651 		gnt_screen_update(widget);
652 G_GNUC_END_IGNORE_DEPRECATIONS
653 	}
654 	g_object_set_data(G_OBJECT(widget), "gnt:queue_update", NULL);
655 	return FALSE;
656 }
657 
gnt_widget_queue_update(GntWidget * widget)658 void gnt_widget_queue_update(GntWidget *widget)
659 {
660 	if (widget->window == NULL)
661 		return;
662 	while (widget->parent)
663 		widget = widget->parent;
664 
665 	if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update"))
666 	{
667 		int id = g_timeout_add(0, update_queue_callback, widget);
668 		g_object_set_data_full(G_OBJECT(widget), "gnt:queue_update", GINT_TO_POINTER(id),
669 				(GDestroyNotify)g_source_remove);
670 	}
671 }
672 
gnt_widget_confirm_size(GntWidget * widget,int width,int height)673 gboolean gnt_widget_confirm_size(GntWidget *widget, int width, int height)
674 {
675 	gboolean ret = FALSE;
676 	g_signal_emit(widget, signals[SIG_CONFIRM_SIZE], 0, width, height, &ret);
677 	return ret;
678 }
679 
gnt_widget_set_visible(GntWidget * widget,gboolean set)680 void gnt_widget_set_visible(GntWidget *widget, gboolean set)
681 {
682 	if (set)
683 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_INVISIBLE);
684 	else
685 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_INVISIBLE);
686 }
687 
688 gboolean
gnt_widget_get_visible(GntWidget * widget)689 gnt_widget_get_visible(GntWidget *widget)
690 {
691 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
692 
693 	return !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_INVISIBLE);
694 }
695 
gnt_widget_has_shadow(GntWidget * widget)696 gboolean gnt_widget_has_shadow(GntWidget *widget)
697 {
698 	return (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_SHADOW) &&
699 			gnt_style_get_bool(GNT_STYLE_SHADOW, FALSE));
700 }
701 
702 gboolean
gnt_widget_in_destruction(GntWidget * widget)703 gnt_widget_in_destruction(GntWidget *widget)
704 {
705 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
706 
707 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DESTROYING);
708 }
709 
710 void
gnt_widget_set_drawing(GntWidget * widget,gboolean drawing)711 gnt_widget_set_drawing(GntWidget *widget, gboolean drawing)
712 {
713 	g_return_if_fail(GNT_IS_WIDGET(widget));
714 
715 	if (drawing) {
716 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DRAWING);
717 	} else {
718 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DRAWING);
719 	}
720 }
721 
722 gboolean
gnt_widget_get_drawing(GntWidget * widget)723 gnt_widget_get_drawing(GntWidget *widget)
724 {
725 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
726 
727 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DRAWING);
728 }
729 
730 void
gnt_widget_set_mapped(GntWidget * widget,gboolean mapped)731 gnt_widget_set_mapped(GntWidget *widget, gboolean mapped)
732 {
733 	g_return_if_fail(GNT_IS_WIDGET(widget));
734 
735 	if (mapped) {
736 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_MAPPED);
737 	} else {
738 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_MAPPED);
739 	}
740 }
741 
742 gboolean
gnt_widget_get_mapped(GntWidget * widget)743 gnt_widget_get_mapped(GntWidget *widget)
744 {
745 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
746 
747 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_MAPPED);
748 }
749 
750 void
gnt_widget_set_has_border(GntWidget * widget,gboolean has_border)751 gnt_widget_set_has_border(GntWidget *widget, gboolean has_border)
752 {
753 	g_return_if_fail(GNT_IS_WIDGET(widget));
754 
755 	if (has_border) {
756 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER);
757 	} else {
758 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER);
759 	}
760 }
761 
762 gboolean
gnt_widget_get_has_border(GntWidget * widget)763 gnt_widget_get_has_border(GntWidget *widget)
764 {
765 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
766 
767 	return !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER);
768 }
769 
770 void
gnt_widget_set_has_shadow(GntWidget * widget,gboolean has_shadow)771 gnt_widget_set_has_shadow(GntWidget *widget, gboolean has_shadow)
772 {
773 	g_return_if_fail(GNT_IS_WIDGET(widget));
774 
775 	if (has_shadow) {
776 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_SHADOW);
777 	} else {
778 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_SHADOW);
779 	}
780 }
781 
782 gboolean
gnt_widget_get_has_shadow(GntWidget * widget)783 gnt_widget_get_has_shadow(GntWidget *widget)
784 {
785 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
786 
787 	return !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_SHADOW);
788 }
789 
790 void
gnt_widget_set_has_focus(GntWidget * widget,gboolean has_focus)791 gnt_widget_set_has_focus(GntWidget *widget, gboolean has_focus)
792 {
793 	g_return_if_fail(GNT_IS_WIDGET(widget));
794 
795 	if (has_focus) {
796 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS);
797 	} else {
798 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS);
799 	}
800 }
801 
802 gboolean
gnt_widget_get_has_focus(GntWidget * widget)803 gnt_widget_get_has_focus(GntWidget *widget)
804 {
805 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
806 
807 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_HAS_FOCUS);
808 }
809 
810 void
gnt_widget_set_is_urgent(GntWidget * widget,gboolean urgent)811 gnt_widget_set_is_urgent(GntWidget *widget, gboolean urgent)
812 {
813 	g_return_if_fail(GNT_IS_WIDGET(widget));
814 
815 	if (urgent) {
816 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_URGENT);
817 	} else {
818 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_URGENT);
819 	}
820 }
821 
822 gboolean
gnt_widget_get_is_urgent(GntWidget * widget)823 gnt_widget_get_is_urgent(GntWidget *widget)
824 {
825 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
826 
827 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_URGENT);
828 }
829 
830 void
gnt_widget_set_grow_x(GntWidget * widget,gboolean grow_x)831 gnt_widget_set_grow_x(GntWidget *widget, gboolean grow_x)
832 {
833 	g_return_if_fail(GNT_IS_WIDGET(widget));
834 
835 	if (grow_x) {
836 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X);
837 	} else {
838 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_GROW_X);
839 	}
840 }
841 
842 gboolean
gnt_widget_get_grow_x(GntWidget * widget)843 gnt_widget_get_grow_x(GntWidget *widget)
844 {
845 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
846 
847 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_X);
848 }
849 
850 void
gnt_widget_set_grow_y(GntWidget * widget,gboolean grow_y)851 gnt_widget_set_grow_y(GntWidget *widget, gboolean grow_y)
852 {
853 	g_return_if_fail(GNT_IS_WIDGET(widget));
854 
855 	if (grow_y) {
856 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_Y);
857 	} else {
858 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_GROW_Y);
859 	}
860 }
861 
862 gboolean
gnt_widget_get_grow_y(GntWidget * widget)863 gnt_widget_get_grow_y(GntWidget *widget)
864 {
865 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
866 
867 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_GROW_Y);
868 }
869 
870 void
gnt_widget_set_transient(GntWidget * widget,gboolean transient)871 gnt_widget_set_transient(GntWidget *widget, gboolean transient)
872 {
873 	g_return_if_fail(GNT_IS_WIDGET(widget));
874 
875 	if (transient) {
876 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_TRANSIENT);
877 	} else {
878 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_TRANSIENT);
879 	}
880 }
881 
882 gboolean
gnt_widget_get_transient(GntWidget * widget)883 gnt_widget_get_transient(GntWidget *widget)
884 {
885 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
886 
887 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT);
888 }
889 
890 void
gnt_widget_set_disable_actions(GntWidget * widget,gboolean disable_actions)891 gnt_widget_set_disable_actions(GntWidget *widget, gboolean disable_actions)
892 {
893 	g_return_if_fail(GNT_IS_WIDGET(widget));
894 
895 	if (disable_actions) {
896 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DISABLE_ACTIONS);
897 	} else {
898 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DISABLE_ACTIONS);
899 	}
900 }
901 
902 gboolean
gnt_widget_get_disable_actions(GntWidget * widget)903 gnt_widget_get_disable_actions(GntWidget *widget)
904 {
905 	g_return_val_if_fail(GNT_IS_WIDGET(widget), FALSE);
906 
907 	return GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DISABLE_ACTIONS);
908 }
909