1 /*
2 * florence - Florence is a simple virtual keyboard for Gnome.
3
4 * Copyright (C) 2012 François Agrech
5
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include "system.h"
23 #include "view.h"
24 #include "trace.h"
25 #include "settings.h"
26 #include "keyboard.h"
27 #include "tools.h"
28 #include <gtk/gtk.h>
29 #include <gdk/gdkx.h>
30 #include <cairo/cairo-xlib.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/extensions/shape.h>
34 #include <X11/extensions/Xcomposite.h>
35
36
37 /* Show the view next to the accessible object if specified. */
38 #ifdef AT_SPI
39 #ifdef ENABLE_AT_SPI2
view_show(struct view * view,AtspiAccessible * object)40 void view_show (struct view *view, AtspiAccessible *object)
41 #else
42 void view_show (struct view *view, Accessible *object)
43 #endif
44 #else
45 void view_show (struct view *view)
46 #endif
47 {
48 START_FUNC
49 gtk_widget_show(GTK_WIDGET(view->window));
50 /* Some winwow managers forget it */
51 gtk_window_set_keep_above(view->window, TRUE);
52 gtk_window_set_urgency_hint(view->window, TRUE);
53 /* reposition the window */
54 gtk_window_move(view->window, settings_get_int(SETTINGS_XPOS), settings_get_int(SETTINGS_YPOS));
55 #ifdef AT_SPI
56 /* positionnement intelligent */
57 if (settings_get_bool(SETTINGS_AUTO_HIDE) &&
58 settings_get_bool(SETTINGS_MOVE_TO_WIDGET) && object) {
59 tools_window_move(view->window, object);
60 }
61 #endif
62 END_FUNC
63 }
64
65 /* Hides the view */
view_hide(struct view * view)66 void view_hide (struct view *view)
67 {
68 START_FUNC
69 gtk_widget_hide(GTK_WIDGET(view->window));
70 END_FUNC
71 }
72
view_on_destroy(gpointer user_data)73 void view_on_destroy(gpointer user_data)
74 {
75 START_FUNC
76 struct view *view=(struct view *)user_data;
77 view->window=NULL;
78 END_FUNC
79 }
80
81 /* destroy the view */
view_destroy(struct view * view)82 void view_destroy(struct view *view)
83 {
84 START_FUNC
85 if (view->window) {
86 GtkWidget *window=GTK_WIDGET(view->window);
87 view->window=NULL;
88 gtk_widget_destroy(window);
89 }
90 END_FUNC
91 }
92
93 /* resize the window */
view_resize(struct view * view)94 void view_resize (struct view *view)
95 {
96 START_FUNC
97 GdkRectangle rect;
98 GdkGeometry hints;
99 hints.win_gravity=GDK_GRAVITY_NORTH_WEST;
100 if (settings_get_bool(SETTINGS_RESIZABLE)) {
101 gtk_window_set_resizable(view->window, TRUE);
102 if (settings_get_bool(SETTINGS_KEEP_RATIO)) {
103 hints.min_aspect=view->vwidth/view->vheight;
104 hints.max_aspect=view->vwidth/view->vheight;
105 gtk_window_set_geometry_hints(view->window, NULL, &hints,
106 GDK_HINT_ASPECT|GDK_HINT_WIN_GRAVITY);
107 } else {
108 gtk_window_set_geometry_hints(view->window, NULL, &hints,
109 GDK_HINT_WIN_GRAVITY);
110 }
111 /* Do not call configure signal handler */
112 if (view->configure_handler) g_signal_handler_disconnect(G_OBJECT(view->window), view->configure_handler);
113 view->configure_handler=0;
114 gtk_window_resize(view->window, view->width, view->height);
115 } else {
116 gtk_window_set_geometry_hints(view->window, NULL, &hints,
117 GDK_HINT_WIN_GRAVITY);
118 gtk_window_set_resizable(view->window, FALSE);
119 gtk_widget_set_size_request(GTK_WIDGET(view->window),
120 view->width, view->height);
121 }
122 /* refresh the view */
123 if (view->window && gtk_widget_get_window(GTK_WIDGET(view->window))) {
124 rect.x=0; rect.y=0;
125 rect.width=view->width; rect.height=view->height;
126 gdk_window_invalidate_rect(gtk_widget_get_window(GTK_WIDGET(view->window)), &rect, TRUE);
127 }
128 END_FUNC
129 }
130
131 /* draws the background of florence */
view_draw(struct view * view,cairo_t * cairoctx,cairo_surface_t ** surface,enum style_class class)132 void view_draw (struct view *view, cairo_t *cairoctx, cairo_surface_t **surface, enum style_class class)
133 {
134 START_FUNC
135 GSList *list=view->keyboards;
136 struct keyboard *keyboard;
137 cairo_t *offscreen;
138
139 /* create the surface */
140 if (!*surface) *surface=cairo_surface_create_similar(cairo_get_target(cairoctx),
141 CAIRO_CONTENT_COLOR_ALPHA, view->width, view->height);
142 offscreen=cairo_create(*surface);
143 cairo_set_source_rgba(offscreen, 0.0, 0.0, 0.0, 0.0);
144 cairo_set_operator(offscreen, CAIRO_OPERATOR_SOURCE);
145 cairo_paint(offscreen);
146 cairo_set_operator(offscreen, CAIRO_OPERATOR_OVER);
147
148 /* browse the keyboards */
149 cairo_save(offscreen);
150 cairo_scale(offscreen, view->scalex, view->scaley);
151 while (list)
152 {
153 keyboard=(struct keyboard *)list->data;
154 if (keyboard_activated(keyboard)) {
155 /* actual draw */
156 switch(class) {
157 case STYLE_SHAPE:
158 keyboard_background_draw(keyboard, offscreen, view->style, view->status);
159 if (keyboard->under) {
160 cairo_set_source_rgba(offscreen, 0.0, 0.0, 0.0, 0.75);
161 cairo_set_operator(offscreen, CAIRO_OPERATOR_OVER);
162 cairo_rectangle(offscreen, keyboard->xpos, keyboard->ypos,
163 keyboard_get_width(keyboard), keyboard_get_height(keyboard));
164 cairo_fill(offscreen);
165 }
166 break;
167 case STYLE_SYMBOL:
168 keyboard_symbols_draw(keyboard, offscreen, view->style, view->status);
169 break;
170 }
171 }
172 list=list->next;
173 }
174 cairo_destroy(offscreen);
175 END_FUNC
176 }
177
178 /* draws the background of florence */
view_background_draw(struct view * view,cairo_t * cairoctx)179 void view_background_draw (struct view *view, cairo_t *cairoctx)
180 {
181 START_FUNC
182 view_draw(view, cairoctx, &(view->background), STYLE_SHAPE);
183 END_FUNC
184 }
185
186 /* draws the symbols */
view_symbols_draw(struct view * view,cairo_t * cairoctx)187 void view_symbols_draw (struct view *view, cairo_t *cairoctx)
188 {
189 START_FUNC
190 view_draw(view, cairoctx, &(view->symbols), STYLE_SYMBOL);
191 END_FUNC
192 }
193
194 /* update the keyboard positions */
view_keyboards_set_pos(struct view * view,struct keyboard * over)195 void view_keyboards_set_pos(struct view *view, struct keyboard *over)
196 {
197 START_FUNC
198 GSList *list=view->keyboards;
199 struct keyboard *keyboard;
200 gdouble width=0.0, height=0.0, xoffset=0.0, yoffset=0.0;
201 gdouble x=0.0, y=0.0;
202
203 /* browse the keyboards */
204 while (list)
205 {
206 keyboard=(struct keyboard *)list->data;
207 if (keyboard_activated(keyboard)) {
208 /* get the position to draw the keyboard */
209 switch (keyboard_get_placement(keyboard)) {
210 case LAYOUT_VOID:
211 width=keyboard_get_width(keyboard);
212 height=keyboard_get_height(keyboard);
213 xoffset=yoffset=0.0;
214 x=y=0.0;
215 if (over) keyboard_set_under(keyboard); else keyboard_set_over(keyboard);
216 break;
217 case LAYOUT_TOP:
218 yoffset+=keyboard_get_height(keyboard);
219 x=0.0; y=-yoffset;
220 if (over) keyboard_set_under(keyboard); else keyboard_set_over(keyboard);
221 break;
222 case LAYOUT_BOTTOM:
223 x=0.0; y=height;
224 height+=keyboard_get_height(keyboard);
225 if (over) keyboard_set_under(keyboard); else keyboard_set_over(keyboard);
226 break;
227 case LAYOUT_LEFT:
228 xoffset+=keyboard_get_width(keyboard);
229 x=-xoffset; y=0.0;
230 if (over) keyboard_set_under(keyboard); else keyboard_set_over(keyboard);
231 break;
232 case LAYOUT_RIGHT:
233 x=width; y=0.0;
234 width+=keyboard_get_width(keyboard);
235 if (over) keyboard_set_under(keyboard); else keyboard_set_over(keyboard);
236 break;
237 case LAYOUT_OVER:
238 if (keyboard_get_width(keyboard)>width) width=keyboard_get_width(keyboard);
239 if (keyboard_get_height(keyboard)>height) height=keyboard_get_height(keyboard);
240 x=(width-view->xoffset-keyboard_get_width(keyboard))/2.0;
241 y=(height-view->yoffset-keyboard_get_height(keyboard))/2.0;
242 if (over==keyboard) keyboard_set_over(keyboard); else keyboard_set_under(keyboard);
243 break;
244 }
245 keyboard_set_pos(keyboard, x+view->xoffset, y+view->yoffset);
246 }
247 list = list->next;
248 }
249 END_FUNC
250 }
251
252 /* calculate the dimensions of Florence */
view_set_dimensions(struct view * view)253 void view_set_dimensions(struct view *view)
254 {
255 START_FUNC
256 GSList *list=view->keyboards;
257 struct keyboard *keyboard;
258 struct keyboard *over=NULL;
259
260 while (list)
261 {
262 keyboard=(struct keyboard *)list->data;
263 if (keyboard_activated(keyboard)) {
264 switch (keyboard_get_placement(keyboard)) {
265 case LAYOUT_VOID:
266 view->vwidth=keyboard_get_width(keyboard);
267 view->vheight=keyboard_get_height(keyboard);
268 view->xoffset=view->yoffset=0;
269 break;
270 case LAYOUT_TOP:
271 view->vheight+=(view->yoffset+=keyboard_get_height(keyboard));
272 break;
273 case LAYOUT_BOTTOM:
274 view->vheight+=keyboard_get_height(keyboard);
275 break;
276 case LAYOUT_LEFT:
277 view->vwidth+=(view->xoffset+=keyboard_get_width(keyboard));
278 break;
279 case LAYOUT_RIGHT:
280 view->vwidth+=keyboard_get_width(keyboard);
281 break;
282 case LAYOUT_OVER:
283 if (keyboard_get_width(keyboard)>view->vwidth) view->vwidth=keyboard_get_width(keyboard);
284 if (keyboard_get_height(keyboard)>view->vheight) view->vheight=keyboard_get_height(keyboard);
285 over=keyboard;
286 break;
287 }
288 }
289 list = list->next;
290 }
291 view->width=(guint)(view->vwidth*view->scalex);
292 view->height=(guint)(view->vheight*view->scaley);
293 view_keyboards_set_pos(view, over);
294 END_FUNC
295 }
296
297 /* get the key at position */
298 #ifdef ENABLE_RAMBLE
view_hit_get(struct view * view,gint x,gint y,enum key_hit * hit)299 struct key *view_hit_get (struct view *view, gint x, gint y, enum key_hit *hit)
300 #else
301 struct key *view_hit_get (struct view *view, gint x, gint y)
302 #endif
303 {
304 START_FUNC
305 GSList *list=view->keyboards;
306 struct keyboard *keyboard=NULL;
307 struct key *key;
308 gint kx=0.0, ky=0.0, kw=0.0, kh=0.0;
309
310 /* find the hit keyboard */
311 while (list)
312 {
313 keyboard=(struct keyboard *)list->data;
314 /* TODO: record in pixel
315 * and move that to keyboard_test */
316 kx=keyboard->xpos*view->scalex;
317 ky=keyboard->ypos*view->scaley;
318 kw=keyboard->width*view->scalex;
319 kh=keyboard->height*view->scaley;
320 if (keyboard_activated(keyboard) && (!keyboard->under) && (x>=kx) && (x<=(kx+kw)) && (y>=ky) && y<=(ky+kh)) {
321 list=NULL;
322 }
323 else list = list->next;
324 }
325 #ifdef ENABLE_RAMBLE
326 key=keyboard_hit_get(keyboard, x-kx, y-ky, view->scalex, view->scaley, hit);
327 #else
328 key=keyboard_hit_get(keyboard, x-kx, y-ky, view->scalex, view->scaley);
329 #endif
330
331 END_FUNC
332 return key;
333 }
334
335 /* Create a window mask for transparent window for non-composited screen */
336 /* For composited screen, this function is useless, use alpha channel instead. */
view_create_window_mask(struct view * view)337 void view_create_window_mask(struct view *view)
338 {
339 START_FUNC
340 Pixmap shape;
341 cairo_surface_t *mask=NULL;
342 cairo_t *cairoctx=NULL;
343 Display *disp=(Display *)gdk_x11_get_default_xdisplay();
344
345 if (settings_get_bool(SETTINGS_TRANSPARENT) && (!view->composite)) {
346 shape=XCreatePixmap(disp, GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(view->window))),
347 view->width, view->height, 1);
348 mask=cairo_xlib_surface_create_for_bitmap(disp, shape,
349 DefaultScreenOfDisplay(disp), view->width, view->height);
350 cairoctx=cairo_create(mask);
351 view_background_draw(view, cairoctx);
352 cairo_set_source_rgba(cairoctx, 0.0, 0.0, 0.0, 0.0);
353 cairo_set_operator(cairoctx, CAIRO_OPERATOR_SOURCE);
354 cairo_paint(cairoctx);
355 cairo_set_source_surface(cairoctx, view->background, 0, 0);
356 cairo_paint(cairoctx);
357 XShapeCombineMask(disp, GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(view->window))),
358 ShapeBounding, 0, 0, cairo_xlib_surface_get_drawable(mask), ShapeSet);
359 cairo_destroy(cairoctx);
360 cairo_surface_destroy(view->background);
361 view->background=NULL;
362 cairo_surface_destroy(mask);
363 status_focus_zoom_set(view->status, FALSE);
364 } else {
365 XShapeCombineMask(disp, GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(view->window))),
366 ShapeBounding, 0, 0, 0, ShapeSet);
367 status_focus_zoom_set(view->status, TRUE);
368 }
369 gtk_widget_queue_draw(GTK_WIDGET(view->window));
370 END_FUNC
371 }
372
373 /* Triggered by gconf when the "transparent" parameter is changed. Calls view_create_window_mask */
view_set_transparent(GSettings * settings,gchar * key,gpointer user_data)374 void view_set_transparent(GSettings *settings, gchar *key, gpointer user_data)
375 {
376 START_FUNC
377 struct view *view=(struct view *)user_data;
378 gboolean shown=gtk_widget_get_visible(GTK_WIDGET(view->window));
379 gtk_widget_show(GTK_WIDGET(view->window));
380 view_create_window_mask(view);
381 if (!shown) gtk_widget_hide(GTK_WIDGET(view->window));
382 END_FUNC
383 }
384
385 /* Triggered by gconf when the "decorated" parameter is changed. Decorates or undecorate the window. */
view_set_decorated(GSettings * settings,gchar * key,gpointer user_data)386 void view_set_decorated(GSettings *settings, gchar *key, gpointer user_data)
387 {
388 START_FUNC
389 struct view *view=(struct view *)user_data;
390 gtk_window_set_decorated(view->window, settings_get_bool(SETTINGS_DECORATED));
391 gtk_window_move(view->window, settings_get_int(SETTINGS_XPOS), settings_get_int(SETTINGS_YPOS));
392 END_FUNC
393 }
394
395 /* Triggered by gconf when the "always_on_top" parameter is changed.
396 Change the window property to be always on top or not to be. */
view_set_always_on_top(GSettings * settings,gchar * key,gpointer user_data)397 void view_set_always_on_top(GSettings *settings, gchar *key, gpointer user_data)
398 {
399 START_FUNC
400 struct view *view=(struct view *)user_data;
401 gtk_window_set_keep_above(view->window, settings_get_bool(SETTINGS_ALWAYS_ON_TOP));
402 END_FUNC
403 }
404
405 /* Triggered by gconf when the "task_bar" parameter is changed.
406 Change the window hint to appear in the task bar or not. */
view_set_task_bar(GSettings * settings,gchar * key,gpointer user_data)407 void view_set_task_bar(GSettings *settings, gchar *key, gpointer user_data)
408 {
409 START_FUNC
410 struct view *view=(struct view *)user_data;
411 gtk_window_set_skip_taskbar_hint(view->window, !settings_get_bool(SETTINGS_TASK_BAR));
412 END_FUNC
413 }
414
415 /* Triggered by gconf when the "resizable" parameter is changed.
416 makes the window (not)resizable the window. */
view_set_resizable(GSettings * settings,gchar * key,gpointer user_data)417 void view_set_resizable(GSettings *settings, gchar *key, gpointer user_data)
418 {
419 START_FUNC
420 struct view *view=(struct view *)user_data;
421 if (settings_get_bool(SETTINGS_RESIZABLE)) {
422 gtk_widget_set_size_request(GTK_WIDGET(view->window), view->vwidth, view->vheight);
423 }
424 view_resize(view);
425 END_FUNC
426 }
427
428 /* Triggered by gconf when a color parameter is changed. */
view_redraw(GSettings * settings,gchar * key,gpointer user_data)429 void view_redraw(GSettings *settings, gchar *key, gpointer user_data)
430 {
431 START_FUNC
432 struct view *view=(struct view *)user_data;
433 style_update_colors(view->style);
434 if ((!strcmp(key, "key")) || (!strcmp(key, "outline"))) {
435 if (view->background) cairo_surface_destroy(view->background);
436 view->background=NULL;
437 } else if (!strncmp(key, "label", 5) || (!strcmp(key, "font")) || (!strcmp(key, "system_font"))) {
438 if (view->symbols) cairo_surface_destroy(view->symbols);
439 view->symbols=NULL;
440 }
441 gtk_widget_queue_draw(GTK_WIDGET(view->window));
442 END_FUNC
443 }
444
445 /* Triggered by gconf when the "resizable" parameter is changed.
446 makes the window (not)resizable the window. */
view_set_keep_ratio(GSettings * settings,gchar * key,gpointer user_data)447 void view_set_keep_ratio(GSettings *settings, gchar *key, gpointer user_data)
448 {
449 START_FUNC
450 struct view *view=(struct view *)user_data;
451 if (settings_get_bool(SETTINGS_KEEP_RATIO)) {
452 view->scaley=view->scalex;
453 }
454 view_resize(view);
455 view_redraw(settings, key, user_data);
456 END_FUNC
457 }
458
459 /* Redraw the key to the window */
view_update(struct view * view,struct key * key,gboolean statechange)460 void view_update(struct view *view, struct key *key, gboolean statechange)
461 {
462 START_FUNC
463 GdkRectangle *rect;
464 GdkCursor *cursor;
465
466 if (!view->window) return;
467 if (key) {
468 if (statechange) {
469 if (view->symbols) cairo_surface_destroy(view->symbols);
470 view->symbols=NULL;
471 gtk_widget_queue_draw(GTK_WIDGET(view->window));
472 } else {
473 rect=keyboard_key_getrect((struct keyboard *)key_get_keyboard(key),
474 key, status_focus_zoom_get(view->status));
475 gdk_window_invalidate_rect(
476 gtk_widget_get_window(GTK_WIDGET(view->window)),
477 rect, TRUE);
478 }
479 }
480 if (status_focus_get(view->status)) {
481 if (!view->hand_cursor) {
482 cursor=gdk_cursor_new(GDK_HAND2);
483 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(view->window)), cursor);
484 view->hand_cursor=TRUE;
485 }
486 } else if (view->hand_cursor) {
487 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(view->window)), NULL);
488 view->hand_cursor=FALSE;
489 }
490 END_FUNC
491 }
492
493 /* on screen change event: check for composite extension */
view_screen_changed(GtkWidget * widget,GdkScreen * old_screen,struct view * view)494 void view_screen_changed (GtkWidget *widget, GdkScreen *old_screen, struct view *view)
495 {
496 START_FUNC
497 GdkVisual *visual;
498 if (gtk_widget_is_composited(widget)) {
499 flo_info(_("X11 composite extension detected. Semi-transparency is enabled."));
500 if (view) view->composite=TRUE;
501 visual=gdk_screen_get_rgba_visual(gdk_screen_get_default());
502 if (visual==NULL) visual=gdk_screen_get_system_visual(gdk_screen_get_default());
503 gtk_widget_set_visual(widget, visual);
504 } else {
505 flo_info(_("Your screen does not support alpha channel. Semi-transparency is disabled"));
506 if (view) view->composite=FALSE;
507 }
508 END_FUNC
509 }
510
511 /* on configure events: record window position */
view_configure(GtkWidget * window,GdkEventConfigure * pConfig,struct view * view)512 void view_configure (GtkWidget *window, GdkEventConfigure* pConfig, struct view *view)
513 {
514 START_FUNC
515 GdkRectangle rect;
516 gint xpos, ypos;
517 if ((!view->window)||(!gtk_widget_get_visible(window))) return;
518
519 /* record window position */
520 if (gtk_window_get_decorated(GTK_WINDOW(view->window)))
521 gtk_window_get_position(GTK_WINDOW(view->window), &xpos, &ypos);
522 else { xpos=pConfig->x; ypos=pConfig->y; }
523 if (settings_get_int(SETTINGS_XPOS)!=xpos)
524 settings_set_int(SETTINGS_XPOS, xpos);
525 if (settings_get_int(SETTINGS_YPOS)!=ypos)
526 settings_set_int(SETTINGS_YPOS, ypos);
527
528 /* handle resize events */
529 if ((pConfig->width!=view->width) || (pConfig->height!=view->height)) {
530 if (settings_get_bool(SETTINGS_KEEP_RATIO)) {
531 view->scalex=view->scaley=(gdouble)pConfig->width/view->vwidth;
532 } else {
533 view->scalex=(gdouble)pConfig->width/view->vwidth;
534 view->scaley=(gdouble)pConfig->height/view->vheight;
535 }
536 if ((view->scalex>200.0)||(view->scaley>200.0))
537 flo_warn(_("Window size out of range :%d, %d"), view->scalex, view->scaley);
538 else {
539 settings_set_double(SETTINGS_SCALEX, view->scalex, FALSE);
540 settings_set_double(SETTINGS_SCALEY, view->scaley, FALSE);
541 }
542 view->width=pConfig->width; view->height=pConfig->height;
543 if (view->background) cairo_surface_destroy(view->background);
544 view->background=NULL;
545 if (view->symbols) cairo_surface_destroy(view->symbols);
546 view->symbols=NULL;
547 view_create_window_mask(view);
548 rect.x=0; rect.y=0;
549 rect.width=pConfig->width; rect.height=pConfig->height;
550 gtk_widget_size_allocate(GTK_WIDGET(view->window), &rect);
551 gdk_window_invalidate_rect(gtk_widget_get_window(GTK_WIDGET(view->window)), &rect, TRUE);
552 gdk_window_process_updates(gtk_widget_get_window(GTK_WIDGET(view->window)), FALSE);
553 }
554
555 END_FUNC
556 }
557
558 /* draw the background of the keyboard */
view_draw_background(struct view * view,cairo_t * context)559 void view_draw_background (struct view *view, cairo_t *context)
560 {
561 START_FUNC
562 /* prepare the background */
563 if (!view->background) {
564 view_background_draw(view, context);
565 }
566
567 /* paint the background */
568 cairo_set_operator(context, CAIRO_OPERATOR_OVER);
569 cairo_set_source_surface(context, view->background, 0, 0);
570 cairo_paint(context);
571 END_FUNC
572 }
573
574 /* draw a list of keys (latched or locked keys) */
view_draw_list(struct view * view,cairo_t * context,GList * list)575 void view_draw_list (struct view *view, cairo_t *context, GList *list)
576 {
577 START_FUNC
578 struct keyboard *keyboard;
579 struct key *key;
580 while (list) {
581 key=(struct key *)list->data;
582 keyboard=(struct keyboard *)key_get_keyboard(key);
583 keyboard_press_draw(keyboard, context, view->style, key, view->status);
584 list=list->next;
585 }
586 END_FUNC
587 }
588
589 /* draw a single key (pressed or focused) */
view_draw_key(struct view * view,cairo_t * context,struct key * key)590 void view_draw_key (struct view *view, cairo_t *context, struct key *key)
591 {
592 START_FUNC
593 struct keyboard *keyboard;
594 if (key) {
595 keyboard=(struct keyboard *)key_get_keyboard(key);
596 keyboard_focus_draw(keyboard, context,
597 (gdouble)cairo_xlib_surface_get_width(view->background),
598 (gdouble)cairo_xlib_surface_get_height(view->background),
599 view->style, key, view->status);
600 }
601 END_FUNC
602 }
603
604 /* on draw event: draws the keyboards to the window */
view_expose(GtkWidget * window,cairo_t * context,struct view * view)605 void view_expose (GtkWidget *window, cairo_t* context, struct view *view)
606 {
607 START_FUNC
608 enum key_state state;
609
610 /* clear the area */
611 if (settings_get_bool(SETTINGS_TRANSPARENT)) {
612 cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.0);
613 cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
614 cairo_paint(context);
615 }
616
617 view_draw_background(view, context);
618
619 /* draw the symbols */
620 if (!view->symbols) {
621 view_symbols_draw(view, context);
622 }
623 cairo_set_source_surface(context, view->symbols, 0, 0);
624 cairo_paint(context);
625
626 /* handle composited transparency */
627 /* TODO: check for transparency support in WM */
628 if (view->composite && settings_get_double(SETTINGS_OPACITY)!=100.0) {
629 if (settings_get_double(SETTINGS_OPACITY)>100.0 ||
630 settings_get_double(SETTINGS_OPACITY)<1.0) {
631 flo_error(_("Window opacity out of range (1.0 to 100.0): %f"),
632 settings_get_double(SETTINGS_OPACITY));
633 }
634 cairo_set_source_rgba(context, 0.0, 0.0, 0.0,
635 (100.0-settings_get_double(SETTINGS_OPACITY))/100.0);
636 cairo_set_operator(context, CAIRO_OPERATOR_DEST_OUT);
637 cairo_paint(context);
638 cairo_set_operator(context, CAIRO_OPERATOR_OVER);
639 }
640
641 cairo_save(context);
642 cairo_scale(context, view->scalex, view->scaley);
643
644 /* draw highlights (pressed keys) */
645 view_draw_list(view, context, status_list_latched(view->status));
646 view_draw_list(view, context, status_list_locked(view->status));
647
648 /* pressed and focused key */
649 view_draw_key(view, context, status_focus_get(view->status));
650 if (status_pressed_get(view->status)) {
651 state=status_pressed_get(view->status)->state;
652 key_state_set(status_pressed_get(view->status), KEY_PRESSED);
653 view_draw_key(view, context, status_pressed_get(view->status));
654 key_state_set(status_pressed_get(view->status), state);
655 }
656
657 cairo_restore(context);
658
659 #ifdef ENABLE_RAMBLE
660 if (view->ramble) ramble_draw(view->ramble, context);
661 #endif
662
663 /* restore configure event handler. */
664 if (!view->configure_handler)
665 view->configure_handler=g_signal_connect(G_OBJECT(view->window), "configure-event",
666 G_CALLBACK(view_configure), view);
667 END_FUNC
668 }
669
670 /* on keys changed events */
view_on_keys_changed(gpointer user_data)671 void view_on_keys_changed(gpointer user_data)
672 {
673 START_FUNC
674 struct view *view=(struct view *)user_data;
675 if (view->symbols) cairo_surface_destroy(view->symbols);
676 view->symbols=NULL;
677 if (view->window) gtk_widget_queue_draw(GTK_WIDGET(view->window));
678 END_FUNC
679 }
680
681 /* track the windows state changes */
view_window_state(GtkWidget * window,GdkEventWindowState * event,struct view * view)682 void view_window_state (GtkWidget *window, GdkEventWindowState *event, struct view *view)
683 {
684 START_FUNC
685 gint is_iconified=gdk_window_get_state(gtk_widget_get_window(window))&GDK_WINDOW_STATE_ICONIFIED;
686 if (is_iconified) {
687 view_hide(view);
688 gtk_window_deiconify(GTK_WINDOW(view->window));
689 }
690 END_FUNC
691 }
692
693
694 /* Triggered by gconf when the "extensions" parameter is changed. */
view_update_extensions(GSettings * settings,gchar * key,gpointer user_data)695 void view_update_extensions(GSettings *settings, gchar *key, gpointer user_data)
696 {
697 START_FUNC
698 struct view *view=(struct view *)user_data;
699 GSList *list=view->keyboards;
700 struct keyboard *keyboard;
701
702 /* Do not call configure signal handler */
703 if (view->configure_handler) g_signal_handler_disconnect(G_OBJECT(view->window), view->configure_handler);
704 view->configure_handler=0;
705
706 while (list)
707 {
708 keyboard=(struct keyboard *)list->data;
709 keyboard_status_update(keyboard, view->status);
710 list=list->next;
711 }
712
713 view_set_dimensions(view);
714 view_resize(view);
715 if (view->background) cairo_surface_destroy(view->background);
716 view->background=NULL;
717 if (view->symbols) cairo_surface_destroy(view->symbols);
718 view->symbols=NULL;
719 view_create_window_mask(view);
720 status_focus_set(view->status, NULL);
721 gtk_widget_queue_draw(GTK_WIDGET(view->window));
722 END_FUNC
723 }
724
725 /* Triggered by gconf when the "zoom" parameter is changed. */
view_set_scalex(GSettings * settings,gchar * key,gpointer user_data)726 void view_set_scalex(GSettings *settings, gchar *key, gpointer user_data)
727 {
728 START_FUNC
729 struct view *view=(struct view *)user_data;
730 /* Do not call configure signal handler */
731 if (view->configure_handler) g_signal_handler_disconnect(G_OBJECT(view->window), view->configure_handler);
732 view->configure_handler=0;
733 view->scalex=settings_get_double(SETTINGS_SCALEX);
734 if (settings_get_bool(SETTINGS_KEEP_RATIO)) view->scaley=view->scalex;
735 view_update_extensions(settings, key, user_data);
736 END_FUNC
737 }
738
739 /* Triggered by gconf when the "zoom" parameter is changed. */
view_set_scaley(GSettings * settings,gchar * key,gpointer user_data)740 void view_set_scaley(GSettings *settings, gchar *key, gpointer user_data)
741 {
742 START_FUNC
743 struct view *view=(struct view *)user_data;
744 /* Do not call configure signal handler */
745 if (view->configure_handler) g_signal_handler_disconnect(G_OBJECT(view->window), view->configure_handler);
746 view->configure_handler=0;
747 view->scaley=settings_get_double(SETTINGS_SCALEY);
748 if (settings_get_bool(SETTINGS_KEEP_RATIO)) view->scalex=view->scaley;
749 view_update_extensions(settings, key, user_data);
750 END_FUNC
751 }
752
753 /* Triggered by gconf when the "opacity" parameter is changed. */
view_set_opacity(GSettings * settings,gchar * key,gpointer user_data)754 void view_set_opacity(GSettings *settings, gchar *key, gpointer user_data)
755 {
756 START_FUNC
757 struct view *view=(struct view *)user_data;
758 gtk_widget_queue_draw(GTK_WIDGET(view->window));
759 END_FUNC
760 }
761
762 /* get gtk window of the view */
view_window_get(struct view * view)763 GtkWindow *view_window_get (struct view *view)
764 {
765 START_FUNC
766 END_FUNC
767 return view->window;
768 }
769
770 /* get gtk window of the view */
view_status_set(struct view * view,struct status * status)771 void view_status_set (struct view *view, struct status *status)
772 {
773 START_FUNC
774 view->status=status;
775 END_FUNC
776 }
777
778 /* liberate all the memory used by the view */
view_free(struct view * view)779 void view_free(struct view *view)
780 {
781 START_FUNC
782 if (view->background) cairo_surface_destroy(view->background);
783 if (view->symbols) cairo_surface_destroy(view->symbols);
784 g_free(view);
785 END_FUNC
786 }
787
788 /* create a view of florence */
view_new(struct status * status,struct style * style,GSList * keyboards)789 struct view *view_new (struct status *status, struct style *style, GSList *keyboards)
790 {
791 START_FUNC
792 struct view *view=g_malloc(sizeof(struct view));
793 if (!view) flo_fatal(_("Unable to allocate memory for view"));
794 memset(view, 0, sizeof(struct view));
795
796 view->status=status;
797 view->style=style;
798 view->keyboards=keyboards;
799 view->scalex=settings_get_double(SETTINGS_SCALEX);
800 view->scaley=settings_get_double(SETTINGS_SCALEY);
801 view_set_dimensions(view);
802 view->window=GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
803 gtk_window_set_keep_above(view->window, settings_get_bool(SETTINGS_ALWAYS_ON_TOP));
804 gtk_window_set_accept_focus(view->window, FALSE);
805 gtk_window_set_skip_taskbar_hint(view->window, !settings_get_bool(SETTINGS_TASK_BAR));
806 /* Remove resize grip since it is buggy */
807 gtk_window_set_has_resize_grip(view->window, FALSE);
808 view_resize(view);
809 gtk_container_set_border_width(GTK_CONTAINER(view->window), 0);
810 gtk_widget_set_events(GTK_WIDGET(view->window),
811 GDK_EXPOSURE_MASK|GDK_POINTER_MOTION_HINT_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|
812 GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_STRUCTURE_MASK|GDK_POINTER_MOTION_MASK);
813 gtk_widget_set_app_paintable(GTK_WIDGET(view->window), TRUE);
814 gtk_window_set_decorated(view->window, settings_get_bool(SETTINGS_DECORATED));
815 gtk_window_move(view->window, settings_get_int(SETTINGS_XPOS), settings_get_int(SETTINGS_YPOS));
816 /*g_signal_connect(gdk_keymap_get_default(), "keys-changed", G_CALLBACK(view_on_keys_changed), view);*/
817 xkeyboard_register_events(status->xkeyboard, view_on_keys_changed, (gpointer)view);
818 g_signal_connect(G_OBJECT(view->window), "screen-changed", G_CALLBACK(view_screen_changed), view);
819 view->configure_handler=g_signal_connect(G_OBJECT(view->window), "configure-event",
820 G_CALLBACK(view_configure), view);
821 g_signal_connect(G_OBJECT(view->window), "draw", G_CALLBACK(view_expose), view);
822 g_signal_connect(G_OBJECT(view->window), "window-state-event", G_CALLBACK(view_window_state), view);
823 view_screen_changed(GTK_WIDGET(view->window), NULL, view);
824 g_signal_connect(G_OBJECT(view->window), "destroy", G_CALLBACK(view_on_destroy), view);
825 gtk_widget_show(GTK_WIDGET(view->window));
826 view_create_window_mask(view);
827
828 /* register settings callbacks */
829 settings_changecb_register(SETTINGS_TRANSPARENT, view_set_transparent, view);
830 settings_changecb_register(SETTINGS_DECORATED, view_set_decorated, view);
831 settings_changecb_register(SETTINGS_RESIZABLE, view_set_resizable, view);
832 settings_changecb_register(SETTINGS_ALWAYS_ON_TOP, view_set_always_on_top, view);
833 settings_changecb_register(SETTINGS_TASK_BAR, view_set_task_bar, view);
834 settings_changecb_register(SETTINGS_KEEP_RATIO, view_set_keep_ratio, view);
835 settings_changecb_register(SETTINGS_SCALEX, view_set_scalex, view);
836 settings_changecb_register(SETTINGS_SCALEY, view_set_scaley, view);
837 settings_changecb_register(SETTINGS_OPACITY, view_set_opacity, view);
838 settings_changecb_register(SETTINGS_EXTENSIONS, view_update_extensions, view);
839 settings_changecb_register(SETTINGS_KEY, view_redraw, view);
840 settings_changecb_register(SETTINGS_OUTLINE, view_redraw, view);
841 settings_changecb_register(SETTINGS_LABEL, view_redraw, view);
842 settings_changecb_register(SETTINGS_LABEL_OUTLINE, view_redraw, view);
843 settings_changecb_register(SETTINGS_ACTIVATED, view_redraw, view);
844 settings_changecb_register(SETTINGS_LATCHED, view_redraw, view);
845 settings_changecb_register(SETTINGS_SYSTEM_FONT, view_redraw, view);
846 settings_changecb_register(SETTINGS_FONT, view_redraw, view);
847
848 /* set the window icon */
849 tools_set_icon(view->window);
850 END_FUNC
851 return view;
852 }
853
854 /* Change the layout and style of the view and redraw */
view_update_layout(struct view * view,struct style * style,GSList * keyboards)855 void view_update_layout(struct view *view, struct style *style, GSList *keyboards)
856 {
857 START_FUNC
858 view->style=style;
859 view->keyboards=keyboards;
860 xkeyboard_register_events(view->status->xkeyboard, view_on_keys_changed, (gpointer)view);
861 view_update_extensions(NULL, NULL, (gpointer)view);
862 END_FUNC
863 }
864
865