Update to 2.0.0 tree from current Fremantle build
[opencv] / src / highgui / window_carbon.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "_highgui.h"
43
44 #include <Carbon/Carbon.h>
45
46 #include <unistd.h>
47 #include <cstdio>
48 #include <cmath>
49
50 //#define MS_TO_TICKS(a) a*3/50
51
52 #define LABELWIDTH 64
53 #define INTERWIDGETSPACE 16
54 #define WIDGETHEIGHT 32
55 #define NO_KEY -1
56
57 struct CvWindow;
58
59 typedef struct CvTrackbar
60 {
61     int signature;
62     
63     ControlRef trackbar;
64     ControlRef label;
65     
66     char* name;
67     CvTrackbar* next;
68     CvWindow* parent;
69     int* data;
70     int pos;
71     int maxval;
72     CvTrackbarCallback notify;
73     CvTrackbarCallback2 notify2;
74     void* userdata;
75 }
76 CvTrackbar;
77
78
79 typedef struct CvWindow
80 {
81     int signature;
82     
83     char* name;
84     CvWindow* prev;
85     CvWindow* next;
86     
87     WindowRef window;
88     CGImageRef imageRef;
89     int imageWidth;//FD
90     int imageHeight;//FD
91         
92     CvMat* image;
93     CvMat* dst_image;
94     int converted;
95     int last_key;
96     int flags;
97     
98     CvMouseCallback on_mouse;
99     void* on_mouse_param;
100     
101     struct {
102         int pos;
103         int rows;
104         CvTrackbar* first;
105     }
106     toolbar;
107     int trackbarheight;
108 }
109 CvWindow;
110
111 static CvWindow* hg_windows = 0;
112
113 #define Assert(exp)                                             \
114 if( !(exp) )                                                    \
115 {                                                               \
116     printf("Assertion: %s  %s: %d\n", #exp, __FILE__, __LINE__);\
117     assert(exp);                                                \
118 }
119
120 static int wasInitialized = 0;    
121 static char lastKey = NO_KEY;
122 OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData);
123 static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData);
124
125 static const EventTypeSpec applicationKeyboardEvents[] = 
126 {
127     { kEventClassKeyboard, kEventRawKeyDown },
128 };
129
130 CV_IMPL int cvInitSystem( int argc, char** argv )
131 {
132     OSErr err = noErr;
133     if( !wasInitialized ) 
134     {
135     
136         hg_windows = 0;
137         err = InstallApplicationEventHandler(NewEventHandlerUPP( keyHandler),GetEventTypeCount(applicationKeyboardEvents),applicationKeyboardEvents,NULL,NULL);
138         if (err != noErr)
139         {
140              fprintf(stderr,"InstallApplicationEventHandler was not ok\n");
141         }
142         wasInitialized = 1;
143     }
144     
145     return 0;
146 }
147
148 // TODO: implement missing functionality
149 CV_IMPL int cvStartWindowThread()
150 {
151     return 0;
152 }
153
154 static int icvCountTrackbarInWindow( const CvWindow* window)
155 {
156     CvTrackbar* trackbar = window->toolbar.first;
157     int count = 0;
158     while (trackbar != 0) {
159         count++;
160         trackbar = trackbar->next;
161     }
162     return count;
163 }
164
165 static CvTrackbar* icvTrackbarByHandle( void * handle )
166 {
167     CvWindow* window = hg_windows;
168     CvTrackbar* trackbar = NULL;
169     while( window != 0 && window->window != handle) {
170         trackbar = window->toolbar.first;
171         while (trackbar != 0 && trackbar->trackbar != handle)
172             trackbar = trackbar->next;
173         if (trackbar != 0 && trackbar->trackbar == handle)
174             break;
175         window = window->next;
176     }
177     return trackbar;
178 }
179
180 static CvWindow* icvWindowByHandle( void * handle )
181 {
182     CvWindow* window = hg_windows;
183     
184     while( window != 0 && window->window != handle)
185         window = window->next;
186     
187     return window;
188 }
189
190 CV_IMPL CvWindow * icvFindWindowByName( const char* name)
191 {
192     CvWindow* window = hg_windows;
193     while( window != 0 && strcmp(name, window->name) != 0 ) 
194                 window = window->next;
195         
196     return window;
197 }
198
199 static CvTrackbar* icvFindTrackbarByName( const CvWindow* window, const char* name )
200 {
201     CvTrackbar* trackbar = window->toolbar.first;
202     
203     while (trackbar != 0 && strcmp( trackbar->name, name ) != 0)
204         trackbar = trackbar->next;
205     
206     return trackbar;
207 }
208
209 //FD
210 /* draw image to frame */
211 static void icvDrawImage( CvWindow* window )
212 {
213     Assert( window != 0 );
214     if( window->imageRef == 0 ) return;
215     
216     CGContextRef myContext;
217     CGRect rect;
218     Rect portrect;
219     int width = window->imageWidth;
220     int height = window->imageHeight;
221     
222         GetWindowPortBounds(window->window, &portrect);
223     
224     if( window->flags & CV_WINDOW_AUTOSIZE ) 
225         { 
226         CGPoint origin = {0,0}; 
227         CGSize size = {portrect.right-portrect.left, portrect.bottom-portrect.top-window->trackbarheight};
228         rect.origin = origin; rect.size = size;
229     } 
230         else 
231         {
232         CGPoint origin = {0, portrect.bottom - height - window->trackbarheight};
233         CGSize size = {width, height};
234         rect.origin = origin; rect.size = size;
235     }
236     
237     /* To be sybnchronous we are using this, better would be to susbcribe to the draw event and process whenever requested, we might save SOME CPU cycles*/
238     SetPortWindowPort (window->window);
239     QDBeginCGContext (GetWindowPort (window->window), &myContext);
240     CGContextSetInterpolationQuality (myContext, kCGInterpolationLow); 
241     CGContextDrawImage(myContext,rect,window->imageRef);
242     CGContextFlush(myContext);// 4
243     QDEndCGContext (GetWindowPort(window->window), &myContext);// 5
244 }
245
246 //FD
247 /* update imageRef */
248 static void icvPutImage( CvWindow* window )
249 {
250     Assert( window != 0 );
251     if( window->image == 0 ) return;
252     
253     CGColorSpaceRef colorspace = NULL;
254     CGDataProviderRef provider = NULL;
255     int width = window->imageWidth = window->image->cols;
256     int height = window->imageHeight = window->image->rows;
257     
258     colorspace = CGColorSpaceCreateDeviceRGB();
259     
260     int size = 8;
261     int nbChannels = 3;
262     
263     provider = CGDataProviderCreateWithData(NULL, window->image->data.ptr, width * height , NULL );
264     
265     if (window->imageRef != NULL){
266         CGImageRelease(window->imageRef);
267         window->imageRef = NULL;
268     }
269     
270     window->imageRef = CGImageCreate( width, height, size , size*nbChannels , window->image->step, colorspace,  kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault );
271     icvDrawImage( window );
272
273     /* release the provider's memory */
274     CGDataProviderRelease( provider );
275 }
276
277 static void icvUpdateWindowSize( const CvWindow* window )
278 {
279     int width = 0, height = 240; /* init Ã  al taille de base de l'image*/
280     Rect globalBounds;
281     
282     GetWindowBounds(window->window, kWindowContentRgn, &globalBounds);
283     
284     int minWidth = 320;
285     
286     if( window->image ) {
287         width = MAX(MAX(window->image->width, width), minWidth);
288         height = window->image->height;
289     } else
290         width = minWidth;
291     
292     height += window->trackbarheight;
293     
294     //height +=WIDGETHEIGHT; /* 32 pixels are spearating tracbars from the video display */
295     
296     globalBounds.right = globalBounds.left + width;
297     globalBounds.bottom = globalBounds.top + height;
298     SetWindowBounds(window->window, kWindowContentRgn, &globalBounds);
299 }
300
301 static void icvDeleteWindow( CvWindow* window )
302 {
303     CvTrackbar* trackbar;
304     
305     if( window->prev )
306         window->prev->next = window->next;
307     else
308         hg_windows = window->next;
309     
310     if( window->next )
311         window->next->prev = window->prev;
312     
313     window->prev = window->next = 0;
314     
315     cvReleaseMat( &window->image );
316     cvReleaseMat( &window->dst_image );
317     
318     for( trackbar = window->toolbar.first; trackbar != 0; ) 
319         {
320         CvTrackbar* next = trackbar->next;
321         cvFree( (void**)&trackbar );
322         trackbar = next;
323     }
324     
325         if (window->imageRef != NULL)
326         CGImageRelease(window->imageRef);
327     
328     cvFree( (void**)&window );
329 }
330
331
332 CV_IMPL void cvDestroyWindow( const char* name)
333 {
334     CV_FUNCNAME( "cvDestroyWindow" );
335     
336     __BEGIN__;
337     
338     CvWindow* window;
339     
340     if(!name)
341         CV_ERROR( CV_StsNullPtr, "NULL name string" );
342     
343     window = icvFindWindowByName( name );
344     if( !window )
345         EXIT;
346     
347     icvDeleteWindow( window );
348     
349     __END__;
350 }
351
352
353 CV_IMPL void cvDestroyAllWindows( void )
354 {
355     while( hg_windows ) 
356         {
357         CvWindow* window = hg_windows;
358         icvDeleteWindow( window );
359     }
360 }
361
362
363 CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
364 {
365     CV_FUNCNAME( "cvShowImage" );
366     
367     __BEGIN__;
368     
369     CvWindow* window;
370     int origin = 0;
371     int resize = 0;
372     CvMat stub, *image;
373     
374     if( !name )
375         CV_ERROR( CV_StsNullPtr, "NULL name" );
376     
377     window = icvFindWindowByName(name);
378         if(!window)
379         {
380                 cvNamedWindow(name, 1);
381                 window = icvFindWindowByName(name);
382         }
383
384     if( !window || !arr )
385         EXIT; // keep silence here.
386     
387     if( CV_IS_IMAGE_HDR( arr ))
388         origin = ((IplImage*)arr)->origin;
389     
390     CV_CALL( image = cvGetMat( arr, &stub ));
391     
392     /*
393      if( !window->image )
394      cvResizeWindow( name, image->cols, image->rows );
395      */
396     
397     if( window->image &&
398         !CV_ARE_SIZES_EQ(window->image, image) ) {
399         if ( ! (window->flags & CV_WINDOW_AUTOSIZE) )//FD
400             resize = 1;
401         cvReleaseMat( &window->image );
402     }
403     
404     if( !window->image ) {
405         resize = 1;//FD
406         window->image = cvCreateMat( image->rows, image->cols, CV_8UC3 );
407     }
408     
409     cvConvertImage( image, window->image, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB );
410     icvPutImage( window );
411     if ( resize )//FD
412         icvUpdateWindowSize( window );
413     
414     __END__;
415 }
416
417 CV_IMPL void cvResizeWindow( const char* name, int width, int height)
418 {
419     CV_FUNCNAME( "cvResizeWindow" );
420     
421     __BEGIN__;
422     
423     CvWindow* window;
424     //CvTrackbar* trackbar;
425     
426     if( !name )
427         CV_ERROR( CV_StsNullPtr, "NULL name" );
428     
429     window = icvFindWindowByName(name);
430     if(!window)
431         EXIT;
432     
433     SizeWindow(window->window, width, height, true);
434     
435     __END__;
436 }
437
438 CV_IMPL void cvMoveWindow( const char* name, int x, int y)
439 {
440     CV_FUNCNAME( "cvMoveWindow" );
441     
442     __BEGIN__;
443     
444     CvWindow* window;
445     //CvTrackbar* trackbar;
446     
447     if( !name )
448         CV_ERROR( CV_StsNullPtr, "NULL name" );
449     
450     window = icvFindWindowByName(name);
451     if(!window)
452         EXIT;
453     
454     MoveWindow(window->window, x, y, true);
455     
456     __END__;
457 }
458
459 void TrackbarActionProcPtr (ControlRef theControl, ControlPartCode partCode)
460 {
461     CvTrackbar * trackbar = icvTrackbarByHandle (theControl);
462     
463         if (trackbar == NULL)
464         {
465         fprintf(stderr,"Error getting trackbar\n");
466         return;
467     }
468         else 
469         {
470         int pos = GetControl32BitValue (theControl);
471         if ( trackbar->data )
472             *trackbar->data = pos;
473         if ( trackbar->notify )
474             trackbar->notify(pos);
475         else if ( trackbar->notify2 )
476             trackbar->notify2(pos, trackbar->userdata);
477     }
478 }
479
480
481 static int icvCreateTrackbar (const char* trackbar_name,
482                               const char* window_name,
483                               int* val, int count,
484                               CvTrackbarCallback on_notify,
485                               CvTrackbarCallback2 on_notify2,
486                               void* userdata)
487 {
488     int result = 0;
489     
490     CV_FUNCNAME( "icvCreateTrackbar" );
491     __BEGIN__;
492     
493     /*char slider_name[32];*/
494     CvWindow* window = 0;
495     CvTrackbar* trackbar = 0;
496     Rect  stboundsRect;
497     ControlRef outControl;
498     ControlRef stoutControl;
499     Rect bounds;
500     
501     if( !window_name || !trackbar_name )
502         CV_ERROR( CV_StsNullPtr, "NULL window or trackbar name" );
503     
504     if( count <= 0 )
505         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
506     
507     window = icvFindWindowByName(window_name);
508     if( !window )
509         EXIT;
510     
511     trackbar = icvFindTrackbarByName(window,trackbar_name);
512     if( !trackbar ) 
513         {
514         int len = strlen(trackbar_name);
515         trackbar = (CvTrackbar*)cvAlloc(sizeof(CvTrackbar) + len + 1);
516         memset( trackbar, 0, sizeof(*trackbar));
517         trackbar->signature = CV_TRACKBAR_MAGIC_VAL;
518         trackbar->name = (char*)(trackbar+1);
519         memcpy( trackbar->name, trackbar_name, len + 1 );
520         trackbar->parent = window;
521         trackbar->next = window->toolbar.first;
522         window->toolbar.first = trackbar;
523         
524         if( val ) 
525                 {
526             int value = *val;
527             if( value < 0 )
528                 value = 0;
529             if( value > count )
530                 value = count;
531             trackbar->pos = value;
532             trackbar->data = val;
533         }
534         
535         trackbar->maxval = count;
536         
537         int c = icvCountTrackbarInWindow(window);               
538         
539         GetWindowBounds(window->window,kWindowContentRgn,&bounds);
540         
541         stboundsRect.top = (INTERWIDGETSPACE +WIDGETHEIGHT)* (c-1)+INTERWIDGETSPACE;
542         stboundsRect.left = INTERWIDGETSPACE;
543         stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT;
544         stboundsRect.right = stboundsRect.left+LABELWIDTH;
545         
546         //fprintf(stdout,"create trackabar bounds (%d %d %d %d)\n",stboundsRect.top,stboundsRect.left,stboundsRect.bottom,stboundsRect.right);
547         CreateStaticTextControl (window->window,&stboundsRect,CFStringCreateWithCString(NULL,trackbar_name,kCFStringEncodingASCII),NULL,&stoutControl);
548         
549         stboundsRect.top = (INTERWIDGETSPACE +WIDGETHEIGHT)* (c-1)+INTERWIDGETSPACE;
550         stboundsRect.left = INTERWIDGETSPACE*2+LABELWIDTH;
551         stboundsRect.bottom = stboundsRect.top + WIDGETHEIGHT;
552         stboundsRect.right =  bounds.right-INTERWIDGETSPACE;
553         
554         CreateSliderControl (window->window,&stboundsRect, trackbar->pos,0,trackbar->maxval,kControlSliderLiveFeedback,0,true,NewControlActionUPP(TrackbarActionProcPtr),&outControl);
555         
556         bounds.bottom += INTERWIDGETSPACE + WIDGETHEIGHT;
557         SetControlVisibility (outControl,true,true);
558         SetControlVisibility (stoutControl,true,true);
559         
560         trackbar->trackbar = outControl;
561         trackbar->label = stoutControl;
562         if (c == 1)
563             window->trackbarheight = INTERWIDGETSPACE*2 + WIDGETHEIGHT;
564         else
565             window->trackbarheight += INTERWIDGETSPACE + WIDGETHEIGHT;
566         icvUpdateWindowSize( window );
567     }
568
569     trackbar->notify = on_notify;
570     trackbar->notify2 = on_notify2;
571     trackbar->userdata = userdata;
572
573     result = 1;
574
575     __END__;
576     return result;
577 }
578
579
580 CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
581                               const char* window_name,
582                               int* val, int count,
583                               CvTrackbarCallback on_notify)
584 {
585     return icvCreateTrackbar(trackbar_name, window_name, val, count, on_notify, 0, 0);
586 }
587
588
589 CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
590                               const char* window_name,
591                               int* val, int count,
592                               CvTrackbarCallback2 on_notify2,
593                               void* userdata)
594 {
595     return icvCreateTrackbar(trackbar_name, window_name, val,
596                              count, 0, on_notify2, userdata);
597 }
598
599
600 CV_IMPL void
601 cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
602 {
603     CvWindow* window = icvFindWindowByName( name );
604     if (window != NULL)
605         {
606         window->on_mouse = function;
607         window->on_mouse_param = info;
608     } 
609         else
610         {
611         fprintf(stdout,"Error with cvSetMouseCallback. Window not found : %s\n",name);
612         }
613 }
614
615  CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
616 {
617     int pos = -1;
618     
619     CV_FUNCNAME( "cvGetTrackbarPos" );
620
621     __BEGIN__;
622
623     CvWindow* window;
624     CvTrackbar* trackbar = 0;
625
626     if( trackbar_name == 0 || window_name == 0 )
627         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
628
629     window = icvFindWindowByName( window_name );
630     if( window )
631         trackbar = icvFindTrackbarByName( window, trackbar_name );
632
633     if( trackbar )
634         pos = trackbar->pos;
635
636     __END__;
637
638     return pos;
639 }
640
641 CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos)
642 {
643    CV_FUNCNAME( "cvSetTrackbarPos" );
644
645     __BEGIN__;
646
647     CvWindow* window;
648     CvTrackbar* trackbar = 0;
649
650     if( trackbar_name == 0 || window_name == 0 )
651         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
652
653     window = icvFindWindowByName( window_name );
654     if( window )
655         trackbar = icvFindTrackbarByName( window, trackbar_name );
656
657     if( trackbar )
658     {
659         if( pos < 0 )
660             pos = 0;
661
662         if( pos > trackbar->maxval )
663             pos = trackbar->maxval;
664
665         // Set new value and redraw the trackbar
666         SetControlValue( trackbar->trackbar, pos );
667         Draw1Control( trackbar->trackbar );     
668     }
669
670     __END__;
671     return ;
672 }
673
674 CV_IMPL void* cvGetWindowHandle( const char* name )
675 {
676     WindowRef result = 0;
677     
678     __BEGIN__;
679     
680     CvWindow* window;
681     window = icvFindWindowByName( name );
682     if (window != NULL)
683         result = window->window;
684     else
685         result = NULL;
686     
687     __END__;
688     
689     return result;
690 }
691
692
693 CV_IMPL const char* cvGetWindowName( void* window_handle )
694 {       
695     const char* window_name = "";
696     
697     CV_FUNCNAME( "cvGetWindowName" );
698     
699     __BEGIN__;
700     
701     CvWindow* window;
702     
703     if( window_handle == 0 )
704         CV_ERROR( CV_StsNullPtr, "NULL window" );
705     window = icvWindowByHandle(window_handle );
706     if( window )
707         window_name = window->name;
708     
709     __END__;
710     
711     return window_name;
712 }
713
714
715 CV_IMPL int cvNamedWindow( const char* name, int flags )
716 {
717     int result = 0;
718     CV_FUNCNAME( "cvNamedWindow" );
719     if (!wasInitialized)
720         cvInitSystem(0, NULL);
721     
722     // to be able to display a window, we need to be a 'faceful' application
723     // http://lists.apple.com/archives/carbon-dev/2005/Jun/msg01414.html
724     static bool switched_to_faceful = false;
725     if (! switched_to_faceful)
726     {
727         ProcessSerialNumber psn = { 0, kCurrentProcess };
728         OSStatus ret = TransformProcessType (&psn, kProcessTransformToForegroundApplication );
729
730         if (ret == noErr) 
731         {
732             SetFrontProcess( &psn );
733             switched_to_faceful = true;
734         }
735         else
736         {
737             fprintf(stderr, "Failed to tranform process type: %d\n", (int) ret);
738             fflush (stderr);
739         }
740     }
741     
742     __BEGIN__;
743     
744     WindowRef       outWindow = NULL;
745     OSStatus              err = noErr;
746     Rect        contentBounds = {100,100,320,440};
747     
748     CvWindow* window;
749     UInt wAttributes = 0;
750     
751     int len;
752     
753     const EventTypeSpec genericWindowEventHandler[] = { 
754         { kEventClassMouse, kEventMouseMoved},
755         { kEventClassMouse, kEventMouseDragged},
756         { kEventClassMouse, kEventMouseUp},
757         { kEventClassMouse, kEventMouseDown},
758         { kEventClassWindow, kEventWindowClose },
759         { kEventClassWindow, kEventWindowBoundsChanged }//FD
760     };
761     
762     if( !name )
763         CV_ERROR( CV_StsNullPtr, "NULL name string" );
764     
765     if( icvFindWindowByName( name ) != 0 ){
766         result = 1;
767         EXIT;
768     }
769     len = strlen(name);
770     CV_CALL( window = (CvWindow*)cvAlloc(sizeof(CvWindow) + len + 1));
771     memset( window, 0, sizeof(*window));
772     window->name = (char*)(window + 1);
773     memcpy( window->name, name, len + 1 );
774     window->flags = flags;
775     window->signature = CV_WINDOW_MAGIC_VAL;
776     window->image = 0;
777     window->last_key = 0;
778     window->on_mouse = 0;
779     window->on_mouse_param = 0;
780     
781     window->next = hg_windows;
782     window->prev = 0;
783     if( hg_windows )
784         hg_windows->prev = window;
785     hg_windows = window;
786     wAttributes =  kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute;
787     
788     err = CreateNewWindow ( kDocumentWindowClass,wAttributes,&contentBounds,&outWindow);
789     if (err != noErr)
790         fprintf(stderr,"Error while creating the window\n");
791     
792     SetWindowTitleWithCFString(outWindow,CFStringCreateWithCString(NULL,name,kCFStringEncodingASCII));
793     if (err != noErr)
794         fprintf(stdout,"Error SetWindowTitleWithCFString\n");
795     
796     window->window = outWindow;
797     
798     err = InstallWindowEventHandler(outWindow, NewEventHandlerUPP(windowEventHandler), GetEventTypeCount(genericWindowEventHandler), genericWindowEventHandler, outWindow, NULL);
799     
800     ShowWindow( outWindow );
801     result = 1;
802         
803     __END__;
804     return result;
805 }
806
807 static pascal OSStatus windowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData)
808 {
809     CvWindow* window = NULL;
810     UInt32 eventKind, eventClass;
811     OSErr err = noErr;
812     int event = 0;
813     UInt32 count = 0;
814     HIPoint point = {0,0};
815     EventMouseButton eventMouseButton = 0;//FD
816     UInt32 modifiers;//FD
817     
818     WindowRef theWindow = (WindowRef)inUserData;
819     if (theWindow == NULL)
820         return eventNotHandledErr;
821     window = icvWindowByHandle(theWindow);
822     if ( window == NULL)
823         return eventNotHandledErr;
824     
825     eventKind = GetEventKind(theEvent);
826     eventClass = GetEventClass(theEvent);
827         
828     switch (eventClass) {
829     case kEventClassMouse : {
830         switch (eventKind){
831         case kEventMouseUp :
832         case kEventMouseDown : 
833         case kEventMouseMoved :
834         case kEventMouseDragged : {
835             err = CallNextEventHandler(nextHandler, theEvent);
836             if (err != eventNotHandledErr)
837                 return err;
838             err = GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(eventMouseButton), NULL, &eventMouseButton);
839             err = GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
840             err = GetEventParameter(theEvent,kEventParamClickCount,typeUInt32,NULL,sizeof(UInt32),NULL,&count);
841             if (err == noErr){
842                 if (count >1) event += 6;
843             } else {
844                 event = CV_EVENT_MOUSEMOVE;
845             }
846             
847             if (eventKind == kEventMouseUp)
848                 event +=4;
849             if (eventKind == kEventMouseDown)
850                 event +=1;
851             
852             unsigned int flags = 0;
853
854             err = GetEventParameter(theEvent, kEventParamWindowMouseLocation, typeHIPoint, NULL, sizeof(point), NULL, &point);
855             if (eventKind != kEventMouseMoved){
856                 switch(eventMouseButton){
857                     case kEventMouseButtonPrimary:
858                         if (modifiers & controlKey){
859                             flags += CV_EVENT_FLAG_RBUTTON;
860                             event += 1;
861                         } else {
862                             flags += CV_EVENT_FLAG_LBUTTON;
863                         }
864                         break;
865                     case kEventMouseButtonSecondary:
866                         flags += CV_EVENT_FLAG_RBUTTON;
867                         event += 1;
868                         break;
869                     case kEventMouseButtonTertiary:
870                         flags += CV_EVENT_FLAG_MBUTTON;
871                         event += 2;
872                         break;
873                 }
874             }
875
876             if (modifiers&controlKey) flags += CV_EVENT_FLAG_CTRLKEY;
877             if (modifiers&shiftKey)   flags += CV_EVENT_FLAG_SHIFTKEY;
878             if (modifiers& cmdKey )   flags += CV_EVENT_FLAG_ALTKEY;
879
880             if (window->on_mouse != NULL){
881                 int lx,ly;
882                 Rect structure, content;
883                 GetWindowBounds(theWindow, kWindowStructureRgn, &structure);
884                 GetWindowBounds(theWindow, kWindowContentRgn, &content);
885                 lx = (int)point.x - content.left + structure.left;
886                 ly = (int)point.y - window->trackbarheight  - content.top + structure.top; /* minus la taille des trackbars */
887                 if (window->flags & CV_WINDOW_AUTOSIZE) {//FD
888                                                          //printf("was %d,%d\n", lx, ly);
889                     /* scale the mouse coordinates */
890                     lx = lx * window->imageWidth / (content.right - content.left);
891                     ly = ly * window->imageHeight / (content.bottom - content.top - window->trackbarheight);
892                 }
893
894                 if (lx>0 && ly >0){ /* a remettre dans les coordonnées locale */
895                     window->on_mouse (event, lx, ly, flags, window->on_mouse_param);
896                     return noErr;
897                 }
898             }
899         }
900         default : return eventNotHandledErr;
901         }
902     }
903     case kEventClassWindow : {//FD
904         switch (eventKind){
905         case kEventWindowBoundsChanged :
906         {
907             /* resize the trackbars */
908             CvTrackbar *t;
909             Rect bounds;
910             GetWindowBounds(window->window,kWindowContentRgn,&bounds);
911             for ( t = window->toolbar.first; t != 0; t = t->next )
912                 SizeControl(t->trackbar,bounds.right - bounds.left - INTERWIDGETSPACE*3 - LABELWIDTH , WIDGETHEIGHT); 
913         }
914             /* redraw the image */
915             icvDrawImage(window);
916             break;
917         default :
918             return eventNotHandledErr;
919         }
920     }
921     default:
922         return eventNotHandledErr;
923     }
924
925     return eventNotHandledErr;
926 }
927
928 OSStatus keyHandler(EventHandlerCallRef hcr, EventRef theEvent, void* inUserData) 
929 {
930     UInt32 eventKind;
931     UInt32 eventClass;
932     OSErr  err        = noErr;
933
934     eventKind  = GetEventKind     (theEvent);
935     eventClass = GetEventClass    (theEvent);
936     err        = GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(lastKey), NULL, &lastKey);
937     if (err != noErr)
938         lastKey = NO_KEY;
939                 
940     return noErr;
941 }
942
943 CV_IMPL int cvWaitKey (int maxWait)
944 {
945     EventRecord theEvent;
946         
947         // wait at least for one event (to allow mouse, etc. processing), exit if maxWait milliseconds passed (nullEvent)
948         UInt32 start = TickCount();
949     int iters=0;
950         do
951         {
952                 // remaining time until maxWait is over
953                 UInt32 wait = EventTimeToTicks (maxWait / 1000.0) - (TickCount() - start);
954                 if ((int)wait <= 0)
955         {
956             if( maxWait > 0 && iters > 0 )
957                 break;
958             wait = 1;
959         }
960         iters++;
961         WaitNextEvent (everyEvent, &theEvent, maxWait > 0 ? wait : kDurationForever, NULL);
962         }
963         while (lastKey == NO_KEY  &&  theEvent.what != nullEvent);
964         
965     int key = lastKey;
966     lastKey = NO_KEY;
967     return key;
968 }
969
970 /* End of file. */