📄 cocoa_gui.mm
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA#undef WITH_COCOA_AUDIO#include "ambulant/gui/cocoa/cocoa_gui.h"#include "ambulant/gui/cocoa/cocoa_audio.h"#include "ambulant/gui/cocoa/cocoa_text.h"#include "ambulant/gui/cocoa/cocoa_html.h"#include "ambulant/gui/cocoa/cocoa_image.h"#include "ambulant/gui/cocoa/cocoa_fill.h"#include "ambulant/gui/cocoa/cocoa_video.h"#include "ambulant/gui/cocoa/cocoa_dsvideo.h"#include "ambulant/lib/mtsync.h"#include "ambulant/common/preferences.h"#include <Cocoa/Cocoa.h>// Defines for image dump debugging#define DUMP_IMAGES_FORMAT @"/tmp/amdump/ambulant_dump_%03d_%s.tiff"//#define DUMP_REDRAW//#define DUMP_TRANSITION//#define AM_DBG#ifndef AM_DBG#define AM_DBG if(0)#endif//static ambulant::lib::critical_section redraw_lock;namespace ambulant {using namespace lib;namespace gui {namespace cocoa {common::window_factory *create_cocoa_window_factory(void *view){ return new cocoa_window_factory(view);}common::playable_factory *create_cocoa_renderer_factory(common::factories *factory){ return new cocoa_renderer_factory(factory);}cocoa_window::~cocoa_window(){ if (m_view) { AmbulantView *my_view = (AmbulantView *)m_view; [my_view ambulantWindowClosed]; } m_view = NULL;} voidcocoa_window::need_redraw(const rect &r){ AM_DBG logger::get_logger()->debug("cocoa_cocoa_window::need_redraw(0x%x, ltrb=(%d,%d,%d,%d))", (void *)this, r.left(), r.top(), r.right(), r.bottom()); if (!m_view) { logger::get_logger()->fatal("cocoa_cocoa_window::need_redraw: no m_view"); return; } AmbulantView *my_view = (AmbulantView *)m_view; NSRect my_rect = [my_view NSRectForAmbulantRect: &r]; NSRectHolder *arect = [[NSRectHolder alloc] initWithRect: my_rect]; // XXX Is it safe to cast C++ objects to ObjC id's? [my_view performSelectorOnMainThread: @selector(asyncRedrawForAmbulantRect:) withObject: arect waitUntilDone: NO];}voidcocoa_window::redraw_now(){ AmbulantView *my_view = (AmbulantView *)m_view; [my_view performSelectorOnMainThread: @selector(syncDisplayIfNeeded:) withObject: nil waitUntilDone: YES];}voidcocoa_window::redraw(const rect &r){ AM_DBG logger::get_logger()->debug("cocoa_window::redraw(0x%x, ltrb=(%d,%d,%d,%d))", (void *)this, r.left(), r.top(), r.right(), r.bottom()); m_handler->redraw(r, this);}voidcocoa_window::user_event(const point &where, int what){ AM_DBG logger::get_logger()->debug("cocoa_window::user_event(0x%x, (%d, %d), %d)", (void *)this, where.x, where.y, what); m_handler->user_event(where, what);}voidcocoa_window::need_events(bool want){ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; AM_DBG logger::get_logger()->debug("cocoa_window::need_events(0x%x, %d)", (void *)this, want); AmbulantView *my_view = (AmbulantView *)m_view; NSWindow *my_window = [my_view window]; AM_DBG NSLog(@"my_window acceptsMouseMovedEvents = %d", [my_window acceptsMouseMovedEvents]); // Synthesize a mouseMoved event NSPoint where = [my_window mouseLocationOutsideOfEventStream]; if (!NSPointInRect(where, [my_view frame])) { AM_DBG NSLog(@"mouse outside our frame"); return; } // Convert from window to frame coordinates where.x -= NSMinX([my_view frame]); where.y -= NSMinY([my_view frame]);#ifndef USE_COCOA_BOTLEFT // Mouse clicks are not flipped, even if the view is where.y = NSMaxY([my_view bounds]) - where.y;#endif AM_DBG NSLog(@"pseudoMouseMoved at (%f, %f)", where.x, where.y); ambulant::lib::point amwhere = ambulant::lib::point((int)where.x, (int)where.y); // XXX Set correct cursor [[NSApplication sharedApplication] sendAction: SEL("resetMouse:") to: nil from: my_view]; user_event(amwhere, 1); // XXX Set correct cursor [[NSApplication sharedApplication] sendAction: SEL("fixMouse:") to: nil from: my_view]; [pool release];}playable *cocoa_renderer_factory::new_playable( playable_notification *context, playable_notification::cookie_type cookie, const lib::node *node, event_processor *evp){ playable *rv; xml_string tag = node->get_qname().second; if (tag == "img") { rv = new cocoa_image_renderer(context, cookie, node, evp, m_factory); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_image_renderer 0x%x", (void *)node, (void *)rv); } else if ( tag == "text") { net::url url = net::url(node->get_url("src")); if (url.guesstype() == "text/html") { rv = new cocoa_html_renderer(context, cookie, node, evp); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_html_renderer 0x%x", (void *)node, (void *)rv); } else { rv = new cocoa_text_renderer(context, cookie, node, evp, m_factory); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_text_renderer 0x%x", (void *)node, (void *)rv); } } else if ( tag == "brush") { rv = new cocoa_fill_renderer(context, cookie, node, evp); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_fill_renderer 0x%x", (void *)node, (void *)rv);#ifdef WITH_COCOA_AUDIO } else if ( tag == "audio") { rv = new cocoa_audio_playable(context, cookie, node, evp); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_audio_renderer 0x%x", (void *)node, (void *)rv);#endif } else if ( tag == "video") { if (common::preferences::get_preferences()->m_prefer_ffmpeg ) { rv = new cocoa_dsvideo_renderer(context, cookie, node, evp, m_factory); if (rv) { logger::get_logger()->trace("video: using native Ambulant renderer"); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_dsvideo_renderer 0x%x", (void *)node, (void *)rv); } else { rv = new cocoa_video_renderer(context, cookie, node, evp); if (rv) logger::get_logger()->trace("video: using QuickTime renderer"); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_video_renderer 0x%x", (void *)node, (void *)rv); } } else { rv = new cocoa_video_renderer(context, cookie, node, evp); if (rv) { logger::get_logger()->trace("video: using QuickTime renderer"); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_video_renderer 0x%x", (void *)node, (void *)rv); } else { rv = new cocoa_dsvideo_renderer(context, cookie, node, evp, m_factory); if (rv) logger::get_logger()->trace("video: using ffmpeg renderer"); AM_DBG logger::get_logger()->debug("cocoa_renderer_factory: node 0x%x: returning cocoa_dsvideo_renderer 0x%x", (void *)node, (void *)rv); } } } else { // logger::get_logger()->error(gettext("cocoa_renderer_factory: no Cocoa renderer for tag \"%s\""), tag.c_str()); return NULL; } return rv;}playable *cocoa_renderer_factory::new_aux_audio_playable( playable_notification *context, playable_notification::cookie_type cookie, const lib::node *node, lib::event_processor *evp, net::audio_datasource *src){ return NULL;}lib::sizecocoa_window_factory::get_default_size(){ if (m_defaultwindow_view == NULL) return lib::size(default_layout_width, default_layout_height); NSSize size = [(AmbulantView *)m_defaultwindow_view bounds].size; return lib::size((int)size.width, (int)size.height);}gui_window *cocoa_window_factory::new_window(const std::string &name, size bounds, gui_events *handler){ if ([(AmbulantView *)m_defaultwindow_view isAmbulantWindowInUse]) { // XXXX Should create new toplevel window and put an ambulantview in it logger::get_logger()->error(gettext("Unsupported: AmbulantPlayer cannot open second toplevel window yet")); return NULL; } cocoa_window *window = new cocoa_window(name, bounds, m_defaultwindow_view, handler); // And we need to inform the object about it AmbulantView *view = (AmbulantView *)window->view(); [view setAmbulantWindow: window]; // And set the window size init_window_size(window, name, bounds); return (gui_window *)window;}voidcocoa_window_factory::init_window_size(cocoa_window *window, const std::string &name, lib::size bounds){ AmbulantView *view = (AmbulantView *)window->view(); // Get the position of our view in window coordinates NSPoint origin = NSMakePoint(0,0); NSView *superview = [view superview]; if (superview) { NSRect rect = [superview convertRect: [view frame] toView: nil]; origin = rect.origin; } // And set the window size AM_DBG NSLog(@"Size changed request: (%d, %d)", bounds.w, bounds.h); NSSize cocoa_size = NSMakeSize(bounds.w + origin.x, bounds.h + origin.y); [[view window] setContentSize: cocoa_size]; AM_DBG NSLog(@"Size changed on %@ to (%f, %f)", [view window], cocoa_size.width, cocoa_size.height); [[view window] makeKeyAndOrderFront: view];}common::bgrenderer *cocoa_window_factory::new_background_renderer(const common::region_info *src){ return new cocoa_background_renderer(src);}voidcocoa_gui_screen::get_size(int *width, int *height){ AmbulantView *view = (AmbulantView *)m_view; NSRect bounds = [view bounds]; *width = int(bounds.size.width); *height = int(bounds.size.height);}boolcocoa_gui_screen::get_screenshot(const char *type, char **out_data, size_t *out_size){ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; *out_data = NULL; *out_size = 0; NSBitmapImageFileType filetype; if ( strcmp(type, "tiff") == 0) filetype = NSTIFFFileType; else if (strcmp(type, "bmp") == 0) filetype = NSBMPFileType; else if (strcmp(type, "gif") == 0) filetype = NSGIFFileType; else if (strcmp(type, "jpeg") == 0) filetype = NSJPEGFileType; else if (strcmp(type, "png") == 0) filetype = NSPNGFileType; else { lib::logger::get_logger()->trace("get_screenshot: unknown filetype \"%s\"", type); goto bad; } NSData *data; AmbulantView *view = (AmbulantView *)m_view; NSImage *image = [view _getOnScreenImage]; if (image == NULL) { lib::logger::get_logger()->trace("get_screenshot: cannot get screen shot"); goto bad; } NSImageRep *rep = [image bestRepresentationForDevice: NULL]; if (rep == NULL) { lib::logger::get_logger()->trace("get_screenshot: cannot get representation for screen shot");// [image release]; goto bad; } data = [rep representationUsingType: filetype properties: NULL];// [image release]; if (data == NULL) { lib::logger::get_logger()->trace("get_screenshot: cannot convert screenshot to %s format", type); goto bad; } *out_data = (char *)malloc([data length]); if (*out_data == NULL) { lib::logger::get_logger()->trace("get_screenshot: out of memory");// [data release]; goto bad; } *out_size = [data length]; [data getBytes: *out_data];// [data release]; [pool release]; return true;bad: [pool release]; return false;}boolcocoa_gui_screen::set_overlay(const char *type, const char *data, size_t size){ AmbulantView *view = (AmbulantView *)m_view; lib::logger::get_logger()->trace("set_overlay: not implemented yet"); return false;}boolcocoa_gui_screen::clear_overlay(){ AmbulantView *view = (AmbulantView *)m_view; lib::logger::get_logger()->trace("clear_overlay: not implemented yet"); return false;}} // namespace cocoa} // namespace gui} //namespace ambulant#ifdef __OBJC__@implementation NSRectHolder- (id) initWithRect: (NSRect)r{ rect = r; return self;}- (NSRect)rect
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -