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