Back to index

texmacs  1.0.7.15
aqua_gui.mm
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : aqua_gui.mm
00004 * DESCRIPTION: Cocoa display class
00005 * COPYRIGHT  : (C) 2006 Massimiliano Gubinelli
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 
00013 #include "iterator.hpp"
00014 #include "dictionary.hpp"
00015 #include "aqua_gui.h"
00016 #include "analyze.hpp"
00017 #include <locale.h>
00018 #include "language.hpp"
00019 #include "message.hpp"
00020 #include "aqua_renderer.h" // for the_aqua_renderer
00021 
00022 //extern hashmap<id, pointer> NSWindow_to_window;
00023 //extern window (*get_current_window) (void);
00024 
00025 aqua_gui_rep* the_gui= NULL;
00026 
00027 int nr_windows = 0; // FIXME: fake variable, referenced in tm_server
00028 
00029 bool aqua_update_flag= false;
00030 
00031 int time_credit;
00032 int timeout_time;
00033 
00034 /******************************************************************************
00035  * Constructor and geometry
00036  ******************************************************************************/
00037 
00038 
00039 aqua_gui_rep::aqua_gui_rep(int& argc, char** argv): 
00040   interrupted(false), selection(NULL)
00041 {
00042   (void) argc; (void) argv;
00043 //  argc               = argc2;
00044 //  argv               = argv2;
00045   interrupted        = false;
00046   interrupt_time     = texmacs_time ();
00047   
00048   set_output_language (get_locale_language ());
00049   // out_lan= get_locale_language ();
00050 //  (void) default_font ();
00051 }
00052 
00053 
00054 /* important routines */
00055 void
00056 aqua_gui_rep::get_extents (SI& width, SI& height) {
00057   NSRect bounds = [[NSScreen mainScreen] visibleFrame];
00058   
00059   width = ((SI) bounds.size.width)  * PIXEL;
00060   height= ((SI) bounds.size.height) * PIXEL;
00061 }
00062 
00063 void
00064 aqua_gui_rep::get_max_size (SI& width, SI& height) {
00065   width = 8000 * PIXEL;
00066   height= 6000 * PIXEL;
00067 }
00068 
00069 /******************************************************************************
00070  * interclient communication
00071  ******************************************************************************/
00072 
00073 bool
00074 aqua_gui_rep::get_selection (string key, tree& t, string& s) {
00075   t= "none";
00076   s= "";
00077   if (selection_t->contains (key)) {
00078     t= copy (selection_t [key]);
00079     s= copy (selection_s [key]);
00080     return true;
00081   }
00082   if (key != "primary") return false;
00083   
00084        NSPasteboard *pb = [NSPasteboard generalPasteboard];
00085        NSArray *types = [NSArray arrayWithObject:NSStringPboardType];
00086        NSString *bestType = [pb availableTypeFromArray:types];
00087 
00088        if (bestType != nil) {
00089               NSString* data = [pb stringForType:bestType];
00090               if (data) {
00091               char *buf = (char*)[data UTF8String];
00092                      unsigned size = strlen(buf);
00093               s << string(buf, size);
00094               }
00095        }
00096 
00097 
00098   t= tuple ("extern", s);
00099   return true;
00100 }
00101 
00102 bool
00103 aqua_gui_rep::set_selection (string key, tree t, string s) {
00104   selection_t (key)= copy (t);
00105   selection_s (key)= copy (s);
00106   if (key == "primary") {
00107     //if (is_nil (windows_l)) return false;
00108     //Window win= windows_l->item;
00109     if (selection!=NULL) tm_delete_array (selection);
00110     //XSetSelectionOwner (dpy, XA_PRIMARY, win, CurrentTime);
00111     //if (XGetSelectionOwner(dpy, XA_PRIMARY)==None) return false;
00112     selection= as_charp (s);
00113        
00114        NSPasteboard *pb = [NSPasteboard generalPasteboard];
00115        NSArray *types = [NSArray arrayWithObjects:
00116               NSStringPboardType, nil];
00117        [pb declareTypes:types owner:nil];
00118        [pb setString:[NSString stringWithCString:selection] forType:NSStringPboardType];
00119        
00120        
00121   }
00122   return true;
00123 }
00124 
00125 void
00126 aqua_gui_rep::clear_selection (string key) {
00127   selection_t->reset (key);
00128   selection_s->reset (key);
00129   if ((key == "primary") && (selection != NULL)) {
00130     tm_delete_array (selection);
00131        // FIXME: should we do something with the pasteboard?
00132     selection= NULL;
00133   }
00134 }
00135 
00136 
00137 /******************************************************************************
00138  * Miscellaneous
00139  ******************************************************************************/
00140 
00141 void aqua_gui_rep::image_gc (string name) { (void) name; }
00142 // FIXME: remove this unused function
00143 void aqua_gui_rep::set_mouse_pointer (string name) { (void) name; }
00144 // FIXME: implement this function
00145 void aqua_gui_rep::set_mouse_pointer (string curs_name, string mask_name)  { (void) curs_name; (void) mask_name; } ;
00146 
00147 /******************************************************************************
00148  * Main loop
00149  ******************************************************************************/
00150 
00151 static bool check_mask(int mask)
00152 {
00153   NSEvent * event = [NSApp nextEventMatchingMask:mask
00154                              untilDate:nil
00155                                 inMode:NSDefaultRunLoopMode 
00156                                dequeue:NO];
00157  // if (event != nil) NSLog(@"%@",event);
00158   return (event != nil);
00159   
00160 }
00161 
00162 #if 0
00163 bool
00164 aqua_gui_rep::check_event (int type) {
00165   switch (type) {
00166     case INTERRUPT_EVENT:
00167       if (interrupted) return true;
00168       else  {
00169         time_t now= texmacs_time ();
00170         if (now - interrupt_time < 0) return false;
00171 //        else interrupt_time= now + (100 / (XPending (dpy) + 1));
00172         else interrupt_time= now + 100;
00173         interrupted= check_mask(NSKeyDownMask |
00174                                // NSKeyUpMask |
00175                                 NSLeftMouseDownMask |
00176                                 NSLeftMouseUpMask |
00177                                 NSRightMouseDownMask |
00178                                 NSRightMouseUpMask );
00179         return interrupted;
00180       }
00181       case INTERRUPTED_EVENT:
00182         return interrupted;
00183       case ANY_EVENT:
00184         return check_mask(NSAnyEventMask);
00185       case MOTION_EVENT:
00186         return check_mask(NSMouseMovedMask);
00187       case DRAG_EVENT:
00188         return check_mask(NSLeftMouseDraggedMask|NSRightMouseDraggedMask);
00189       case MENU_EVENT:
00190         return check_mask(NSLeftMouseDownMask |
00191                           NSLeftMouseUpMask |
00192                           NSRightMouseDownMask |
00193                           NSRightMouseUpMask );
00194   }
00195   return interrupted;
00196 }
00197 #else
00198 bool
00199 aqua_gui_rep::check_event (int type) {
00200   return false;
00201 }
00202 #endif
00203 
00204 void
00205 aqua_gui_rep::show_wait_indicator (widget w, string message, string arg) {
00206 }
00207 
00208 
00209 void (*the_interpose_handler) (void) = NULL;
00210 //void set_interpose_handler (void (*r) (void)) { the_interpose_handler= r; }
00211 void gui_interpose (void (*r) (void)) { the_interpose_handler= r; }
00212 
00213 void update()
00214 {
00215        //NSBeep();
00216        if (the_interpose_handler) the_interpose_handler();
00217 }
00218 
00219 void aqua_gui_rep::update ()
00220 {
00221 //  NSLog(@"UPDATE----------------------------");
00222   ::update();
00223 }
00224 
00225 
00226 
00227 
00228 @interface TMHelper : NSObject
00229 {
00230 }
00231 @end
00232 @implementation TMHelper
00233 - init
00234 {
00235   if (self = [super init])
00236   {
00237               [NSApp setDelegate:self];
00238   }
00239   return self;
00240 }
00241 
00242 - (void)applicationWillUpdate:(NSNotification *)aNotification
00243 {
00244 //     NSBeep();
00245        update();
00246 }
00247 - (void)dealloc
00248 {
00249        [NSApp setDelegate:nil];
00250   [super dealloc];
00251 }
00252 @end
00253 
00254 
00255 @interface TMInterposer : NSObject
00256 {  
00257        NSNotification *n;
00258 }
00259 - (void)interposeNow;
00260 -(void)waitIdle;
00261 @end
00262 
00263 @implementation TMInterposer
00264 - init
00265 {
00266   if (self = [super init])
00267   {
00268        //     n = [[NSNotification notificationWithName:@"TMInterposeNotification" object:self] retain];
00269    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interposeNow) name:@"TMInterposeNotification" object:nil];
00270                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interposeNow) name:NSApplicationWillUpdateNotification object:nil];
00271        //     [self waitIdle];
00272   }
00273   return self;
00274 }
00275 - (void)dealloc
00276 {
00277        //[n release];
00278   [[NSNotificationCenter defaultCenter] removeObserver:self];
00279   [super dealloc];
00280 }
00281 
00282 - (void)interposeNow
00283 {
00284 //     NSBeep();
00285        update();
00286        //[self performSelector:@selector(waitIdle) withObject:nil afterDelay:0.25 inModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, nil]];
00287 }
00288 -(void)waitIdle
00289 {
00290        [[NSNotificationQueue defaultQueue] enqueueNotification:n 
00291                                                                                                                                                            postingStyle:NSPostWhenIdle
00292                                                                                                                                                            coalesceMask:NSNotificationCoalescingOnName 
00293                                                                                                                                                                          forModes:nil];
00294 }
00295 
00296 @end
00297 
00298 
00299 
00300 //@class FScriptMenuItem;
00301 
00302 void aqua_gui_rep::event_loop ()
00303 #if 0
00304 {
00305 //     TMInterposer* i = [[TMInterposer alloc ] init];
00306        //[[NSApp mainMenu] addItem:[[[FScriptMenuItem alloc] init] autorelease]];
00307 //     update();
00308        [[[TMHelper alloc] init] autorelease];
00309        [NSApp run];
00310 //     [i release];
00311 }
00312 #else
00313 {
00314 //     [[NSApp mainMenu] addItem:[[[FScriptMenuItem alloc] init] autorelease]];
00315        [NSApp finishLaunching];
00316        {
00317        NSEvent *event = nil;
00318     time_credit= 1000000;
00319 
00320   while (1) {
00321     timeout_time= texmacs_time () + time_credit;
00322 
00323     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00324                      NSDate *dateSlow = [NSDate dateWithTimeIntervalSinceNow:0.5];
00325               event= //[NSDate distantFuture] [NSApp nextEventMatchingMask:NSAnyEventMask untilDate: dateSlow 
00326                                                                                                                  inMode:NSDefaultRunLoopMode dequeue:YES];              
00327               while (event)
00328               {
00329                      [NSApp sendEvent:event];
00330               //     update();
00331                      //NSDate *dateFast = [NSDate dateWithTimeIntervalSinceNow:0.001];
00332                      event= // dateFast [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] 
00333                                                                                                                         inMode:NSDefaultRunLoopMode dequeue:YES];
00334               }
00335               interrupted = false;
00336     if (!event)  {
00337        update();
00338       time_credit= min (1000000, 2 * time_credit);
00339       aqua_update_flag= false;
00340     }
00341     [pool release];
00342   }  
00343        }
00344 }
00345 #endif
00346 
00347 
00348 
00349 
00350 aqua_gui_rep::~aqua_gui_rep() 
00351 { 
00352 } 
00353 
00354 
00355 
00356 /* interface ******************************************************************/
00357 #pragma mark GUI interface
00358 
00359 //static display cur_display= NULL;
00360 
00361 static NSAutoreleasePool *pool = nil;
00362 //static NSApplication *app = nil;
00363 
00364 
00365 
00366 /******************************************************************************
00367 * Main routines
00368 ******************************************************************************/
00369 
00370 void gui_open (int& argc2, char** argv2)
00371   // start the gui
00372 {
00373   if (!NSApp) {
00374     // initialize app
00375     [NSApplication sharedApplication];
00376     [NSBundle loadNibNamed:@"MainMenu" owner:NSApp];
00377   }
00378   if (!pool) {
00379     // create autorelease pool 
00380     pool = [[NSAutoreleasePool alloc] init];
00381   } else [pool retain];
00382   
00383   the_gui = tm_new <aqua_gui_rep> (argc2, argv2);
00384 }
00385 
00386 void gui_start_loop ()
00387   // start the main loop
00388 {
00389   the_gui->event_loop ();
00390 }
00391 
00392 void gui_close ()
00393   // cleanly close the gui
00394 {
00395   ASSERT (the_gui != NULL, "gui not yet open");
00396   [pool release];
00397   tm_delete (the_gui);
00398   the_gui=NULL;
00399 }
00400 void
00401 gui_root_extents (SI& width, SI& height) {   
00402        // get the screen size
00403   the_gui->get_extents (width, height);
00404 }
00405 
00406 void
00407 gui_maximal_extents (SI& width, SI& height) {
00408   // get the maximal size of a window (can be larger than the screen size)
00409   the_gui->get_max_size (width, height);
00410 }
00411 
00412 void gui_refresh ()
00413 {
00414   // update and redraw all windows (e.g. on change of output language)
00415   // FIXME: add suitable code
00416 }
00417 
00418 
00419 
00420 /******************************************************************************
00421 * Font support
00422 ******************************************************************************/
00423 
00424 void
00425 set_default_font (string name) {
00426        (void) name;
00427   // set the name of the default font
00428   // this is ignored since Qt handles fonts for the widgets
00429 }
00430 
00431 font
00432 get_default_font (bool tt, bool mini, bool bold) {
00433   (void) tt; (void) mini;
00434   // get the default font or monospaced font (if tt is true)
00435        
00436   // return a null font since this function is not called in the Qt port.
00437   if (DEBUG_EVENTS) cout << "get_default_font(): SHOULD NOT BE CALLED\n";
00438   return NULL;
00439   //return tex_font (this, "ecrm", 10, 300, 0);
00440 }
00441 
00442 // load the metric and glyphs of a system font
00443 // you are not obliged to provide any system fonts
00444 
00445 void
00446 load_system_font (string family, int size, int dpi,
00447                   font_metric& fnm, font_glyphs& fng)
00448 {
00449        (void) family; (void) size; (void) dpi; (void) fnm; (void) fng;
00450        if (DEBUG_EVENTS) cout << "load_system_font(): SHOULD NOT BE CALLED\n";
00451 }
00452 
00453 /******************************************************************************
00454 * Clipboard support
00455 ******************************************************************************/
00456 
00457   // Copy a selection 't' with string equivalent 's' to the clipboard 'cb'
00458   // Returns true on success
00459 bool
00460 set_selection (string key, tree t, string s, string format) {
00461   (void) format;
00462   return the_gui->set_selection (key, t, s);
00463 }
00464 
00465   // Retrieve the selection 't' with string equivalent 's' from clipboard 'cb'
00466   // Returns true on success; sets t to (extern s) for external selections
00467 bool
00468 get_selection (string key, tree& t, string& s, string format) { 
00469   (void) format;
00470   return the_gui->get_selection (key, t, s);
00471 }
00472 
00473   // Clear the selection on clipboard 'cb'
00474 void
00475 clear_selection (string key) {
00476   the_gui->clear_selection (key);
00477 }
00478 
00479 
00480 /******************************************************************************
00481 * Miscellaneous
00482 ******************************************************************************/
00483 int char_clip=0;
00484 
00485 void 
00486 beep () {
00487   // Issue a beep
00488   NSBeep();
00489 }
00490 
00491 void 
00492 needs_update () {
00493   aqua_update_flag= true;
00494 }
00495 
00496 bool check_event (int type)
00497   // Check whether an event of one of the above types has occurred;
00498   // we check for keyboard events while repainting windows
00499 { return the_gui->check_event(type); }
00500 
00501 void image_gc (string name) {
00502   // Garbage collect images of a given name (may use wildcards)
00503   // This routine only needs to be implemented if you use your own image cache
00504   the_aqua_renderer()->image_gc(name); 
00505 }
00506 
00507 void
00508 show_help_balloon (widget balloon, SI x, SI y) { 
00509   // Display a help balloon at position (x, y); the help balloon should
00510   // disappear as soon as the user presses a key or moves the mouse
00511   (void) balloon; (void) x; (void) y;
00512 }
00513 
00514 void
00515 show_wait_indicator (widget base, string message, string argument) {
00516   // Display a wait indicator with a message and an optional argument
00517   // The indicator might for instance be displayed at the center of
00518   // the base widget which triggered the lengthy operation;
00519   // the indicator should be removed if the message is empty
00520   the_gui->show_wait_indicator(base,message,argument); 
00521 }
00522 
00523 void
00524 external_event (string type, time_t t) {
00525   // External events, such as pushing a button of a remote infrared commander
00526 #if 0
00527   QTMWidget *tm_focus = qobject_cast<QTMWidget*>(qApp->focusWidget());
00528   if (tm_focus) {
00529     simple_widget_rep *wid = tm_focus->tm_widget();
00530     if (wid) the_gui -> process_keypress (wid, type, t);
00531   }
00532 #endif
00533 }
00534 
00535 font x_font (string family, int size, int dpi)
00536 {
00537   (void) family; (void) size; (void) dpi;
00538   if (DEBUG_EVENTS) cout << "x_font(): SHOULD NOT BE CALLED\n";
00539   return NULL;
00540 }
00541