1 /*
2  * (SLIK) SimpLIstic sKin functions
3  * (C) 2005 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11 
12 #include "ui2_includes.h"
13 #include "ui2_typedefs.h"
14 #include "ui2_display.h"
15 
16 #include "ui2_main.h"
17 #include "ui2_skin.h"
18 #include "ui2_tooltip.h"
19 #include "ui2_util.h"
20 #include "ui2_widget.h"
21 #include "ui_pixbuf_ops.h"
22 
23 #include <gdk/gdkkeysyms.h> /* for key values */
24 
25 #include <math.h>
26 
27 
28 /*
29  *-----------------------------------------------------------------------------
30  * Screen refreshing
31  *-----------------------------------------------------------------------------
32  */
33 
34 /* ok, so the freeze is ugly, but does help when first loading a skin */
35 
ui_display_render_freeze(UIData * ui)36 static void ui_display_render_freeze(UIData *ui)
37 {
38 	ui->frozen = TRUE;
39 }
40 
ui_display_render_thaw(UIData * ui)41 static void ui_display_render_thaw(UIData *ui)
42 {
43 	ui->frozen = FALSE;
44 }
45 
ui_display_render_area(UIData * ui,gint x,gint y,gint w,gint h,WidgetData * wd)46 void ui_display_render_area(UIData *ui, gint x, gint y, gint w, gint h, WidgetData *wd)
47 {
48 	GdkPixbuf *pixbuf;
49 	GdkPixmap *pixmap;
50 
51 	if (ui->frozen) return;
52 	if (w < 1 || h < 1) return;
53 
54 	pixbuf = skin_get_pixbuf(ui->skin);
55 	pixmap = skin_get_buffer(ui->skin);
56 
57 	if (!pixbuf || !pixmap || !ui->display->window) return;
58 
59 	if (wd && wd == ui->focus_widget && (slik_focus_enable || ui->focus_enable) &&
60 	    GTK_WIDGET_HAS_FOCUS(ui->display))
61 		{
62 		gint wx, wy, ww, wh;
63 		if (!ui_widget_focus_draw(ui, wd, x, y, w, h) &&
64 		    ui_widget_get_geometry(wd, &wx, &wy, &ww, &wh))
65 			{
66 			ui_display_draw_focus(ui, pixbuf, wx, wy, ww, wh, x, y, w, h, NULL);
67 			}
68 		}
69 
70 	if (debug_mode) printf("render: %d, %d (%d x %d)\n", x, y, w, h);
71 
72 	gdk_draw_pixbuf(pixmap, ui->display->style->fg_gc[GTK_WIDGET_STATE(ui->display)],
73 			pixbuf,
74 			x, y, x, y, w, h,
75 			GDK_RGB_DITHER_NONE, 1, 1); /* FIXME: no dithering */
76 
77 	gdk_draw_drawable(ui->display->window, ui->display->style->fg_gc[GTK_WIDGET_STATE(ui->display)],
78 			  pixmap, x, y, x, y, w, h);
79 }
80 
ui_display_redraw_area(UIData * ui,gint x,gint y,gint w,gint h,gint update)81 void ui_display_redraw_area(UIData *ui, gint x, gint y, gint w, gint h, gint update)
82 {
83 	GList *work;
84 
85 	pixbuf_copy_area(ui->skin->overlay, x, y,
86 			 ui->skin->pixbuf, x, y, w, h, FALSE);
87 	ui_display_render_freeze(ui);
88 
89 	work = ui->skin->widget_list;
90 	while(work)
91 		{
92 		WidgetData *wd = work->data;
93 		if (ui_widget_contacts_area(wd, x, y, w, h))
94 			{
95 			ui_widget_draw(ui, wd, update, TRUE);
96 			}
97 		work = work->next;
98 		}
99 
100 	ui_display_render_thaw(ui);
101 	ui_display_render_area(ui, x, y, w, h, ui->focus_widget);
102 }
103 
ui_display_draw_focus(UIData * ui,GdkPixbuf * pixbuf,gint x,gint y,gint w,gint h,gint clip_x,gint clip_y,gint clip_w,gint clip_h,GdkPixbuf * clip_pb)104 void ui_display_draw_focus(UIData *ui, GdkPixbuf *pixbuf, gint x, gint y, gint w, gint h,
105 			   gint clip_x, gint clip_y, gint clip_w, gint clip_h, GdkPixbuf *clip_pb)
106 {
107 	gint rx, ry, rw, rh;
108 	SkinData *skin;
109 
110 	if (!util_clip_region(x, y, w, h,
111 			      clip_x, clip_y, clip_w, clip_h,
112 			      &rx, &ry, &rw, &rh)) return;
113 
114 	skin = ui->skin;
115 
116 	if (skin->focus_overlay)
117 		{
118 		if (skin->focus_has_border)
119 			{
120 			util_pixbuf_copy_border_clipped(skin->focus_overlay,
121 							skin->focus_border_left, skin->focus_border_right,
122 							skin->focus_border_top, skin->focus_border_bottom,
123 							pixbuf, x, y, w, h,
124 							clip_x, clip_y, clip_w, clip_h,
125 							skin->focus_box_alpha);
126 			}
127 		else
128 			{
129 			gint fx, fy, fw, fh;
130 			gint bx, by, bw, bh;
131 
132 			fw = gdk_pixbuf_get_width(skin->focus_overlay);
133 			fh = gdk_pixbuf_get_height(skin->focus_overlay);
134 
135 			fx = (skin->focus_anchor_right) ? MAX((x + w - fw), 0) : x;
136 			fy = (skin->focus_anchor_bottom) ? MAX((y + h - fh), 0) : y;
137 
138 			if (util_clip_region(rx, ry, rw, rh, fx, fy, fw, fh,
139 					     &bx, &by, &bw, &bh))
140 				{
141 				pixbuf_copy_area_alpha(skin->focus_overlay, 0, 0,
142 						       pixbuf, bx, by, bw, bh, skin->focus_box_alpha);
143 				}
144 			}
145 		}
146 	else
147 		{
148 		guint8 r, g, b, a;
149 
150 		r = skin->focus_box_r;
151 		g = skin->focus_box_g;
152 		b = skin->focus_box_b;
153 		a = skin->focus_box_alpha;
154 
155 		if (skin->focus_box_filled)
156 			{
157 			/* filled */
158 			pixbuf_draw_rect_fill(pixbuf, rx, ry, rw, rh, r, g, b, a);
159 			}
160 		else
161 			{
162 			gint bx, by, bw, bh;
163 			if (util_clip_region(rx, ry, rw, rh, x, y, w, 2,
164 					     &bx, &by, &bw, &bh))
165 				{
166 				pixbuf_draw_rect_fill(pixbuf, bx, by, bw, bh, r, g, b, a);
167 				}
168 			if (util_clip_region(rx, ry, rw, rh, x, y + h - 2, w, 2,
169 					     &bx, &by, &bw, &bh))
170 				{
171 				pixbuf_draw_rect_fill(pixbuf, bx, by, bw, bh, r, g, b, a);
172 				}
173 			if (util_clip_region(rx, ry, rw, rh, x, y + 2, 2, h - 4,
174 					     &bx, &by, &bw, &bh))
175 				{
176 				pixbuf_draw_rect_fill(pixbuf, bx, by, bw, bh, r, g, b, a);
177 				}
178 			if (util_clip_region(rx, ry, rw, rh, x + w - 2, y + 2, 2, h - 4,
179 					     &bx, &by, &bw, &bh))
180 				{
181 				pixbuf_draw_rect_fill(pixbuf, bx, by, bw, bh, r, g, b, a);
182 				}
183 			}
184 		}
185 }
186 
187 /*
188  *-----------------------------------------------------------------------------
189  * misc
190  *-----------------------------------------------------------------------------
191  */
192 
ui_display_sync_shape(UIData * ui)193 void ui_display_sync_shape(UIData *ui)
194 {
195 	if (!ui->skin) return;
196 
197 	if (ui->window)
198 		{
199 		if (slik_allow_shapes)
200 			{
201 			gtk_widget_shape_combine_mask(ui->window, ui->skin->mask_buffer, 0, 0);
202 			}
203 		gtk_widget_set_size_request(ui->display, ui->skin->width, ui->skin->height);
204 		gtk_window_resize(GTK_WINDOW(ui->window), ui->skin->width, ui->skin->height);
205 
206 		/* wonder why this is here? Try removing it and changing skin to a new size */
207 		gdk_window_resize(ui->display->window, ui->skin->width, ui->skin->height);
208 		gdk_window_resize(ui->window->window, ui->skin->width, ui->skin->height);
209 		}
210 	else
211 		{
212 		if (slik_allow_shapes)
213 			{
214 			gtk_widget_shape_combine_mask(ui->display, ui->skin->mask_buffer, 0, 0);
215 			}
216 		gtk_widget_set_size_request(ui->display, ui->skin->width, ui->skin->height);
217 		}
218 }
219 
ui_display_draw_all(UIData * ui,gint update,gint force)220 void ui_display_draw_all(UIData *ui, gint update, gint force)
221 {
222 	GList *work;
223 
224 	if (!ui->skin) return;
225 
226 	work = ui->skin->widget_list;
227 	while(work)
228 		{
229 		ui_widget_draw(ui, work->data, update, force);
230 		work = work->next;
231 		}
232 }
233 
ui_display_sync(UIData * ui,gint update)234 void ui_display_sync(UIData *ui, gint update)
235 {
236 	if (!ui->skin) return;
237 
238 	ui_display_render_freeze(ui);
239 	ui_display_draw_all(ui, update, TRUE);
240 	ui_display_render_thaw(ui);
241 
242 	/* do it all at once */
243 	ui_display_render_area(ui, 0, 0, ui->skin->width, ui->skin->height, ui->focus_widget);
244 }
245 
ui_display_sync_all(UIData * ui)246 void ui_display_sync_all(UIData *ui)
247 {
248 	if (!ui->skin) return;
249 
250 	skin_check_bounds(ui->skin);
251 
252 	skin_sync_buffer(ui->skin, ui);
253 	ui_display_sync_shape(ui);
254 
255 	ui_display_sync(ui, TRUE);
256 }
257 
ui_display_expose(GtkWidget * widget,GdkEventExpose * event,gpointer data)258 static void ui_display_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
259 {
260 	UIData *ui = data;
261 	GdkPixmap *pixmap;
262 
263 	pixmap = skin_get_buffer(ui->skin);
264 	if (!pixmap) return;
265 
266 	gdk_draw_drawable(ui->display->window, ui->display->style->fg_gc[GTK_WIDGET_STATE(ui->display)],
267 			  pixmap,
268 			  (gint)event->area.x, (gint)event->area.y,
269 			  (gint)event->area.x, (gint)event->area.y,
270 			  (gint)event->area.width, (gint)event->area.height);
271 }
272 
ui_display_move_idle_cb(gpointer data)273 static gint ui_display_move_idle_cb(gpointer data)
274 {
275 	UIData *ui = data;
276 
277 	skin_sync_back(ui->skin, ui);
278 	ui_display_sync(ui, FALSE);
279 
280 	ui->root_win_idle = -1;
281 
282 	return FALSE;
283 }
284 
ui_display_move(GtkWidget * widget,GdkEventConfigure * event,gpointer data)285 static void ui_display_move(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
286 {
287 	UIData *ui = data;
288 
289 	if (debug_mode) printf("move event\n");
290 
291 	if (ui->root_win_idle == -1 &&
292 	    (ui->skin->transparent || slik_transparency_force))
293 		{
294 		ui->root_win_idle = g_idle_add(ui_display_move_idle_cb, ui);
295 		}
296 }
297 
298 /*
299  *-----------------------------------------------------------------------------
300  * Focus (keyboard stuff)
301  *-----------------------------------------------------------------------------
302  */
303 
304 typedef enum {
305 	UI_FOCUS_NONE = 0,
306 	UI_FOCUS_LEFT,
307 	UI_FOCUS_UP,
308 	UI_FOCUS_RIGHT,
309 	UI_FOCUS_DOWN,
310 	UI_FOCUS_TAB_FORWARD,
311 	UI_FOCUS_TAB_BACKWARD
312 } UIMoveFocusType;
313 
314 #define DIST(x, y) (sqrt(x * x + y * y))
315 
ui_display_focus_nearest(UIData * ui,gint x,gint y)316 static WidgetData *ui_display_focus_nearest(UIData *ui, gint x, gint y)
317 {
318 	WidgetData *wd = NULL;
319 	gint dx, dy;
320 	GList *work;
321 
322 	if (!slik_focus_enable && !ui->focus_enable) return NULL;
323 
324 	dx = ui->skin->width;
325 	dy = ui->skin->height;
326 
327 	work = ui->skin->widget_list;
328 	while (work)
329 		{
330 		WidgetData *tmp;
331 		gint tx, ty, tw, th;
332 
333 		tmp = work->data;
334 		work = work->next;
335 		if (ui_widget_can_focus(tmp) &&
336 		    ui_widget_get_geometry(tmp, &tx, &ty, &tw, &th))
337 			{
338 			tx = tx + (tw / 2);
339 			ty = ty + (th / 2);
340 			if (DIST((x - tx), (y - ty)) < DIST(dx, dy))
341 				{
342 				dx = abs(x - tx);
343 				dy = abs(y - ty);
344 				wd = tmp;
345 				}
346 			}
347 		}
348 
349 	return wd;
350 }
351 
ui_display_focus_nearest_clipped(UIData * ui,WidgetData * current,gint clip_x,gint clip_y,gint clip_w,gint clip_h)352 static WidgetData *ui_display_focus_nearest_clipped(UIData *ui, WidgetData *current,
353 						    gint clip_x, gint clip_y, gint clip_w, gint clip_h)
354 {
355 	WidgetData *wd = NULL;
356 	gint cx, cy, cw, ch;
357 
358 	if (current && ui_widget_get_geometry(current, &cx, &cy, &cw, &ch))
359 		{
360 		gint dx, dy;
361 		gint px, py;
362 		GList *work;
363 
364 		px = cx + (cw / 2);
365 		py = cy + (ch / 2);
366 
367 		dx = ui->skin->width;
368 		dy = ui->skin->height;
369 
370 		work = ui->skin->widget_list;
371 		while (work)
372 			{
373 			WidgetData *tmp;
374 			gint x, y, w, h;
375 
376 			tmp = work->data;
377 			work = work->next;
378 			if (current != tmp && ui_widget_can_focus(tmp) &&
379 			    ui_widget_get_geometry(tmp, &x, &y, &w, &h))
380 				{
381 				gint dmy;
382 				if (util_clip_region(clip_x, clip_y, clip_w, clip_h,
383 						     x, y, w, h, &dmy, &dmy, &dmy, &dmy))
384 					{
385 					gint tx, ty;
386 					gint ax, ay;
387 
388 					tx = x + (w / 2);
389 					ty = y + (h / 2);
390 
391 					ax = abs(tx - px);
392 					ay = abs(ty - py);
393 
394 					if (DIST(ax, ay) < DIST(dx, dy))
395 						{
396 						dy = ay;
397 						dx = ax;
398 						wd = tmp;
399 						}
400 					}
401 				}
402 			}
403 		}
404 
405 	return wd;
406 }
407 
ui_display_focus_find(UIData * ui,WidgetData * current,gint x_dir,gint y_dir)408 static WidgetData *ui_display_focus_find(UIData *ui, WidgetData *current, gint x_dir, gint y_dir)
409 {
410 	WidgetData *wd = NULL;
411 	gint cx, cy, cw, ch;
412 
413 	if (!slik_focus_enable && !ui->focus_enable) return NULL;
414 
415 	if (x_dir == 0 && y_dir == 0) return current;
416 
417 	if (current && ui_widget_get_geometry(current, &cx, &cy, &cw, &ch))
418 		{
419 		/* create a region that we are (trying to) move into */
420 		if (x_dir < 0)
421 			{
422 			cw = cx - 1;
423 			cx = 0;
424 			}
425 		else if (x_dir > 0)
426 			{
427 			cx += cw + 1;
428 			cw = ui->skin->width - cx;
429 			}
430 		if (y_dir < 0)
431 			{
432 			ch = cy - 1;
433 			cy = 0;
434 			}
435 		else if (y_dir > 0)
436 			{
437 			cy += ch + 1;
438 			ch = ui->skin->height - cy;
439 			}
440 
441 		wd = ui_display_focus_nearest_clipped(ui, current, cx, cy, cw, ch);
442 
443 		if (!wd)
444 			{
445 			/* try it all again, this time with a broader range */
446 			if (x_dir != 0)
447 				{
448 				cy = 0;
449 				ch = ui->skin->height;
450 				}
451 			if (y_dir != 0)
452 				{
453 				cx = 0;
454 				cw = ui->skin->width;
455 				}
456 
457 			wd = ui_display_focus_nearest_clipped(ui, current, cx, cy, cw, ch);
458 			}
459 
460 		}
461 	else
462 		{
463 		wd = ui_display_focus_nearest(ui, 0, 0);
464 		}
465 
466 	if (!wd) wd = current;
467 
468 	return wd;
469 }
470 
ui_display_focus_next(UIData * ui,WidgetData * current,gint forward)471 static WidgetData *ui_display_focus_next(UIData *ui, WidgetData *current, gint forward)
472 {
473 	GList *start = NULL;
474 	GList *work;
475 
476 	if (current)
477 		{
478 		start = g_list_find(ui->skin->widget_list, current);
479 		}
480 	if (!start)
481 		{
482 		if (forward)
483 			{
484 			start = ui->skin->widget_list;
485 			}
486 		else
487 			{
488 			start = g_list_last(ui->skin->widget_list);
489 			}
490 		}
491 	if (!start) return current;
492 
493 	if (forward)
494 		{
495 		work = start->next;
496 		}
497 	else
498 		{
499 		work = start->prev;
500 		}
501 
502 	while (work)
503 		{
504 		WidgetData *wd;
505 
506 		wd = work->data;
507 		if (current != wd && ui_widget_can_focus(wd)) return wd;
508 
509 		if (forward)
510 			{
511 			work = work->next;
512 			}
513 		else
514 			{
515 			work = work->prev;
516 			}
517 		}
518 
519 	return current;
520 }
521 
ui_display_focus_clear(UIData * ui)522 static void ui_display_focus_clear(UIData *ui)
523 {
524 	if (ui->focus_widget)
525 		{
526 		gint x, y, w, h;
527 
528 		if (ui_widget_get_geometry(ui->focus_widget, &x, &y, &w, &h))
529 			{
530 			ui->focus_widget = NULL;
531 			ui_display_redraw_area(ui, x, y, w, h, FALSE);
532 			}
533 		else
534 			{
535 			ui->focus_widget = NULL;
536 			}
537 		}
538 }
539 
540 
ui_display_focus_move(UIData * ui,UIMoveFocusType focus)541 static gint ui_display_focus_move(UIData *ui, UIMoveFocusType focus)
542 {
543 	WidgetData *new_widget;
544 	gint x, y, w, h;
545 
546 	if (!slik_focus_enable && !ui->focus_enable) return FALSE;
547 
548 	new_widget = NULL;
549 	switch (focus)
550 		{
551 		case UI_FOCUS_LEFT:
552 			new_widget = ui_display_focus_find(ui, ui->focus_widget, -1, 0);
553 			break;
554 		case UI_FOCUS_UP:
555 			new_widget = ui_display_focus_find(ui, ui->focus_widget, 0, -1);
556 			break;
557 		case UI_FOCUS_RIGHT:
558 			new_widget = ui_display_focus_find(ui, ui->focus_widget, 1, 0);
559 			break;
560 		case UI_FOCUS_DOWN:
561 			new_widget = ui_display_focus_find(ui, ui->focus_widget, 0, 1);
562 			break;
563 		case UI_FOCUS_TAB_FORWARD:
564 			new_widget = ui_display_focus_next(ui, ui->focus_widget, TRUE);
565 			break;
566 		case UI_FOCUS_TAB_BACKWARD:
567 			new_widget = ui_display_focus_next(ui, ui->focus_widget, FALSE);
568 			break;
569 		case UI_FOCUS_NONE:
570 		default:
571 			break;
572 		}
573 
574 	if (new_widget == ui->focus_widget) return FALSE;
575 
576 	ui_display_focus_clear(ui);
577 
578 	ui->focus_widget = new_widget;
579 	if (new_widget &&
580 	    ui_widget_get_geometry(new_widget, &x, &y, &w, &h))
581 		{
582 		ui_display_render_area(ui, x, y, w, h, new_widget);
583 
584 		if (ui->tooltips_enable)
585 			{
586 			const gchar *message;
587 
588 			message = ui_tooltip_get(ui, new_widget->key, new_widget->type);
589 			ui_tooltip_show(ui, new_widget, message);
590 			}
591 		}
592 
593 	return TRUE;
594 }
595 
ui_display_key_press(GtkWidget * w,GdkEventKey * event,gpointer data)596 static gint ui_display_key_press(GtkWidget *w, GdkEventKey *event, gpointer data)
597 {
598 	UIData *ui = data;
599 	gint ret = FALSE;
600 
601 	if (!ui->skin) return FALSE;
602 
603 	ui_tooltip_show(ui, NULL, NULL);
604 
605 	/* pop up menus should work _always_, so test before poss. bail out */
606 	if (event->keyval == GDK_F10 ||
607 	    event->keyval == GDK_Menu)
608 		{
609 		if (ui->click_func)
610 			{
611 			/* hmm, perhaps the function table needs a menu callback
612 			 * instead of synthesizing a button 3 press ?
613 			 */
614 			ui->click_func(ui, 3, event->time, ui->click_data);
615 			}
616 		return TRUE;
617 		}
618 
619 	if (!slik_focus_enable && !ui->focus_enable) return FALSE;
620 
621 	if (ui->active_widget) return FALSE;
622 
623 	if (ui->focus_widget &&
624 	    ui_widget_focus_key_event(ui, ui->focus_widget, event))
625 		{
626 		ret = TRUE;
627 		}
628 	else
629 		{
630 		switch (event->keyval)
631 			{
632 			case GDK_Left: case GDK_KP_Left:
633 				ret = ui_display_focus_move(ui, UI_FOCUS_LEFT);
634 				break;
635 			case GDK_Right: case GDK_KP_Right:
636 				ret = ui_display_focus_move(ui, UI_FOCUS_RIGHT);
637 				break;
638 			case GDK_Up: case GDK_KP_Up:
639 				ret = ui_display_focus_move(ui, UI_FOCUS_UP);
640 				break;
641 			case GDK_Down: case GDK_KP_Down:
642 				ret = ui_display_focus_move(ui, UI_FOCUS_DOWN);
643 				break;
644 			case GDK_ISO_Left_Tab:
645 				ret = ui_display_focus_move(ui, UI_FOCUS_TAB_BACKWARD);
646 				break;
647 			case GDK_Tab:
648 				ret = ui_display_focus_move(ui, UI_FOCUS_TAB_FORWARD);
649 				break;
650 			default:
651 				break;
652 			}
653 		}
654 
655 #if 0
656 	if (ret) gtk_signal_emit_stop_by_name(GTK_OBJECT(w), "key_press_event");
657 #endif
658 
659 	return ret;
660 }
661 
ui_display_scrolled(GtkWidget * widget,GdkEventScroll * event,gpointer data)662 static gint ui_display_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer data)
663 {
664 	UIData *ui = data;
665 	gint button = -1;
666 
667 	if (event->direction == GDK_SCROLL_UP)
668 		{
669 		button = 4;
670 		}
671 	else if (event->direction == GDK_SCROLL_DOWN)
672 		{
673 		button = 5;
674 		}
675 
676 	if (ui->click_func && button > 0)
677 		{
678 		ui->click_func(ui, button, event->time, ui->click_data);
679 		}
680 
681 	return TRUE;
682 }
683 
ui_display_focus_in(GtkWidget * widget,GdkEventFocus * event,gpointer data)684 static gint ui_display_focus_in(GtkWidget *widget, GdkEventFocus *event, gpointer data)
685 {
686 	UIData *ui = data;
687 
688 	GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
689 
690 	if (!ui->skin || (!slik_focus_enable && !ui->focus_enable)) return FALSE;
691 
692 	if (!ui->focus_widget) ui->focus_widget = ui_display_focus_next(ui, NULL, TRUE);
693 	if (ui->focus_widget)
694 		{
695 		gint x, y, w, h;
696 
697 		if (ui_widget_get_geometry(ui->focus_widget, &x, &y, &w, &h))
698 			{
699 			ui_display_render_area(ui, x, y, w, h, ui->focus_widget);
700 			}
701 		}
702 
703 	return FALSE;
704 }
705 
ui_display_focus_out(GtkWidget * widget,GdkEventFocus * event,gpointer data)706 static gint ui_display_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer data)
707 {
708 	UIData *ui = data;
709 
710 	GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
711 
712 	ui_tooltip_show(ui, NULL, NULL);
713 
714 	if (!ui->skin || (!slik_focus_enable && !ui->focus_enable)) return FALSE;
715 
716 	if (ui->focus_widget)
717 		{
718 		gint x, y, w, h;
719 
720 		if (ui_widget_get_geometry(ui->focus_widget, &x, &y, &w, &h))
721 			{
722 			ui_display_redraw_area(ui, x, y, w, h, FALSE);
723 			}
724 		}
725 
726 	return FALSE;
727 }
728 
729 /*
730  *-----------------------------------------------------------------------------
731  * Button motion / press handling
732  *-----------------------------------------------------------------------------
733  */
734 
ui_display_motion(GtkWidget * w,GdkEventMotion * event,gpointer data)735 static gint ui_display_motion(GtkWidget *w, GdkEventMotion *event, gpointer data)
736 {
737 	UIData *ui = data;
738 	gint x = (gint)event->x;
739 	gint y = (gint)event->y;
740 	GList *work;
741 	gint tip_updated = FALSE;
742 
743 	if (debug_skin) printf("motion:%d x %d\n", x, y);
744 
745 	if (!ui->skin) return FALSE;
746 
747 	if (ui->active_widget)
748 		{
749 		ui_widget_motion(ui, ui->active_widget, x, y);
750 		return FALSE;
751 		}
752 
753 	if (ui->in_move)
754 		{
755 		GdkModifierType modmask;
756 		gint px, py;
757 
758 		if (!ui->window) return FALSE;
759 
760 		gdk_window_get_pointer (NULL, &px, &py, &modmask);
761 		px -= ui->press_x;
762 		py -= ui->press_y;
763 		if (slik_smart_placement &&
764 		    !(event->state & GDK_SHIFT_MASK))
765 			{
766 			gint w = gdk_screen_width();
767 			gint h = gdk_screen_height();
768 			if (px < 8 && px > -8) px = 0;
769 			if (py < 8 && py > -8) py = 0;
770 			if (px + ui->skin->width > w - 8 && px + ui->skin->width < w + 8) px = w - ui->skin->width;
771 			if (py + ui->skin->height > h - 8 && py + ui->skin->height < h +8) py = h - ui->skin->height;
772 			}
773 		gdk_window_move(ui->window->window, px, py);
774 		return TRUE;
775 		}
776 
777 	work = ui->skin->widget_list;
778 	while (work)
779 		{
780 		WidgetData *wd = work->data;
781 		gint wx, wy, ww, wh;
782 
783 		ui_widget_motion(ui, work->data, x, y);
784 
785 		if (ui->tooltips_enable &&
786 		    !tip_updated &&
787 		    wd->od && wd->od->is_visible && ui_widget_get_geometry(wd, &wx, &wy, &ww, &wh) &&
788 		    x >= wx && x <= wx+ww && y >= wy && y <= wy+wh)
789 			{
790 			const gchar *message;
791 
792 			message = ui_tooltip_get(ui, wd->key, wd->type);
793 			if (message)
794 				{
795 				ui_tooltip_show(ui, wd, message);
796 				tip_updated = TRUE;
797 				}
798 			}
799 
800 		work = work->next;
801 		}
802 
803 	if (ui->tooltips_enable && !tip_updated) ui_tooltip_show(ui, NULL, NULL);
804 
805 	return FALSE;
806 }
807 
ui_display_pressed(GtkWidget * w,GdkEventButton * event,gpointer data)808 static gint ui_display_pressed(GtkWidget *w, GdkEventButton *event, gpointer data)
809 {
810 	UIData *ui = data;
811 	GdkModifierType modmask;
812 	gint x = (gint)event->x;
813 	gint y = (gint)event->y;
814 	GList *work;
815 
816 	if (debug_mode) printf("pressed:%d x %d, %d\n", x, y, event->button);
817 
818 	if (!ui->skin) return FALSE;
819 
820 	ui_tooltip_show(ui, NULL, NULL);
821 
822 	/* edit uis have no window, and we only want button 1 to work on them */
823 	if (event->button > 1 && !ui->window) return FALSE;
824 
825 	if (event->button >= 2)
826 		{
827 		if (ui->click_func)
828 			{
829 			ui->click_func(ui, event->button, event->time, ui->click_data);
830 			return TRUE;
831 			}
832 		return FALSE;
833 		}
834 
835 	if (event->type != GDK_BUTTON_PRESS) return FALSE;
836 
837 	gtk_grab_add(ui->display);
838 
839 	ui->press_x = x;
840 	ui->press_y = y;
841 
842 	work = ui->skin->widget_list;
843 	while (work)
844 		{
845 		if (ui_widget_press(ui, work->data, x, y))
846 			{
847 			ui->active_widget = work->data;
848 			if (debug_mode) printf("pressed widget: \"%s\" (%d)\n", ui->active_widget->key, ui->active_widget->type);
849 
850 			if ((slik_focus_enable || ui->focus_enable) &&
851 			    ui_widget_can_focus(ui->active_widget))
852 				{
853 				if (ui->focus_widget != ui->active_widget)
854 					{
855 					gint x, y, w, h;
856 					ui_display_focus_clear(ui);
857 					ui->focus_widget = ui->active_widget;
858 					if (ui_widget_get_geometry(ui->focus_widget, &x, &y, &w, &h))
859 						{
860 						ui_display_render_area(ui, x, y, w, h, ui->focus_widget);
861 						}
862 					}
863 				if (!GTK_WIDGET_HAS_FOCUS(ui->display))
864 					{
865 					gtk_widget_grab_focus(ui->display);
866 					}
867 				}
868 
869 			return TRUE;
870 			}
871 		work = work->next;
872 		}
873 
874 	if (ui->allow_move)
875 		{
876 		ui->in_move = TRUE;
877 		gdk_window_get_pointer (NULL, &ui->press_root_x, &ui->press_root_y, &modmask);
878 		}
879 	ui->in_press = (event->x >= 0 && event->x <= ui->skin->width &&
880 			event->y >= 0 && event->y <= ui->skin->height);
881 
882 	return ui->in_press;
883 }
884 
ui_display_released(GtkWidget * w,GdkEventButton * event,gpointer data)885 static gint ui_display_released(GtkWidget *w, GdkEventButton *event, gpointer data)
886 {
887 	UIData *ui = data;
888 	gint x = (gint)event->x;
889 	gint y = (gint)event->y;
890 
891 	if (debug_mode) printf("released:%d x %d, %d\n", x, y, event->button);
892 
893 	if (!ui->skin) return FALSE;
894 	if (!ui->in_press && !ui->active_widget) return FALSE;
895 
896 	gtk_grab_remove(ui->display);
897 
898 	if (ui->active_widget)
899 		{
900 		if (debug_mode) printf("releasing widget: \"%s\" (%d)\n", ui->active_widget->key, ui->active_widget->type);
901 		ui_widget_release(ui, ui->active_widget, x, y);
902 		ui->active_widget = NULL;
903 		}
904 	else
905 		{
906 		GdkModifierType modmask;
907 		gint px;
908 		gint py;
909 		gdk_window_get_pointer (NULL, &px, &py, &modmask);
910 		if (px == ui->press_root_x && py == ui->press_root_y && ui->window)
911 			{
912 			gdk_window_raise (ui->window->window);
913 			}
914 		}
915 
916 	ui->in_press = FALSE;
917 	ui->in_move = FALSE;
918 
919 	return FALSE;
920 }
921 
ui_display_leave(GtkWidget * widget,GdkEventCrossing * event,gpointer data)922 static void ui_display_leave(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
923 {
924 	UIData *ui = data;
925 
926 	if (!ui->skin) return;
927 
928 	if (!ui->active_widget)
929 		{
930 		GList *work;
931 
932 		work = ui->skin->widget_list;
933 		while(work)
934 			{
935 			ui_widget_reset(ui, work->data);
936 			work = work->next;
937 			}
938 		}
939 }
940 
ui_display_events_init(UIData * ui)941 void ui_display_events_init(UIData *ui)
942 {
943 	GTK_WIDGET_SET_FLAGS(ui->display, GTK_CAN_FOCUS);
944 
945 	gtk_widget_set_events(ui->display, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
946 			      GDK_POINTER_MOTION_MASK |
947 			      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
948 	g_signal_connect(G_OBJECT(ui->display),"motion_notify_event",
949 			 G_CALLBACK(ui_display_motion), ui);
950 	g_signal_connect(G_OBJECT(ui->display),"button_press_event",
951 			 G_CALLBACK(ui_display_pressed), ui);
952 	g_signal_connect(G_OBJECT(ui->display),"button_release_event",
953 			 G_CALLBACK(ui_display_released), ui);
954 	g_signal_connect(G_OBJECT(ui->display),"leave_notify_event",
955 			 G_CALLBACK(ui_display_leave), ui);
956 
957 	g_signal_connect(G_OBJECT(ui->display),"key_press_event",
958 			 G_CALLBACK(ui_display_key_press), ui);
959 	g_signal_connect(G_OBJECT(ui->display),"scroll_event",
960 			 G_CALLBACK(ui_display_scrolled), ui);
961 
962 	g_signal_connect(G_OBJECT(ui->display),"focus_in_event",
963 			 G_CALLBACK(ui_display_focus_in), ui);
964 	g_signal_connect(G_OBJECT(ui->display),"focus_out_event",
965 			 G_CALLBACK(ui_display_focus_out), ui);
966 
967 	ui->active_widget = NULL;
968 	ui->in_press = FALSE;
969 	ui->in_move = FALSE;
970 
971 	/* the expose event */
972 	g_signal_connect(GTK_OBJECT(ui->display), "expose_event",
973 			   G_CALLBACK(ui_display_expose), ui);
974 	if (ui->window)
975 		{
976 		g_signal_connect(GTK_OBJECT(ui->window), "configure_event",
977 				   G_CALLBACK(ui_display_move), ui);
978 		}
979 }
980 
981