The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GtkWindow.vala in birdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of birdfont/GtkWindow.vala.
Merge ../birdfont-2.x
1 /* 2 Copyright (C) 2012 2013 2014 2015 Johan Mattsson 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 using Cairo; 19 using Gtk; 20 using Gdk; 21 using BirdFont; 22 using WebKit; 23 using Gdk; 24 using Notify; 25 26 namespace BirdFont { 27 28 public class GtkWindow : Gtk.Window, NativeWindow { 29 30 Box list_box; 31 Box canvas_box; 32 33 WebView html_canvas; 34 ScrolledWindow html_box; 35 36 Box tab_box; 37 38 GlyphCanvasArea glyph_canvas_area; 39 40 Clipboard clipboard; 41 string clipboard_svg = ""; 42 string inkscape_clipboard = ""; 43 44 Scrollbar scrollbar; 45 bool scrollbar_supress_signal = false; 46 47 /** Text input and callbacks. */ 48 public static bool text_input_is_active = false; 49 TextListener text_listener = new TextListener ("", "", ""); 50 Label text_input_label; 51 Entry text_entry; 52 Box text_box; 53 Gtk.Button submit_text_button; 54 55 ToolboxCanvas toolbox; 56 57 Task background_task = new Task(idle); 58 59 public GtkWindow (string title) { 60 scrollbar = new Scrollbar (Orientation.VERTICAL, new Adjustment (0, 0, 1, 1, 0.01, 0.1)); 61 ((Gtk.Window)this).set_title ("BirdFont"); 62 } 63 64 public static void idle () { 65 } 66 67 public void init () { 68 Notify.init ("Fonts have been exported."); 69 70 clipboard = Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); 71 72 Signal.connect(this, "notify::is-active", (GLib.Callback) window_focus, null); 73 74 scrollbar.value_changed.connect (() => { 75 double p; 76 77 if (!scrollbar_supress_signal) { 78 p = scrollbar.get_value () / (1 - scrollbar.adjustment.page_size); 79 FontDisplay display = MainWindow.get_current_display (); 80 display.scroll_to (p); 81 } 82 }); 83 84 delete_event.connect (() => { 85 MenuTab.quit (); 86 return true; 87 }); 88 89 set_size_and_position (); 90 91 glyph_canvas_area = new GlyphCanvasArea (MainWindow.glyph_canvas); 92 93 html_canvas = new WebView (); 94 html_box = new ScrolledWindow (null, null); 95 html_box.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC); 96 html_box.add (html_canvas); 97 98 MainWindow.get_tab_bar ().signal_tab_selected.connect ((f, tab) => { 99 string uri = ""; 100 string html = ""; 101 FontDisplay fd = tab.get_display (); 102 103 scrollbar.set_visible (fd.has_scrollbar ()); 104 105 if (fd.get_name () == "Preview") { 106 uri = Preview.get_uri (); 107 html = Preview.get_html_with_absolute_paths (); 108 109 try { 110 html_canvas.load_html (html, uri); 111 } catch (Error e) { 112 warning (e.message); 113 warning ("Failed to load html into canvas."); 114 } 115 116 // show the webview when loading has finished 117 html_box.set_visible (true); 118 glyph_canvas_area.set_visible (false); 119 } else { 120 html_box.set_visible (false); 121 glyph_canvas_area.set_visible (true); 122 } 123 }); 124 125 // Hide this canvas when window is realized and flip canvas 126 // visibility in tab selection signal. 127 html_canvas.draw.connect ((t, e) => { 128 glyph_canvas_area.set_visible (false); 129 return false; 130 }); 131 132 canvas_box = new Box (Orientation.HORIZONTAL, 0); 133 canvas_box.pack_start (glyph_canvas_area, true, true, 0); 134 canvas_box.pack_start (html_box, true, true, 0); 135 canvas_box.pack_start (scrollbar, false, true, 0); 136 137 submit_text_button = new Gtk.Button (); 138 submit_text_button.set_label ("Submit"); 139 text_input_label = new Label (" " + "Text"); 140 text_entry = new Entry (); 141 text_box = new Box (Orientation.HORIZONTAL, 6); 142 text_box.pack_start (text_input_label, false, false, 0); 143 text_box.pack_start (text_entry, true, true, 0); 144 text_box.pack_start (submit_text_button, false, false, 0); 145 146 text_entry.changed.connect (() => { 147 text_listener.signal_text_input (text_entry.text); 148 }); 149 150 submit_text_button.clicked.connect (() => { 151 text_listener.signal_submit (text_entry.text); 152 text_input_is_active = false; 153 }); 154 155 tab_box = new Box (Orientation.VERTICAL, 0); 156 157 tab_box.pack_start (new TabbarCanvas (MainWindow.get_tab_bar ()), false, false, 0); 158 tab_box.pack_start (text_box, false, false, 5); 159 tab_box.pack_start (canvas_box, true, true, 0); 160 161 toolbox = new ToolboxCanvas (MainWindow.get_toolbox ()); 162 list_box = new Box (Orientation.HORIZONTAL, 0); 163 list_box.pack_start (toolbox, false, false, 0); 164 list_box.pack_start (tab_box, true, true, 0); 165 166 Box vbox = new Box (Orientation.VERTICAL, 0); 167 vbox.pack_start(list_box, true, true, 0); 168 add (vbox); 169 170 try { 171 set_icon_from_file ((!) SearchPaths.find_file (null, "birdfont_window_icon.png").get_path ()); 172 } catch (GLib.Error e) { 173 warning (e.message); 174 } 175 176 key_press_event.connect ((t, event) => { 177 if (!GtkWindow.text_input_is_active) { 178 GtkWindow.reset_modifier (event.state); 179 TabContent.key_press (event.keyval); 180 } 181 182 return false; 183 }); 184 185 key_release_event.connect ((t, event) => { 186 if (!GtkWindow.text_input_is_active) { 187 TabContent.key_release (event.keyval); 188 } 189 190 return false; 191 }); 192 193 size_allocate.connect(() => { 194 GlyphCanvas.redraw (); 195 }); 196 197 show_all (); 198 199 scrollbar.set_visible (false); 200 201 hide_text_input (); 202 203 MainWindow.open_recent_files_tab (); 204 } 205 206 public void window_focus (void* data) { 207 TabContent.reset_modifier (); 208 } 209 210 public static void reset_modifier (ModifierType flags) { 211 if ((flags & ModifierType.CONTROL_MASK) == 0) { 212 TabContent.key_release (Key.CTRL_RIGHT); 213 TabContent.key_release (Key.CTRL_LEFT); 214 } 215 216 if ((flags & ModifierType.SHIFT_MASK) == 0) { 217 TabContent.key_release (Key.SHIFT_LEFT); 218 TabContent.key_release (Key.SHIFT_RIGHT); 219 } 220 221 if ((flags & ModifierType.MOD1_MASK) == 0) { 222 TabContent.key_release (Key.ALT_LEFT); 223 TabContent.key_release (Key.ALT_RIGHT); 224 } 225 226 if ((flags & ModifierType.MOD5_MASK) == 0) { 227 TabContent.key_release (Key.LOGO_LEFT); 228 TabContent.key_release (Key.LOGO_RIGHT); 229 } 230 } 231 232 public void font_loaded () { 233 Font f = BirdFont.get_current_font (); 234 set_title (@"$(f.full_name)"); 235 } 236 237 public void set_scrollbar_size (double size) { 238 scrollbar.adjustment.page_size = size; 239 scrollbar.set_visible (size != 0); 240 } 241 242 public void set_scrollbar_position (double position) { 243 scrollbar_supress_signal = true; 244 scrollbar.adjustment.value = position * (1 - scrollbar.adjustment.page_size); 245 scrollbar_supress_signal = false; 246 } 247 248 public void dump_clipboard_content (Clipboard clipboard, SelectionData selection_data) { 249 string d; 250 return_if_fail (!is_null (selection_data)); 251 d = (string) ((!) selection_data); 252 stdout.printf (d); 253 } 254 255 public void dump_clipboard_target (Clipboard clipboard, Atom[] atoms) { 256 foreach (Atom target in atoms) { 257 print ("Target: " + target.name () + "\n"); 258 clipboard.request_contents (target, dump_clipboard_content); 259 } 260 } 261 262 public void dump_clipboard () { 263 clipboard.request_targets (dump_clipboard_target); 264 } 265 266 public string get_clipboard_data () { 267 SelectionData? selection_data; 268 Atom target; 269 string? t; 270 271 target = Atom.intern_static_string ("image/x-inkscape-svg"); 272 selection_data = clipboard.wait_for_contents (target); 273 274 if (!is_null (selection_data)) { 275 return (string) (((!) selection_data).get_data ()); 276 } 277 278 t = clipboard.wait_for_text (); 279 if (t != null) { 280 return (!) t; 281 } 282 283 return ""; 284 } 285 286 public void set_inkscape_clipboard (string inkscape_clipboard_data) { 287 if (BirdFont.mac) { 288 clipboard.set_text (inkscape_clipboard_data, -1); 289 } else { 290 TargetEntry t = { "image/x-inkscape-svg", 0, 0 }; 291 TargetEntry[] targets = { t }; 292 inkscape_clipboard = inkscape_clipboard_data; 293 294 // we can not add data to this closure because the third argument 295 // is owner and not private data. 296 clipboard.set_with_owner (targets, 297 298 // obtain clipboard data 299 (clipboard, selection_data, info, owner) => { 300 Atom type; 301 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->inkscape_clipboard.to_utf8 (); 302 type = Atom.intern_static_string ("image/x-inkscape-svg"); 303 selection_data.set (type, 8, data); 304 }, 305 306 // clear clipboard data 307 (clipboard, user_data) => { 308 }, 309 310 this); 311 } 312 } 313 314 public void set_clipboard_text (string text) { 315 clipboard.set_text (text, -1); 316 } 317 318 public string get_clipboard_text () { 319 string? t; 320 321 t = clipboard.wait_for_text (); 322 if (t != null) { 323 return ((!) t).dup (); 324 } 325 326 return "".dup (); 327 } 328 329 public void set_clipboard (string svg) { 330 TargetEntry t = { "image/svg+xml", 0, 0 }; 331 TargetEntry[] targets = { t }; 332 clipboard_svg = svg; 333 clipboard.set_with_owner (targets, 334 335 // obtain clipboard data 336 (clipboard, selection_data, info, owner) => { 337 Atom type; 338 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->clipboard_svg.to_utf8 (); 339 type = Atom.intern_static_string ("image/svg+xml"); 340 selection_data.set (type, 0, data); 341 }, 342 343 // clear clipboard data 344 (clipboard, user_data) => { 345 }, 346 347 this); 348 } 349 350 public void update_window_size () { 351 int w, h; 352 get_size (out w, out h); 353 354 Preferences.set ("window_width", @"$w"); 355 Preferences.set ("window_height", @"$h"); 356 } 357 358 private void set_size_and_position () { 359 int w = Preferences.get_window_width (); 360 int h = Preferences.get_window_height (); 361 set_default_size (w, h); 362 } 363 364 public void quit () { 365 Gtk.main_quit (); 366 } 367 368 public void file_chooser (string title, FileChooser fc, uint flags) { 369 string? fn = null; 370 bool folder; 371 if (BirdFont.get_arguments () .has_argument ("--windows")) { 372 folder = (flags & FileChooser.DIRECTORY) > 0; 373 MenuTab.show_file_dialog_tab (title, fc, folder); 374 } else { 375 if ((flags & FileChooser.DIRECTORY) > 0) { 376 if ((flags & FileChooser.LOAD) > 0) { 377 fn = show_file_chooser (title, FileChooserAction.SELECT_FOLDER, Stock.OPEN); 378 } else if ((flags & FileChooser.SAVE) > 0) { 379 fn = show_file_chooser (title, FileChooserAction.SELECT_FOLDER, Stock.SAVE); 380 } else { 381 warning ("Open or save is not set."); 382 } 383 } else if ((flags & FileChooser.LOAD) > 0) { 384 fn = show_file_chooser (title, FileChooserAction.OPEN, Stock.OPEN); 385 } else if ((flags & FileChooser.SAVE) > 0) { 386 fn = show_file_chooser (title, FileChooserAction.SAVE, Stock.SAVE); 387 } else { 388 warning ("Unknown type"); 389 } 390 } 391 392 fc.selected (fn); 393 } 394 395 public string? show_file_chooser (string title, FileChooserAction action, string label) { 396 string? fn = null; 397 FileChooserDialog file_chooser = new FileChooserDialog (title, this, action, Stock.CANCEL, ResponseType.CANCEL, label, ResponseType.ACCEPT); 398 Font font = BirdFont.get_current_font (); 399 int i; 400 string last_folder; 401 402 last_folder = Preferences.get ("last_folder"); 403 404 try { 405 if (last_folder == "") { 406 file_chooser.set_current_folder_file (font.get_folder ()); 407 } else { 408 file_chooser.set_current_folder_file (File.new_for_path (last_folder)); 409 } 410 } catch (GLib.Error e) { 411 stderr.printf (e.message); 412 } 413 414 if (file_chooser.run () == ResponseType.ACCEPT) { 415 GlyphCanvas.redraw (); 416 fn = file_chooser.get_filename (); 417 } 418 419 file_chooser.destroy (); 420 421 if (fn != null) { 422 i = ((!) fn).last_index_of ("/"); 423 if (i > -1) { 424 last_folder = ((!) fn).substring (0, i); 425 Preferences.set ("last_folder", @"$last_folder"); 426 } 427 } 428 429 return fn; 430 } 431 432 public void hide_text_input () { 433 text_listener = new TextListener ("", "", ""); 434 text_box.hide (); 435 text_input_is_active = false; 436 } 437 438 public void set_text_listener (TextListener listener) { 439 text_listener = listener; 440 text_input_label.set_text (" " + listener.label); 441 submit_text_button.set_label (listener.button_label); 442 text_box.show (); 443 text_entry.set_text (listener.default_text); 444 text_entry.activate.connect (() => { 445 text_listener.signal_submit (text_entry.text); 446 text_input_is_active = false; 447 }); 448 text_entry.grab_focus (); 449 text_input_is_active = true; 450 } 451 452 public bool convert_to_png (string from, string to) { 453 Pixbuf pixbuf; 454 string folder; 455 int i; 456 457 try { 458 i = to.last_index_of ("/"); 459 if (i != -1) { 460 folder = to.substring (0, i); 461 DirUtils.create (folder, 0xFFFFFF); 462 } 463 464 pixbuf = new Pixbuf.from_file (from); 465 pixbuf.save (to, "png"); 466 } catch (GLib.Error e) { 467 warning (e.message); 468 return false; 469 } 470 471 return true; 472 } 473 474 public void run_background_thread (Task t) { 475 unowned Thread<void*> bg; 476 477 MenuTab.start_background_thread (); 478 background_task = t; 479 480 try { 481 bg = Thread.create<void*> (this.background_thread, true); 482 } catch (GLib.Error e) { 483 warning (e.message); 484 } 485 } 486 487 public void run_non_blocking_background_thread (Task t) { 488 unowned Thread<void*> bg; 489 490 try { 491 bg = Thread.create<void*> (t.perform_task, true); 492 } catch (GLib.Error e) { 493 warning (e.message); 494 } 495 } 496 497 public void* background_thread () { 498 background_task.run (); 499 MenuTab.stop_background_thread (); 500 return null; 501 } 502 503 /** Run export in a background thread. */ 504 public void export_font () { 505 unowned Thread<void*> export_thread; 506 507 MenuTab.start_background_thread (); 508 509 try { 510 export_thread = Thread.create<void*> (this.export_thread, true); 511 } catch (GLib.Error e) { 512 warning (e.message); 513 } 514 } 515 516 public void* export_thread () { 517 IdleSource idle = new IdleSource (); 518 519 ExportCallback.export_fonts (); 520 MenuTab.stop_background_thread (); 521 MenuTab.signal_file_exported (); 522 523 idle.set_callback (() => { 524 Notify.Notification export_notification; 525 export_notification = new Notify.Notification ("BirdFont", t_("Your fonts have been exported."), null); 526 export_notification.show (); 527 return false; 528 }); 529 idle.attach (null); 530 531 return null; 532 } 533 534 /** Load font in a background thread. */ 535 public void load () { 536 unowned Thread<void*> thread; 537 538 MenuTab.start_background_thread (); 539 540 try { 541 thread = Thread.create<void*> (this.loading_thread, true); 542 } catch (GLib.Error e) { 543 warning (e.message); 544 } 545 } 546 547 public void* loading_thread () { 548 BirdFont.get_current_font ().load (); 549 MenuTab.stop_background_thread (); 550 MenuTab.signal_file_loaded (); 551 return null; 552 } 553 554 /** Save font in a background thread. */ 555 public void save () { 556 unowned Thread<void*> thread; 557 558 MenuTab.start_background_thread (); 559 560 try { 561 thread = Thread.create<void*> (this.saving_thread, true); 562 } catch (GLib.Error e) { 563 warning (e.message); 564 } 565 } 566 567 public void* saving_thread () { 568 BirdFont.get_current_font ().save (); 569 MenuTab.stop_background_thread (); 570 MenuTab.signal_file_saved (); 571 return null; 572 } 573 574 public void load_background_image () { 575 unowned Thread<void*> thread; 576 577 MenuTab.start_background_thread (); 578 579 try { 580 thread = Thread.create<void*> (this.background_image_thread, true); 581 } catch (GLib.Error e) { 582 warning (e.message); 583 } 584 } 585 586 public void* background_image_thread () { 587 BackgroundTool.load_background_image (); 588 MenuTab.stop_background_thread (); 589 return null; 590 } 591 592 public bool can_export () { 593 return true; 594 } 595 596 public void set_cursor (int visible) { 597 if (visible != NativeWindow.VISIBLE) { 598 get_window ().set_cursor (new Cursor (CursorType.BLANK_CURSOR)); 599 } else { 600 get_window ().set_cursor (new Cursor (CursorType.ARROW)); 601 } 602 } 603 604 public double get_screen_scale () { 605 string? scale = Environment.get_variable ("GDK_SCALE"); 606 double factor; 607 608 if (scale == null) { 609 return 1; 610 } 611 612 if (double.try_parse ((!) scale, out factor)) { 613 return factor; 614 } 615 616 return 1; 617 } 618 } 619 620 class TabbarCanvas : DrawingArea { 621 TabBar tabbar; 622 623 public TabbarCanvas (TabBar tb) { 624 tabbar = tb; 625 626 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK); 627 628 motion_notify_event.connect ((t, e)=> { 629 Gtk.Allocation alloc; 630 tabbar.motion (e.x, e.y); 631 get_allocation (out alloc); 632 queue_draw_area (0, 0, alloc.width, alloc.height); 633 return true; 634 }); 635 636 button_press_event.connect ((t, e)=> { 637 Gtk.Allocation alloc; 638 get_allocation (out alloc); 639 GtkWindow.reset_modifier (e.state); 640 tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height); 641 queue_draw_area (0, 0, alloc.width, alloc.height); 642 return true; 643 }); 644 645 draw.connect ((t, e)=> { 646 Gtk.Allocation alloc; 647 Context cr; 648 StyleContext context; 649 Gdk.RGBA color; 650 651 cr = cairo_create (get_window ()); 652 get_allocation (out alloc); 653 654 context = get_style_context (); 655 context.add_class (STYLE_CLASS_BUTTON); 656 color = context.get_background_color (Gtk.StateFlags.NORMAL); 657 658 if (color.alpha > 0) { 659 tabbar.set_background_color (color.red, color.green, color.blue); 660 } 661 662 tabbar.draw (cr, alloc.width, alloc.height); 663 return true; 664 }); 665 666 tabbar.signal_tab_selected.connect ((t) => { 667 Gtk.Allocation alloc; 668 get_allocation (out alloc); 669 queue_draw_area (0, 0, alloc.width, alloc.height); 670 }); 671 672 tabbar.redraw_tab_bar.connect ((x, y, w, h) => { 673 queue_draw_area (x, y, w, h); 674 }); 675 676 set_size_request (20, 38); 677 } 678 679 } 680 681 class ToolboxCanvas : DrawingArea { 682 Toolbox tb; 683 684 public ToolboxCanvas (Toolbox toolbox) { 685 tb = toolbox; 686 687 realize.connect (() => { 688 Gtk.Allocation allocation; 689 get_allocation (out allocation); 690 Toolbox.allocation_width = allocation.width; 691 Toolbox.allocation_height = allocation.height; 692 Toolbox.redraw_tool_box (); 693 }); 694 695 tb.redraw.connect ((x, y, w, h) => { 696 queue_draw_area (x, y, w, h); 697 }); 698 699 button_press_event.connect ((se, e)=> { 700 if (e.type == EventType.2BUTTON_PRESS) { 701 tb.double_click (e.button, e.x, e.y); 702 } else { 703 tb.press (e.button, e.x, e.y); 704 } 705 return true; 706 }); 707 708 button_release_event.connect ((se, e)=> { 709 tb.release (e.button, e.x, e.y); 710 return true; 711 }); 712 713 motion_notify_event.connect ((sen, e)=> { 714 // FIXME: e.y is two pixels off in GTK under Gnome 715 tb.move (e.x, e.y); 716 return true; 717 }); 718 719 draw.connect ((t, e)=> { 720 Gtk.Allocation allocation; 721 get_allocation (out allocation); 722 723 Context cw = cairo_create(get_window()); 724 Toolbox.allocation_width = allocation.width; 725 Toolbox.allocation_height = allocation.height; 726 tb.draw (allocation.width, allocation.height, cw); 727 728 return true; 729 }); 730 731 scroll_event.connect ((t, e)=> { 732 if (e.direction == Gdk.ScrollDirection.UP) { 733 tb.scroll_up (e.x, e.y); 734 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 735 tb.scroll_down (e.x, e.y); 736 } 737 return true; 738 }); 739 740 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK); 741 742 set_size_request (212, 100); 743 744 leave_notify_event.connect ((t, e)=> { 745 tb.reset_active_tool (); 746 return true; 747 }); 748 749 } 750 } 751 752 public class GlyphCanvasArea : DrawingArea { 753 GlyphCanvas glyph_canvas; 754 WidgetAllocation alloc = new WidgetAllocation (); 755 uint32 last_release = 0; 756 uint32 last_press = 0; 757 758 public GlyphCanvasArea (GlyphCanvas gc) { 759 int event_flags; 760 761 glyph_canvas = gc; 762 763 event_flags = EventMask.BUTTON_PRESS_MASK; 764 event_flags |= EventMask.BUTTON_RELEASE_MASK; 765 event_flags |= EventMask.POINTER_MOTION_MASK; 766 event_flags |= EventMask.LEAVE_NOTIFY_MASK; 767 event_flags |= EventMask.SCROLL_MASK; 768 769 add_events (event_flags); 770 771 bool button_down = false; 772 773 glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => { 774 queue_draw_area ((int)x, (int)y, (int)w, (int)h); 775 }); 776 777 draw.connect ((t, e)=> { 778 Gtk.Allocation allocation; 779 get_allocation (out allocation); 780 781 alloc = new WidgetAllocation (); 782 783 alloc.width = allocation.width; 784 alloc.height = allocation.height; 785 alloc.x = allocation.x; 786 alloc.y = allocation.y; 787 788 Context cw = cairo_create (get_window()); 789 790 Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); 791 Context c = new Context (s); 792 793 TabContent.draw (alloc, c); 794 795 cw.save (); 796 cw.set_source_surface (c.get_target (), 0, 0); 797 cw.paint (); 798 cw.restore (); 799 800 return true; 801 }); 802 803 button_press_event.connect ((t, e)=> { 804 GtkWindow.reset_modifier (e.state); 805 806 if (button_down) { 807 warning (@"Button already is down. $(e.button)"); 808 } 809 810 if (e.time < last_press) { 811 warning ("Discarding event."); 812 return true; 813 } 814 815 last_press = e.time; 816 817 if (e.type == EventType.BUTTON_PRESS) { 818 TabContent.button_press (e.button, e.x, e.y); 819 button_down = true; 820 } else if (e.type == EventType.2BUTTON_PRESS) { 821 TabContent.double_click (e.button, e.x, e.y); 822 } 823 824 return true; 825 }); 826 827 button_release_event.connect ((t, e)=> { 828 if (!button_down) { 829 warning (@"Button is not down $(e.button)"); 830 } 831 832 if (e.time < last_release) { 833 warning ("Discarding event."); 834 return true; 835 } 836 837 if (e.type == EventType.BUTTON_RELEASE) { 838 TabContent.button_release ((int) e.button, e.x, e.y); 839 last_release = e.time; 840 button_down = false; 841 } 842 843 return true; 844 }); 845 846 motion_notify_event.connect ((t, e)=> { 847 TabContent.motion_notify (e.x, e.y); 848 return true; 849 }); 850 851 scroll_event.connect ((t, e)=> { 852 if (e.direction == Gdk.ScrollDirection.UP) { 853 TabContent.scroll_wheel_up (e.x, e.y); 854 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 855 TabContent.scroll_wheel_down (e.x, e.y) ; 856 } 857 858 TabContent.button_release (2, e.x, e.y); 859 return true; 860 }); 861 862 can_focus = true; 863 } 864 } 865 866 } 867