framework2
1771 строка · 53.1 Кб
1#include "ofAppGLFWWindow.h"
2
3#include "ofGLRenderer.h"
4#include "ofGLProgrammableRenderer.h"
5
6#define GLFW_INCLUDE_NONE
7#include "GLFW/glfw3.h"
8
9#ifdef TARGET_LINUX
10#include "ofIcon.h"
11#include "ofImage.h"
12#define GLFW_EXPOSE_NATIVE_X11
13#ifndef TARGET_OPENGLES
14#define GLFW_EXPOSE_NATIVE_GLX
15#else
16#define GLFW_EXPOSE_NATIVE_EGL
17#endif
18#include <X11/extensions/Xrandr.h>
19#include <X11/XKBlib.h>
20#include "GLFW/glfw3native.h"
21#include <X11/Xatom.h>
22#include <xcb/xcb.h>
23#include <xcb/xcbext.h>
24#elif defined(TARGET_OSX)
25#include <Cocoa/Cocoa.h>
26#define GLFW_EXPOSE_NATIVE_COCOA
27#define GLFW_EXPOSE_NATIVE_NSGL
28#include "GLFW/glfw3native.h"
29#elif defined(TARGET_WIN32)
30#define GLFW_EXPOSE_NATIVE_WIN32
31#define GLFW_EXPOSE_NATIVE_WGL
32#include <GLFW/glfw3native.h>
33#endif
34
35using std::vector;
36using std::shared_ptr;
37using std::numeric_limits;
38
39//-------------------------------------------------------
40ofAppGLFWWindow::ofAppGLFWWindow()
41:coreEvents(new ofCoreEvents) {
42bEnableSetupScreen = true;
43buttonInUse = 0;
44buttonPressed = false;
45bWindowNeedsShowing = true;
46
47orientation = OF_ORIENTATION_DEFAULT;
48targetWindowMode = OF_WINDOW;
49
50ofAppPtr = nullptr;
51
52pixelScreenCoordScale = 1;
53nFramesSinceWindowResized = 0;
54iconSet = false;
55windowP = nullptr;
56windowW = 0;
57windowH = 0;
58currentW = 0;
59currentH = 0;
60
61glfwSetErrorCallback(error_cb);
62}
63
64ofAppGLFWWindow::~ofAppGLFWWindow(){
65close();
66}
67
68void ofAppGLFWWindow::close(){
69if(windowP){
70
71
72glfwSetMouseButtonCallback( windowP, nullptr );
73glfwSetCursorPosCallback( windowP, nullptr );
74glfwSetCursorEnterCallback( windowP, nullptr );
75glfwSetKeyCallback( windowP, nullptr );
76glfwSetWindowSizeCallback( windowP, nullptr );
77glfwSetFramebufferSizeCallback( windowP, nullptr);
78glfwSetWindowCloseCallback( windowP, nullptr );
79glfwSetScrollCallback( windowP, nullptr );
80glfwSetDropCallback( windowP, nullptr );
81
82//hide the window before we destroy it stops a flicker on OS X on exit.
83glfwHideWindow(windowP);
84
85// We must ensure renderer is destroyed *before* glfw destroys the window in glfwDestroyWindow,
86// as `glfwDestroyWindow` at least on Windows has the effect of unloading OpenGL, making all
87// calls to OpenGL illegal.
88currentRenderer.reset();
89
90glfwDestroyWindow(windowP);
91windowP = nullptr;
92events().disable();
93bWindowNeedsShowing = true;
94}
95}
96
97//------------------------------------------------------------
98void ofAppGLFWWindow::setNumSamples(int _samples){
99settings.numSamples=_samples;
100}
101
102//------------------------------------------------------------
103void ofAppGLFWWindow::setMultiDisplayFullscreen(bool bMultiFullscreen){
104settings.multiMonitorFullScreen = bMultiFullscreen;
105}
106
107//------------------------------------------------------------
108void ofAppGLFWWindow::setDoubleBuffering(bool doubleBuff){
109settings.doubleBuffering = doubleBuff;
110}
111
112//------------------------------------------------------------
113void ofAppGLFWWindow::setColorBits(int r, int g, int b){
114settings.redBits=r;
115settings.greenBits=g;
116settings.blueBits=b;
117}
118
119//------------------------------------------------------------
120void ofAppGLFWWindow::setAlphaBits(int a){
121settings.alphaBits=a;
122}
123
124//------------------------------------------------------------
125void ofAppGLFWWindow::setDepthBits(int depth){
126settings.depthBits=depth;
127}
128
129//------------------------------------------------------------
130void ofAppGLFWWindow::setStencilBits(int stencil){
131settings.stencilBits=stencil;
132}
133
134//------------------------------------------------------------
135#ifdef TARGET_OPENGLES
136void ofAppGLFWWindow::setup(const ofGLESWindowSettings & settings){
137#else
138void ofAppGLFWWindow::setup(const ofGLWindowSettings & settings){
139#endif
140const ofGLFWWindowSettings * glSettings = dynamic_cast<const ofGLFWWindowSettings*>(&settings);
141if(glSettings){
142setup(*glSettings);
143}else{
144setup(ofGLFWWindowSettings(settings));
145}
146}
147
148void ofAppGLFWWindow::setup(const ofGLFWWindowSettings & _settings){
149if(windowP){
150ofLogError() << "window already setup, probably you are mixing old and new style setup";
151ofLogError() << "call only ofCreateWindow(settings) or ofSetupOpenGL(...)";
152ofLogError() << "calling window->setup() after ofCreateWindow() is not necessary and won't do anything";
153return;
154}
155settings = _settings;
156
157if(!glfwInit( )){
158ofLogError("ofAppGLFWWindow") << "couldn't init GLFW";
159return;
160}
161
162// ofLogNotice("ofAppGLFWWindow") << "WINDOW MODE IS " << screenMode;
163
164glfwDefaultWindowHints();
165glfwWindowHint(GLFW_RED_BITS, settings.redBits);
166glfwWindowHint(GLFW_GREEN_BITS, settings.greenBits);
167glfwWindowHint(GLFW_BLUE_BITS, settings.blueBits);
168glfwWindowHint(GLFW_ALPHA_BITS, settings.alphaBits);
169glfwWindowHint(GLFW_DEPTH_BITS, settings.depthBits);
170glfwWindowHint(GLFW_STENCIL_BITS, settings.stencilBits);
171glfwWindowHint(GLFW_STEREO, settings.stereo);
172glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
173#ifndef TARGET_OSX
174glfwWindowHint(GLFW_AUX_BUFFERS, settings.doubleBuffering?1:0);
175#else
176glfwWindowHint(GLFW_DOUBLEBUFFER, settings.doubleBuffering?1:0);
177#endif
178glfwWindowHint(GLFW_SAMPLES, settings.numSamples);
179glfwWindowHint(GLFW_RESIZABLE, settings.resizable);
180glfwWindowHint(GLFW_DECORATED, settings.decorated);
181
182#ifdef TARGET_OPENGLES
183glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, settings.glesVersion);
184glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
185glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
186if(settings.glesVersion>=2){
187currentRenderer = std::make_shared<ofGLProgrammableRenderer>(this);
188}else{
189currentRenderer = std::make_shared<ofGLRenderer>(this);
190}
191#else
192glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
193glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, settings.glVersionMajor);
194glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, settings.glVersionMinor);
195if((settings.glVersionMajor==3 && settings.glVersionMinor>=2) || settings.glVersionMajor>=4){
196glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
197}
198if(settings.glVersionMajor>=3){
199glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
200#if (GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR > 2) || (GLFW_VERSION_MAJOR > 3 )
201glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, settings.transparent);
202#endif
203currentRenderer = std::make_shared<ofGLProgrammableRenderer>(this);
204}else{
205currentRenderer = std::make_shared<ofGLRenderer>(this);
206}
207#endif
208
209GLFWwindow * sharedContext = nullptr;
210if(settings.shareContextWith){
211sharedContext = (GLFWwindow*)settings.shareContextWith->getWindowContext();
212}
213
214if(settings.windowMode==OF_GAME_MODE){
215int count;
216GLFWmonitor** monitors = glfwGetMonitors(&count);
217if( settings.monitor >= count ){
218ofLogError("ofAppGLFWWindow") << "requested game mode monitor is: " << settings.monitor << " monitor count is: " << count;
219}
220settings.monitor = ofClamp(settings.monitor,0,count-1);
221if(settings.isSizeSet()){
222currentW = settings.getWidth();
223currentH = settings.getHeight();
224}else{
225auto mode = glfwGetVideoMode(monitors[settings.monitor]);
226currentW = mode->width;
227currentH = mode->height;
228}
229if(count>settings.monitor){
230windowP = glfwCreateWindow(currentW, currentH, settings.title.c_str(), monitors[settings.monitor], sharedContext);
231}else{
232ofLogError("ofAppGLFWWindow") << "couldn't find any monitors";
233return;
234}
235}else{
236windowP = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.title.c_str(), nullptr, sharedContext);
237if(!windowP){
238ofLogError("ofAppGLFWWindow") << "couldn't create GLFW window";
239return;
240}
241if(settings.windowMode==OF_FULLSCREEN){
242int count = 0;
243auto monitors = glfwGetMonitors(&count);
244if( settings.monitor >= count ){
245ofLogError("ofAppGLFWWindow") << "requested fullscreen monitor is: " << settings.monitor << " monitor count is: " << count;
246}
247settings.monitor = ofClamp(settings.monitor,0,count-1);
248
249auto mode = glfwGetVideoMode(monitors[settings.monitor]);
250currentW = mode->width;
251currentH = mode->height;
252if(!settings.isPositionSet()){
253if(count > 0){
254int x = 0, y = 0;
255glfwGetMonitorPos(monitors[settings.monitor],&x,&y);
256settings.setPosition(glm::vec2(x,y));
257setWindowPosition(settings.getPosition().x,settings.getPosition().y);
258auto mode = glfwGetVideoMode(monitors[settings.monitor]);
259#ifdef TARGET_OSX
260//for OS X we need to set this first as the window size affects the window positon
261settings.setSize(mode->width, mode->height);
262#endif
263setWindowPosition(settings.getPosition().x,settings.getPosition().y);
264currentW = mode->width;
265currentH = mode->height;
266}
267}else{
268setWindowPosition(settings.getPosition().x,settings.getPosition().y);
269#ifdef TARGET_OSX
270auto size = getScreenSize();
271settings.setSize(size.x, size.y);
272#endif
273currentW = settings.getWidth();
274currentH = settings.getHeight();
275for(int i = 0; i < count; i++){
276int x = 0, y = 0;
277glfwGetMonitorPos(monitors[i],&x,&y);
278auto mode = glfwGetVideoMode(monitors[i]);
279int w = mode->width;
280int h = mode->height;
281ofRectangle rect(x-1,y-1,w+1,h+1);
282if(rect.inside(settings.getPosition())){
283currentW = mode->width;
284currentH = mode->height;
285break;
286}
287}
288}
289targetWindowMode = settings.windowMode;
290settings.windowMode = OF_WINDOW;
291}else{
292if (settings.isPositionSet()) {
293setWindowPosition(settings.getPosition().x,settings.getPosition().y);
294}
295glfwGetWindowSize( windowP, ¤tW, ¤tH );
296}
297#ifdef TARGET_LINUX
298if(!iconSet){
299ofPixels iconPixels;
300#ifdef DEBUG
301iconPixels.allocate(ofIconDebug.width,ofIconDebug.height,ofIconDebug.bytes_per_pixel);
302GIMP_IMAGE_RUN_LENGTH_DECODE(iconPixels.getData(),ofIconDebug.rle_pixel_data,iconPixels.getWidth()*iconPixels.getHeight(),ofIconDebug.bytes_per_pixel);
303#else
304iconPixels.allocate(ofIcon.width,ofIcon.height,ofIcon.bytes_per_pixel);
305GIMP_IMAGE_RUN_LENGTH_DECODE(iconPixels.getData(),ofIcon.rle_pixel_data,iconPixels.getWidth()*iconPixels.getHeight(),ofIcon.bytes_per_pixel);
306#endif
307setWindowIcon(iconPixels);
308}
309#endif
310if(settings.iconified){
311iconify(true);
312}
313}
314
315//don't try and show a window if its been requsted to be hidden
316bWindowNeedsShowing = settings.visible;
317
318glfwSetWindowUserPointer(windowP,this);
319
320windowW = settings.getWidth();
321windowH = settings.getHeight();
322
323#ifdef TARGET_RASPBERRY_PI
324windowRect.width = windowW;
325windowRect.height = windowH;
326#endif
327
328glfwMakeContextCurrent(windowP);
329
330int framebufferW, framebufferH, tmpWindowW, tmpWindowH;
331glfwGetFramebufferSize(windowP, &framebufferW, &framebufferH);
332glfwGetWindowSize( windowP, &tmpWindowW, &tmpWindowH );
333
334//this lets us detect if the window is running in a retina mode
335if( framebufferW != tmpWindowW){
336pixelScreenCoordScale = (float)framebufferW / (float)tmpWindowW;
337if( pixelScreenCoordScale < 1 ){
338pixelScreenCoordScale = 1;
339}
340
341if(targetWindowMode == OF_WINDOW){
342auto position = getWindowPosition();
343setWindowShape(windowW, windowH);
344setWindowPosition(position.x, position.y);
345}
346}
347
348#ifndef TARGET_OPENGLES
349static bool inited = false;
350if(!inited){
351glewExperimental = GL_TRUE;
352GLenum err = glewInit();
353if (GLEW_OK != err)
354{
355/* Problem: glewInit failed, something is seriously wrong. */
356ofLogError("ofAppRunner") << "couldn't init GLEW: " << glewGetErrorString(err);
357return;
358}
359inited = true;
360}
361#endif
362
363ofLogVerbose() << "GL Version: " << glGetString(GL_VERSION);
364
365if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){
366#ifndef TARGET_OPENGLES
367static_cast<ofGLProgrammableRenderer*>(currentRenderer.get())->setup(settings.glVersionMajor,settings.glVersionMinor);
368#else
369static_cast<ofGLProgrammableRenderer*>(currentRenderer.get())->setup(settings.glesVersion,0);
370#endif
371}else{
372static_cast<ofGLRenderer*>(currentRenderer.get())->setup();
373}
374
375setVerticalSync(true);
376glfwSetMouseButtonCallback(windowP, mouse_cb);
377glfwSetCursorPosCallback(windowP, motion_cb);
378glfwSetCursorEnterCallback(windowP, entry_cb);
379glfwSetKeyCallback(windowP, keyboard_cb);
380glfwSetCharCallback(windowP, char_cb);
381glfwSetWindowSizeCallback(windowP, resize_cb);
382glfwSetFramebufferSizeCallback(windowP, framebuffer_size_cb);
383glfwSetWindowCloseCallback(windowP, exit_cb);
384glfwSetScrollCallback(windowP, scroll_cb);
385glfwSetDropCallback(windowP, drop_cb );
386
387
388#ifdef TARGET_LINUX
389XSetLocaleModifiers("");
390xim = XOpenIM(getX11Display(), 0, 0, 0);
391if(!xim){
392// fallback to internal input method
393XSetLocaleModifiers("@im=none");
394xim = XOpenIM(getX11Display(), 0, 0, 0);
395}
396xic = XCreateIC(xim,
397XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
398XNClientWindow, getX11Window(),
399XNFocusWindow, getX11Window(),
400NULL);
401#endif
402}
403
404#ifdef TARGET_LINUX
405//------------------------------------------------------------
406void ofAppGLFWWindow::setWindowIcon(const std::string & path){
407ofPixels iconPixels;
408ofLoadImage(iconPixels,path);
409setWindowIcon(iconPixels);
410}
411
412//------------------------------------------------------------
413void ofAppGLFWWindow::setWindowIcon(const ofPixels & iconPixels){
414iconSet = true;
415int length = 2+iconPixels.getWidth()*iconPixels.getHeight();
416vector<unsigned long> buffer(length);
417buffer[0]=iconPixels.getWidth();
418buffer[1]=iconPixels.getHeight();
419for(size_t i=0;i<iconPixels.getWidth()*iconPixels.getHeight();i++){
420buffer[i+2] = iconPixels[i*4+3]<<24;
421buffer[i+2] += iconPixels[i*4+0]<<16;
422buffer[i+2] += iconPixels[i*4+1]<<8;
423buffer[i+2] += iconPixels[i*4+2];
424}
425
426XChangeProperty(getX11Display(), getX11Window(), XInternAtom(getX11Display(), "_NET_WM_ICON", False), XA_CARDINAL, 32,
427PropModeReplace, (const unsigned char*)buffer.data(), length);
428XFlush(getX11Display());
429}
430#endif
431
432//--------------------------------------------
433ofCoreEvents & ofAppGLFWWindow::events(){
434return *coreEvents;
435}
436
437//--------------------------------------------
438shared_ptr<ofBaseRenderer> & ofAppGLFWWindow::renderer(){
439return currentRenderer;
440}
441
442//--------------------------------------------
443void ofAppGLFWWindow::update(){
444events().notifyUpdate();
445
446//show the window right before the first draw call.
447if( bWindowNeedsShowing && windowP ){
448glfwShowWindow(windowP);
449bWindowNeedsShowing = false;
450if(targetWindowMode==OF_FULLSCREEN){
451setFullscreen(true);
452}
453}
454
455#ifdef TARGET_RASPBERRY_PI
456//needed for rpi. as good values don't come into resize_cb when coming out of fullscreen
457if( needsResizeCheck && windowP ){
458int winW, winH;
459glfwGetWindowSize(windowP, &winW, &winH);
460
461//wait until the window size is the size it was before going fullscreen
462//then stop the resize check
463if( winW == windowRect.getWidth() && winH == windowRect.getHeight() ){
464resize_cb(windowP, currentW, currentH);
465needsResizeCheck = false;
466}
467}
468#endif
469}
470
471//--------------------------------------------
472void ofAppGLFWWindow::pollEvents(){
473glfwPollEvents();
474}
475
476//--------------------------------------------
477void ofAppGLFWWindow::draw(){
478currentRenderer->startRender();
479if( bEnableSetupScreen ) currentRenderer->setupScreen();
480
481events().notifyDraw();
482
483#ifdef TARGET_WIN32
484if (currentRenderer->getBackgroundAuto() == false){
485// on a PC resizing a window with this method of accumulation (essentially single buffering)
486// is BAD, so we clear on resize events.
487if (nFramesSinceWindowResized < 3){
488currentRenderer->clear();
489} else {
490if ( (events().getFrameNum() < 3 || nFramesSinceWindowResized < 3) && settings.doubleBuffering){
491glfwSwapBuffers(windowP);
492}else{
493glFlush();
494}
495}
496} else {
497if(settings.doubleBuffering){
498glfwSwapBuffers(windowP);
499} else {
500glFlush();
501}
502}
503#else
504if (currentRenderer->getBackgroundAuto() == false){
505// in accum mode resizing a window is BAD, so we clear on resize events.
506if (nFramesSinceWindowResized < 3){
507currentRenderer->clear();
508}
509}
510if(settings.doubleBuffering){
511glfwSwapBuffers(windowP);
512} else{
513glFlush();
514}
515#endif
516
517currentRenderer->finishRender();
518
519nFramesSinceWindowResized++;
520}
521
522
523//--------------------------------------------
524void ofAppGLFWWindow::swapBuffers() {
525glfwSwapBuffers(windowP);
526}
527
528//--------------------------------------------
529void ofAppGLFWWindow::startRender() {
530renderer()->startRender();
531}
532
533//--------------------------------------------
534void ofAppGLFWWindow::finishRender() {
535renderer()->finishRender();
536}
537
538//--------------------------------------------
539bool ofAppGLFWWindow::getWindowShouldClose(){
540return glfwWindowShouldClose(windowP);
541}
542
543//--------------------------------------------
544void ofAppGLFWWindow::setWindowShouldClose(){
545glfwSetWindowShouldClose(windowP,1);
546}
547
548//------------------------------------------------------------
549void ofAppGLFWWindow::setWindowTitle(std::string title){
550settings.title = title;
551glfwSetWindowTitle(windowP,settings.title.c_str());
552}
553
554//------------------------------------------------------------
555int ofAppGLFWWindow::getPixelScreenCoordScale(){
556return pixelScreenCoordScale;
557}
558
559//------------------------------------------------------------
560glm::vec2 ofAppGLFWWindow::getWindowSize(){
561if(settings.windowMode == OF_GAME_MODE)
562{
563const GLFWvidmode * desktopMode = glfwGetVideoMode(glfwGetWindowMonitor(windowP));
564if(desktopMode){
565return {desktopMode->width*pixelScreenCoordScale, desktopMode->height*pixelScreenCoordScale};
566}else{
567return {currentW*pixelScreenCoordScale, currentH*pixelScreenCoordScale};
568}
569}else{
570return {currentW*pixelScreenCoordScale, currentH*pixelScreenCoordScale};
571}
572}
573
574//------------------------------------------------------------
575glm::vec2 ofAppGLFWWindow::getWindowPosition(){
576int x, y;
577glfwGetWindowPos(windowP, &x, &y);
578
579x *= pixelScreenCoordScale;
580y *= pixelScreenCoordScale;
581
582if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
583return glm::vec2{x,y};
584}else{
585return glm::vec2(x,y); //NOTE: shouldn't this be (y,x) ??????
586}
587}
588
589//------------------------------------------------------------
590int ofAppGLFWWindow::getCurrentMonitor(){
591int numberOfMonitors;
592GLFWmonitor** monitors = glfwGetMonitors(&numberOfMonitors);
593
594int xW; int yW;
595glfwGetWindowPos(windowP, &xW, &yW);
596
597for (int iC=0; iC < numberOfMonitors; iC++){
598int xM; int yM;
599glfwGetMonitorPos(monitors[iC], &xM, &yM);
600const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[iC]);
601ofRectangle monitorRect(xM, yM, desktopMode->width, desktopMode->height);
602bool bPointMatch = xW >= monitorRect.getMinX() && yW >= monitorRect.getMinY() && xW < monitorRect.getMaxX() && yW < monitorRect.getMaxY();
603// if (monitorRect.inside(xW, yW)){
604if( bPointMatch ) {
605return iC;
606break;
607}
608}
609return 0;
610}
611
612
613//------------------------------------------------------------
614glm::vec2 ofAppGLFWWindow::getScreenSize(){
615int count;
616GLFWmonitor** monitors = glfwGetMonitors(&count);
617if(count>0){
618int currentMonitor = getCurrentMonitor();
619const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[currentMonitor]);
620if(desktopMode){
621if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
622return {desktopMode->width*pixelScreenCoordScale, desktopMode->height*pixelScreenCoordScale};
623}else{
624return {desktopMode->height*pixelScreenCoordScale, desktopMode->width*pixelScreenCoordScale};
625}
626}
627}
628return glm::vec2();
629}
630
631//------------------------------------------------------------
632int ofAppGLFWWindow::getWidth(){
633if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
634return currentW * pixelScreenCoordScale;
635}else{
636return currentH * pixelScreenCoordScale;
637}
638}
639
640//------------------------------------------------------------
641int ofAppGLFWWindow::getHeight(){
642if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){
643return currentH * pixelScreenCoordScale;
644}else{
645return currentW * pixelScreenCoordScale;
646}
647}
648
649//------------------------------------------------------------
650GLFWwindow* ofAppGLFWWindow::getGLFWWindow(){
651return windowP;
652}
653
654//------------------------------------------------------------
655ofWindowMode ofAppGLFWWindow::getWindowMode(){
656return settings.windowMode;
657}
658
659//------------------------------------------------------------
660void ofAppGLFWWindow::setWindowPosition(int x, int y){
661glfwSetWindowPos(windowP,x/pixelScreenCoordScale,y/pixelScreenCoordScale);
662}
663
664//------------------------------------------------------------
665void ofAppGLFWWindow::setWindowShape(int w, int h){
666if(settings.windowMode == OF_WINDOW){
667windowW = w;
668windowH = h;
669}
670currentW = w/pixelScreenCoordScale;
671currentH = h/pixelScreenCoordScale;
672
673#ifdef TARGET_OSX
674auto pos = getWindowPosition();
675glfwSetWindowSize(windowP,currentW,currentH);
676if( pos != getWindowPosition() ){
677setWindowPosition(pos.x, pos.y);
678}
679#else
680glfwSetWindowSize(windowP,currentW,currentH);
681#endif
682}
683
684//------------------------------------------------------------
685void ofAppGLFWWindow::hideCursor(){
686if(settings.windowMode == OF_FULLSCREEN || settings.windowMode == OF_GAME_MODE){
687glfwSetInputMode(windowP,GLFW_CURSOR,GLFW_CURSOR_DISABLED);
688}else{
689glfwSetInputMode(windowP,GLFW_CURSOR,GLFW_CURSOR_HIDDEN);
690}
691};
692
693//------------------------------------------------------------
694void ofAppGLFWWindow::showCursor(){
695glfwSetInputMode(windowP,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
696};
697
698//------------------------------------------------------------
699void ofAppGLFWWindow::enableSetupScreen(){
700bEnableSetupScreen = true;
701};
702
703//------------------------------------------------------------
704void ofAppGLFWWindow::disableSetupScreen(){
705bEnableSetupScreen = false;
706};
707
708//------------------------------------------------------------
709void ofAppGLFWWindow::setFullscreen(bool fullscreen){
710if (fullscreen){
711targetWindowMode = OF_FULLSCREEN;
712}else{
713targetWindowMode = OF_WINDOW;
714}
715
716#if defined(TARGET_OSX)
717NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP);
718if (([cocoaWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) {
719settings.windowMode = OF_FULLSCREEN;
720if (targetWindowMode == OF_WINDOW) {
721[cocoaWindow toggleFullScreen:nil];
722}
723} else {
724[cocoaWindow setHasShadow:NO];
725}
726#endif
727
728//we only want to change window mode if the requested window is different to the current one.
729bool bChanged = targetWindowMode != settings.windowMode;
730if( !bChanged ){
731return;
732}
733
734#ifdef TARGET_LINUX
735#include <X11/Xatom.h>
736
737Window nativeWin = glfwGetX11Window(windowP);
738Display* display = glfwGetX11Display();
739if(targetWindowMode==OF_FULLSCREEN){
740
741#ifdef TARGET_RASPBERRY_PI
742// save window shape before going fullscreen
743if( windowP ){
744int tmpW, tmpH;
745glfwGetWindowSize(windowP, &tmpW, &tmpH);
746windowRect.setSize(tmpW, tmpH);
747}
748#endif
749
750int monitorCount;
751GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
752if( settings.multiMonitorFullScreen && monitorCount > 1 ){
753// find the monitors at the edges of the virtual desktop
754int minx=numeric_limits<int>::max();
755int miny=numeric_limits<int>::max();
756int maxx=numeric_limits<int>::min();
757int maxy=numeric_limits<int>::min();
758int x,y,w,h;
759int monitorLeft=0, monitorRight=0, monitorTop=0, monitorBottom=0;
760for(int i = 0; i < monitorCount; i++){
761glfwGetMonitorPos(monitors[i],&x,&y);
762auto videoMode = glfwGetVideoMode(monitors[i]);
763w = videoMode->width;
764h = videoMode->height;
765if(x<minx){
766monitorLeft = i;
767minx = x;
768}
769if(y<miny){
770monitorTop = i;
771miny = y;
772}
773if(x+w>maxx){
774monitorRight = i;
775maxx = x+w;
776}
777if(y+h>maxy){
778monitorBottom = i;
779maxy = y+h;
780}
781}
782
783// send fullscreen_monitors event with the edges monitors
784Atom m_net_fullscreen_monitors= XInternAtom(display, "_NET_WM_FULLSCREEN_MONITORS", false);
785
786XEvent xev;
787
788xev.xclient.type = ClientMessage;
789xev.xclient.serial = 0;
790xev.xclient.send_event = True;
791xev.xclient.window = nativeWin;
792xev.xclient.message_type = m_net_fullscreen_monitors;
793xev.xclient.format = 32;
794
795xev.xclient.data.l[0] = monitorTop;
796xev.xclient.data.l[1] = monitorBottom;
797xev.xclient.data.l[2] = monitorLeft;
798xev.xclient.data.l[3] = monitorRight;
799xev.xclient.data.l[4] = 1;
800XSendEvent(display, RootWindow(display, DefaultScreen(display)),
801False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
802currentW = maxx - minx;
803currentH = maxy - minx;
804}else{
805auto monitor = glfwGetWindowMonitor(windowP);
806if(monitor){
807auto videoMode = glfwGetVideoMode(monitor);
808if(videoMode){
809currentW = videoMode->width;
810currentH = videoMode->height;
811}
812}
813}
814}
815
816// send fullscreen event
817Atom m_net_state= XInternAtom(display, "_NET_WM_STATE", false);
818Atom m_net_fullscreen= XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", false);
819
820XEvent xev;
821
822xev.xclient.type = ClientMessage;
823xev.xclient.serial = 0;
824xev.xclient.send_event = True;
825xev.xclient.window = nativeWin;
826xev.xclient.message_type = m_net_state;
827xev.xclient.format = 32;
828
829if (fullscreen)
830xev.xclient.data.l[0] = 1;
831else
832xev.xclient.data.l[0] = 0;
833
834xev.xclient.data.l[1] = m_net_fullscreen;
835xev.xclient.data.l[2] = 0;
836xev.xclient.data.l[3] = 0;
837xev.xclient.data.l[4] = 0;
838XSendEvent(display, RootWindow(display, DefaultScreen(display)),
839False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
840
841// tell the window manager to bypass composition for this window in fullscreen for speed
842// it'll probably help solving vsync issues
843Atom m_bypass_compositor = XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False);
844unsigned long value = fullscreen ? 1 : 0;
845XChangeProperty(display, nativeWin, m_bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&value, 1);
846
847XFlush(display);
848
849#ifdef TARGET_RASPBERRY_PI
850if( !fullscreen ){
851needsResizeCheck = true;
852}
853#endif
854
855// setWindowShape(windowW, windowH);
856
857#elif defined(TARGET_OSX)
858
859if( targetWindowMode == OF_FULLSCREEN){
860//----------------------------------------------------
861[NSApp setPresentationOptions:NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock];
862NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP);
863
864[cocoaWindow setStyleMask:NSWindowStyleMaskBorderless];
865
866int monitorCount;
867GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
868
869int currentMonitor = getCurrentMonitor();
870auto screenSize = getScreenSize();
871
872if( orientation == OF_ORIENTATION_90_LEFT || orientation == OF_ORIENTATION_90_RIGHT ){
873std::swap(screenSize.x, screenSize.y);
874}
875
876ofRectangle allScreensSpace;
877
878// save window shape before going fullscreen
879auto pos = getWindowPosition();
880auto size = getWindowSize();
881windowRect.x = pos.x;
882windowRect.y = pos.y;
883windowRect.width = size.x;
884windowRect.height = size.y;
885
886if( settings.multiMonitorFullScreen && monitorCount > 1 ){
887
888//calc the sum Rect of all the monitors
889for(int i = 0; i < monitorCount; i++){
890const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[i]);
891int x, y;
892glfwGetMonitorPos(monitors[i], &x, &y);
893ofRectangle screen = ofRectangle( x, y, desktopMode->width, desktopMode->height );
894allScreensSpace = allScreensSpace.getUnion(screen);
895}
896//for OS X we need to set this first as the window size affects the window positon
897//need to account for the pixel density factor when we're getting the values from glfw
898setWindowShape(allScreensSpace.width*pixelScreenCoordScale, allScreensSpace.height*pixelScreenCoordScale);
899setWindowPosition(allScreensSpace.x, allScreensSpace.y);
900
901}else if (monitorCount > 1 && currentMonitor < monitorCount){
902int xpos;
903int ypos;
904glfwGetMonitorPos(monitors[currentMonitor], &xpos, &ypos);
905
906// Scale (if needed) to physical pixels size, since setWindowPosition
907// uses physical pixel dimensions. On HIDPI screens pixelScreenCoordScale
908// is likely to be 2, on "normal" screens pixelScreenCoordScale will be 1:
909xpos *= pixelScreenCoordScale;
910ypos *= pixelScreenCoordScale;
911
912//we do this as setWindowShape affects the position of the monitor
913//normally we would just call setWindowShape first, but on multi monitor you see the window bleed onto the second monitor as it first changes shape and is then repositioned.
914//this first moves it over in X, does the screen resize and then by calling it again its set correctly in y.
915setWindowPosition(xpos, ypos);
916setWindowShape(screenSize.x, screenSize.y);
917setWindowPosition(xpos, ypos);
918}else{
919//for OS X we need to set this first as the window size affects the window positon
920setWindowShape(screenSize.x, screenSize.y);
921setWindowPosition(0,0);
922}
923
924// make sure to save current pos if not specified in settings
925if( settings.isPositionSet() ) {
926auto pos = getWindowPosition();
927settings.setPosition(ofVec2f(pos.x, pos.y));
928}
929
930//make sure the window is getting the mouse/key events
931[cocoaWindow makeFirstResponder:cocoaWindow.contentView];
932
933}else if( targetWindowMode == OF_WINDOW ){
934
935// set window shape if started in fullscreen
936if(windowRect.width == 0 && windowRect.height == 0) {
937windowRect.x = getWindowPosition().x;
938windowRect.y = getWindowPosition().y;
939windowRect.width = getWindowSize().x;
940windowRect.height = getWindowSize().y;
941}
942
943setWindowShape(windowRect.width, windowRect.height);
944setWindowTitle(settings.title);
945
946[NSApp setPresentationOptions:NSApplicationPresentationDefault];
947NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP);
948[cocoaWindow setStyleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable];
949
950//----------------------------------------------------
951// if we have recorded the screen position, put it there
952// if not, better to let the system do it (and put it where it wants)
953if (ofGetFrameNum() > 0){
954setWindowPosition(windowRect.x, windowRect.y);
955}
956
957//----------------------------------------------------
958//make sure the window is getting the mouse/key events
959[cocoaWindow makeFirstResponder:cocoaWindow.contentView];
960}
961#elif defined(TARGET_WIN32)
962if( targetWindowMode == OF_FULLSCREEN){
963// save window shape before going fullscreen
964auto pos = getWindowPosition();
965auto size = getWindowSize();
966windowRect.x = pos.x;
967windowRect.y = pos.y;
968windowRect.width = size.x;
969windowRect.height = size.y;
970
971//----------------------------------------------------
972HWND hwnd = glfwGetWin32Window(windowP);
973
974SetWindowLong(hwnd, GWL_EXSTYLE, 0);
975SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
976SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
977
978float fullscreenW = getScreenSize().x;
979float fullscreenH = getScreenSize().y;
980
981if( orientation == OF_ORIENTATION_90_LEFT || orientation == OF_ORIENTATION_90_RIGHT ){
982std::swap(fullscreenW, fullscreenH);
983}
984
985int xpos = 0;
986int ypos = 0;
987
988if( settings.multiMonitorFullScreen ){
989
990int minX = 0;
991int maxX = 0;
992int minY = 0;
993int maxY = 0;
994int monitorCount;
995GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
996int tempXPos = 0;
997int tempYPos = 0;
998//lets find the total width of all the monitors
999//and we'll make the window height the height of the largest monitor.
1000for(int i = 0; i < monitorCount; i++){
1001const GLFWvidmode * desktopMode = glfwGetVideoMode(monitors[i]);
1002glfwGetMonitorPos(monitors[i], &tempXPos, &tempYPos);
1003minX = std::min(tempXPos,minX);
1004minY = std::min(tempYPos,minY);
1005maxX = std::max(maxX,tempXPos + desktopMode->width);
1006maxY = std::max(maxY,tempYPos + desktopMode->height);
1007
1008xpos = std::min(xpos,tempXPos);
1009ypos = std::min(ypos,tempYPos);
1010}
1011
1012fullscreenW = maxX-minX;
1013fullscreenH = maxY-minY;
1014}else{
1015
1016int monitorCount;
1017GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
1018int currentMonitor = getCurrentMonitor();
1019glfwGetMonitorPos(monitors[currentMonitor], &xpos, &ypos);
1020
1021}
1022
1023SetWindowPos(hwnd, HWND_TOPMOST, xpos, ypos, fullscreenW, fullscreenH, SWP_SHOWWINDOW);
1024currentW = fullscreenW;
1025currentH = fullscreenH;
1026
1027}else if( targetWindowMode == OF_WINDOW ){
1028// set window shape if started in fullscreen
1029if(windowRect.width == 0 && windowRect.height == 0) {
1030windowRect.x = getWindowPosition().x;
1031windowRect.y = getWindowPosition().y;
1032windowRect.width = getWindowSize().x;
1033windowRect.height = getWindowSize().y;
1034}
1035
1036HWND hwnd = glfwGetWin32Window(windowP);
1037
1038DWORD EX_STYLE = WS_EX_OVERLAPPEDWINDOW;
1039DWORD STYLE = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SIZEBOX;
1040
1041ChangeDisplaySettings(0, 0);
1042SetWindowLong(hwnd, GWL_EXSTYLE, EX_STYLE);
1043SetWindowLong(hwnd, GWL_STYLE, STYLE);
1044SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1045
1046//not sure why this is - but if we don't do this the window shrinks by 4 pixels in x and y
1047//should look for a better fix.
1048setWindowPosition(windowRect.x-2, windowRect.y-2);
1049setWindowShape(windowRect.width+4, windowRect.height+4);
1050}
1051#endif
1052
1053settings.windowMode = targetWindowMode;
1054}
1055
1056//------------------------------------------------------------
1057void ofAppGLFWWindow::toggleFullscreen(){
1058if (settings.windowMode == OF_GAME_MODE) return;
1059
1060
1061if (settings.windowMode == OF_WINDOW){
1062setFullscreen(true);
1063} else {
1064setFullscreen(false);
1065}
1066}
1067
1068//------------------------------------------------------------
1069void ofAppGLFWWindow::setOrientation(ofOrientation orientation){
1070this->orientation = orientation;
1071}
1072
1073//------------------------------------------------------------
1074ofOrientation ofAppGLFWWindow::getOrientation(){
1075return orientation;
1076}
1077
1078//------------------------------------------------------------
1079static void rotateMouseXY(ofOrientation orientation, int w, int h, double &x, double &y) {
1080int savedY;
1081switch(orientation) {
1082case OF_ORIENTATION_180:
1083x = w - x;
1084y = h - y;
1085break;
1086
1087case OF_ORIENTATION_90_RIGHT:
1088savedY = y;
1089y = x;
1090x = w-savedY;
1091break;
1092
1093case OF_ORIENTATION_90_LEFT:
1094savedY = y;
1095y = h - x;
1096x = savedY;
1097break;
1098
1099case OF_ORIENTATION_DEFAULT:
1100default:
1101break;
1102}
1103}
1104
1105//------------------------------------------------------------
1106ofAppGLFWWindow * ofAppGLFWWindow::setCurrent(GLFWwindow* windowP){
1107ofAppGLFWWindow * instance = static_cast<ofAppGLFWWindow *>(glfwGetWindowUserPointer(windowP));
1108shared_ptr<ofMainLoop> mainLoop = ofGetMainLoop();
1109if(mainLoop){
1110mainLoop->setCurrentWindow(instance);
1111}
1112instance->makeCurrent();
1113return instance;
1114}
1115
1116
1117namespace{
1118int glfwtToOFModifiers(int mods){
1119int modifiers = 0;
1120if(mods & GLFW_MOD_SHIFT){
1121modifiers |= OF_KEY_SHIFT;
1122}
1123if(mods & GLFW_MOD_ALT){
1124modifiers |= OF_KEY_ALT;
1125}
1126if(mods & GLFW_MOD_CONTROL){
1127modifiers |= OF_KEY_CONTROL;
1128}
1129if(mods & GLFW_MOD_SUPER){
1130modifiers |= OF_KEY_SUPER;
1131}
1132return modifiers;
1133}
1134
1135unsigned long keycodeToUnicode(ofAppGLFWWindow * window, int scancode, int modifier){
1136#ifdef TARGET_LINUX
1137XkbStateRec xkb_state = {};
1138XkbGetState(window->getX11Display(), XkbUseCoreKbd, &xkb_state);
1139XEvent ev = {0};
1140ev.xkey.keycode = scancode;
1141ev.xkey.state = xkb_state.mods & ~ControlMask;
1142ev.xkey.display = window->getX11Display();
1143ev.xkey.type = KeyPress;
1144KeySym keysym = NoSymbol;
1145int status;
1146char buffer[32] = {0};
1147char* chars = buffer;
1148auto count = Xutf8LookupString(window->getX11XIC(), &ev.xkey, chars, sizeof(buffer) - 1, &keysym, &status);
1149if ((count > 0 && (status == XLookupChars || status == XLookupBoth)) || status == XLookupKeySym){
1150char ** c = &chars;
1151unsigned int ch = 0, count = 0;
1152static const unsigned int offsets[] =
1153{
11540x00000000u, 0x00003080u, 0x000e2080u,
11550x03c82080u, 0xfa082080u, 0x82082080u
1156};
1157
1158do
1159{
1160ch = (ch << 6) + (unsigned char) **c;
1161(*c)++;
1162count++;
1163} while ((**c & 0xc0) == 0x80);
1164
1165if(count>6){
1166return 0;
1167}else{
1168return ch - offsets[count - 1];
1169}
1170}else{
1171return 0;
1172}
1173#endif
1174#ifdef TARGET_WIN32
1175static WCHAR buf[2];
1176static BYTE keyboardState[256];
1177GetKeyboardState( keyboardState );
1178
1179// Careful: keycode arrives translated into GLFW key codes,
1180// but keycode needs to be a virtual key (VK_...) so we're
1181// in deep troble, since this information has been removed
1182// by GLFW...
1183//
1184// The way around this is to ask the operating system
1185// nicely to create a virtual key for us, based on
1186// the scancode and the currently bound keyboard layout.
1187// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646306(v=vs.85).aspx
1188//
1189// create a "fake" virtual key
1190
1191UINT fakeVirtualKey = MapVirtualKey( scancode, MAPVK_VSC_TO_VK_EX );
1192
1193int ret = ToUnicode( fakeVirtualKey, scancode, keyboardState, buf , 2, 0);
1194
1195if ( ret == 1 ){
1196return buf[0];
1197} else {
1198return 0;
1199}
1200#endif
1201#ifdef TARGET_OSX
1202static UInt32 deadKeyState = 0;
1203static UniChar characters[8];
1204static UniCharCount characterCount = 0;
1205
1206typedef struct __TISInputSource* TISInputSourceRef;
1207typedef TISInputSourceRef (*pFnGetInputSource)(void); // define function pointer that may return a input source ref, no arguments
1208typedef void* (*pFnGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
1209typedef UInt8 (*pFnGetKeyboardType)(void);
1210
1211static const CFBundleRef tisBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
1212
1213// We need to call some system methods, following GLFW's example
1214// in their OS X version of ```_glfwPlatformGetKeyName```.
1215//
1216// We know these methods must be available, since GLFW uses them
1217// internally.
1218//
1219// The most important method is ```UCKeyTranslate``` - everything
1220// else here is just a royal preparation party to feed it with the
1221// correct parameters.
1222//
1223// Since these methods are hidden deep within Carbon,
1224// we have to first request function pointers to make
1225// them callable.
1226//
1227// We do this only the first time, then we're re-using them,
1228// that's why these elements are marked static, and static const.
1229//
1230static pFnGetInputSource getInputSource = (pFnGetInputSource)CFBundleGetFunctionPointerForName(tisBundle, CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
1231static pFnGetKeyboardType getKeyboardType = (pFnGetKeyboardType)CFBundleGetFunctionPointerForName(tisBundle,CFSTR("LMGetKbdType"));
1232static pFnGetInputSourceProperty getInputSourceProperty = (pFnGetInputSourceProperty)CFBundleGetFunctionPointerForName(tisBundle, CFSTR("TISGetInputSourceProperty"));
1233
1234static const TISInputSourceRef sourceRef = getInputSource(); // note that for the first time, this creates a copy on the heap, then we're re-using it.
1235
1236static const CFStringRef* kPropertyUnicodeKeyLayoutData = (CFStringRef*)CFBundleGetDataPointerForName(tisBundle, CFSTR("kTISPropertyUnicodeKeyLayoutData"));
1237static const CFStringRef kTISPropertyUnicodeKeyLayoutData = * kPropertyUnicodeKeyLayoutData;
1238static const CFDataRef UnicodeKeyLayoutData = (CFDataRef)getInputSourceProperty(sourceRef, kTISPropertyUnicodeKeyLayoutData);
1239
1240static const UCKeyboardLayout* pKeyboardLayout = (UCKeyboardLayout*)CFDataGetBytePtr(UnicodeKeyLayoutData);
1241
1242UInt32 mod_OSX = 0;
1243{
1244// We have to translate the GLFW modifier bitflags back to OS X,
1245// so that SHIFT, CONTROL, etc can be taken into account when
1246// calculating the unicode codepoint.
1247
1248// UCKeyTranslate expects the Carbon-era modifier mask values,
1249// so use these instead of the NSEventModifierFlag enums
1250if (modifier & GLFW_MOD_SHIFT)
1251mod_OSX |= 512; // Carbon shiftKey value
1252if (modifier & GLFW_MOD_CONTROL)
1253mod_OSX |= 4096; // Carbon controlKey value
1254if (modifier & GLFW_MOD_ALT)
1255mod_OSX |= 2048; // Carbon optionKey value
1256if (modifier & GLFW_MOD_SUPER)
1257mod_OSX |= 256; // Carbon cmdKey
1258
1259// shift into 1 byte as per the Apple docs
1260mod_OSX = (mod_OSX >> 8) & 0xFF;
1261}
1262
1263// All this yak shaving was necessary to feed this diva of a function call:
1264// https://developer.apple.com/library/mac/documentation/Carbon/Reference/Unicode_Utilities_Ref/index.html#//apple_ref/c/func/UCKeyTranslate
1265
1266if (noErr == UCKeyTranslate(pKeyboardLayout,
1267scancode,
1268kUCKeyActionDisplay,
1269mod_OSX,
1270getKeyboardType(),
1271kUCKeyTranslateNoDeadKeysBit,
1272&deadKeyState,
1273sizeof(characters) / sizeof(characters[0]),
1274&characterCount,
1275characters))
1276{
1277// if successful, first character contains codepoint
1278return characters[0];
1279} else {
1280return 0;
1281}
1282
1283#endif
1284return 0;
1285}
1286}
1287
1288//------------------------------------------------------------
1289void ofAppGLFWWindow::mouse_cb(GLFWwindow* windowP_, int button, int state, int mods) {
1290ofAppGLFWWindow * instance = setCurrent(windowP_);
1291
1292#ifdef TARGET_OSX
1293//we do this as unlike glut, glfw doesn't report right click for ctrl click or middle click for alt click
1294if( instance->events().getKeyPressed(OF_KEY_CONTROL) && button == GLFW_MOUSE_BUTTON_LEFT){
1295button = GLFW_MOUSE_BUTTON_RIGHT;
1296}
1297if( instance->events().getKeyPressed(OF_KEY_ALT) && button == GLFW_MOUSE_BUTTON_LEFT){
1298button = GLFW_MOUSE_BUTTON_MIDDLE;
1299}
1300#endif
1301
1302switch(button){
1303case GLFW_MOUSE_BUTTON_LEFT:
1304button = OF_MOUSE_BUTTON_LEFT;
1305break;
1306case GLFW_MOUSE_BUTTON_RIGHT:
1307button = OF_MOUSE_BUTTON_RIGHT;
1308break;
1309case GLFW_MOUSE_BUTTON_MIDDLE:
1310button = OF_MOUSE_BUTTON_MIDDLE;
1311break;
1312}
1313instance->buttonInUse = button;
1314
1315
1316ofMouseEventArgs::Type action;
1317if (state == GLFW_PRESS) {
1318action = ofMouseEventArgs::Pressed;
1319instance->buttonPressed=true;
1320} else {
1321action = ofMouseEventArgs::Released;
1322instance->buttonPressed=false;
1323}
1324
1325int modifiers = glfwtToOFModifiers(mods);
1326
1327ofMouseEventArgs args(action, instance->events().getMouseX(), instance->events().getMouseY(), button, modifiers);
1328
1329instance->events().notifyMouseEvent(args);
1330}
1331
1332//------------------------------------------------------------
1333void ofAppGLFWWindow::motion_cb(GLFWwindow* windowP_, double x, double y) {
1334ofAppGLFWWindow * instance = setCurrent(windowP_);
1335rotateMouseXY(instance->orientation, instance->getWidth(), instance->getHeight(), x, y);
1336
1337ofMouseEventArgs::Type action;
1338if(!instance->buttonPressed){
1339action = ofMouseEventArgs::Moved;
1340}else{
1341action = ofMouseEventArgs::Dragged;
1342}
1343
1344ofMouseEventArgs args(action,
1345x*instance->pixelScreenCoordScale,
1346y*instance->pixelScreenCoordScale,
1347instance->buttonInUse,
1348instance->events().getModifiers());
1349instance->events().notifyMouseEvent(args);
1350}
1351
1352//------------------------------------------------------------
1353void ofAppGLFWWindow::entry_cb(GLFWwindow *windowP_, int entered) {
1354ofAppGLFWWindow * instance = setCurrent(windowP_);
1355ofMouseEventArgs::Type action;
1356if(entered){
1357action = ofMouseEventArgs::Entered;
1358}else{
1359action = ofMouseEventArgs::Exited;
1360}
1361
1362ofMouseEventArgs args(action,
1363instance->events().getMouseX(),
1364instance->events().getMouseY(),
1365instance->buttonInUse,
1366instance->events().getModifiers());
1367instance->events().notifyMouseEvent(args);
1368}
1369
1370//------------------------------------------------------------
1371void ofAppGLFWWindow::scroll_cb(GLFWwindow* windowP_, double x, double y) {
1372ofAppGLFWWindow * instance = setCurrent(windowP_);
1373rotateMouseXY(instance->orientation, instance->getWidth(), instance->getHeight(), x, y);
1374
1375ofMouseEventArgs args(ofMouseEventArgs::Scrolled,
1376instance->events().getMouseX(),
1377instance->events().getMouseY(),
1378instance->buttonInUse,
1379instance->events().getModifiers());
1380args.scrollX = x;
1381args.scrollY = y;
1382instance->events().notifyMouseEvent(args);
1383}
1384
1385//------------------------------------------------------------
1386void ofAppGLFWWindow::drop_cb(GLFWwindow* windowP_, int numFiles, const char** dropString) {
1387ofAppGLFWWindow * instance = setCurrent(windowP_);
1388ofDragInfo drag;
1389drag.position = {instance->events().getMouseX(), instance->events().getMouseY()};
1390drag.files.resize(numFiles);
1391for(int i=0; i<(int)drag.files.size(); i++){
1392drag.files[i] = of::filesystem::path(dropString[i]).string();
1393}
1394instance->events().notifyDragEvent(drag);
1395}
1396
1397//------------------------------------------------------------
1398void ofAppGLFWWindow::error_cb(int errorCode, const char* errorDescription){
1399ofLogError("ofAppGLFWWindow") << errorCode << ": " << errorDescription;
1400}
1401
1402//------------------------------------------------------------
1403void ofAppGLFWWindow::keyboard_cb(GLFWwindow* windowP_, int keycode, int scancode, int action, int mods) {
1404int key = 0;
1405uint32_t codepoint = 0;
1406ofAppGLFWWindow * instance = setCurrent(windowP_);
1407switch (keycode) {
1408case GLFW_KEY_ESCAPE:
1409key = OF_KEY_ESC;
1410break;
1411case GLFW_KEY_F1:
1412key = OF_KEY_F1;
1413break;
1414case GLFW_KEY_F2:
1415key = OF_KEY_F2;
1416break;
1417case GLFW_KEY_F3:
1418key = OF_KEY_F3;
1419break;
1420case GLFW_KEY_F4:
1421key = OF_KEY_F4;
1422break;
1423case GLFW_KEY_F5:
1424key = OF_KEY_F5;
1425break;
1426case GLFW_KEY_F6:
1427key = OF_KEY_F6;
1428break;
1429case GLFW_KEY_F7:
1430key = OF_KEY_F7;
1431break;
1432case GLFW_KEY_F8:
1433key = OF_KEY_F8;
1434break;
1435case GLFW_KEY_F9:
1436key = OF_KEY_F9;
1437break;
1438case GLFW_KEY_F10:
1439key = OF_KEY_F10;
1440break;
1441case GLFW_KEY_F11:
1442key = OF_KEY_F11;
1443break;
1444case GLFW_KEY_F12:
1445key = OF_KEY_F12;
1446break;
1447case GLFW_KEY_LEFT:
1448key = OF_KEY_LEFT;
1449break;
1450case GLFW_KEY_RIGHT:
1451key = OF_KEY_RIGHT;
1452break;
1453case GLFW_KEY_UP:
1454key = OF_KEY_UP;
1455break;
1456case GLFW_KEY_DOWN:
1457key = OF_KEY_DOWN;
1458break;
1459case GLFW_KEY_PAGE_UP:
1460key = OF_KEY_PAGE_UP;
1461break;
1462case GLFW_KEY_PAGE_DOWN:
1463key = OF_KEY_PAGE_DOWN;
1464break;
1465case GLFW_KEY_HOME:
1466key = OF_KEY_HOME;
1467break;
1468case GLFW_KEY_END:
1469key = OF_KEY_END;
1470break;
1471case GLFW_KEY_INSERT:
1472key = OF_KEY_INSERT;
1473break;
1474case GLFW_KEY_LEFT_SHIFT:
1475key = OF_KEY_LEFT_SHIFT;
1476break;
1477case GLFW_KEY_LEFT_CONTROL:
1478key = OF_KEY_LEFT_CONTROL;
1479break;
1480case GLFW_KEY_LEFT_ALT:
1481key = OF_KEY_LEFT_ALT;
1482break;
1483case GLFW_KEY_LEFT_SUPER:
1484key = OF_KEY_LEFT_SUPER;
1485break;
1486case GLFW_KEY_RIGHT_SHIFT:
1487key = OF_KEY_RIGHT_SHIFT;
1488break;
1489case GLFW_KEY_RIGHT_CONTROL:
1490key = OF_KEY_RIGHT_CONTROL;
1491break;
1492case GLFW_KEY_RIGHT_ALT:
1493key = OF_KEY_RIGHT_ALT;
1494break;
1495case GLFW_KEY_RIGHT_SUPER:
1496key = OF_KEY_RIGHT_SUPER;
1497break;
1498case GLFW_KEY_BACKSPACE:
1499key = OF_KEY_BACKSPACE;
1500break;
1501case GLFW_KEY_DELETE:
1502key = OF_KEY_DEL;
1503break;
1504case GLFW_KEY_ENTER:
1505key = OF_KEY_RETURN;
1506codepoint = '\n';
1507break;
1508case GLFW_KEY_KP_ENTER:
1509key = OF_KEY_RETURN;
1510codepoint = '\n';
1511break;
1512case GLFW_KEY_TAB:
1513key = OF_KEY_TAB;
1514codepoint = '\t';
1515break;
1516case GLFW_KEY_KP_0:
1517key = codepoint = '0';
1518break;
1519case GLFW_KEY_KP_1:
1520key = codepoint = '1';
1521break;
1522case GLFW_KEY_KP_2:
1523key = codepoint = '2';
1524break;
1525case GLFW_KEY_KP_3:
1526key = codepoint = '3';
1527break;
1528case GLFW_KEY_KP_4:
1529key = codepoint = '4';
1530break;
1531case GLFW_KEY_KP_5:
1532key = codepoint = '5';
1533break;
1534case GLFW_KEY_KP_6:
1535key = codepoint = '6';
1536break;
1537case GLFW_KEY_KP_7:
1538key = codepoint = '7';
1539break;
1540case GLFW_KEY_KP_8:
1541key = codepoint = '8';
1542break;
1543case GLFW_KEY_KP_9:
1544key = codepoint = '9';
1545break;
1546case GLFW_KEY_KP_DIVIDE:
1547key = codepoint = '/';
1548break;
1549case GLFW_KEY_KP_MULTIPLY:
1550key = codepoint = '*';
1551break;
1552case GLFW_KEY_KP_SUBTRACT:
1553key = codepoint = '-';
1554break;
1555case GLFW_KEY_KP_ADD:
1556key = codepoint = '+';
1557break;
1558case GLFW_KEY_KP_DECIMAL:
1559key = codepoint = '.';
1560break;
1561case GLFW_KEY_KP_EQUAL:
1562key = codepoint = '=';
1563break;
1564default:
1565codepoint = keycodeToUnicode(instance, scancode, mods);
1566key = codepoint;
1567break;
1568}
1569
1570int modifiers = glfwtToOFModifiers(mods);
1571
1572if(action == GLFW_PRESS){
1573ofKeyEventArgs keyE(ofKeyEventArgs::Pressed,key,keycode,scancode,codepoint,modifiers);
1574instance->events().notifyKeyEvent(keyE);
1575}else if(action == GLFW_REPEAT){
1576ofKeyEventArgs keyE(ofKeyEventArgs::Pressed,key,keycode,scancode,codepoint,modifiers);
1577keyE.isRepeat = true;
1578instance->events().notifyKeyEvent(keyE);
1579}else if (action == GLFW_RELEASE){
1580ofKeyEventArgs keyE(ofKeyEventArgs::Released,key,keycode,scancode,codepoint,modifiers);
1581instance->events().notifyKeyEvent(keyE);
1582}
1583}
1584
1585//------------------------------------------------------------
1586void ofAppGLFWWindow::char_cb(GLFWwindow* windowP_, uint32_t key){
1587ofAppGLFWWindow * instance = setCurrent(windowP_);
1588instance->events().charEvent.notify(key);
1589}
1590
1591//------------------------------------------------------------
1592void ofAppGLFWWindow::resize_cb(GLFWwindow* windowP_, int w, int h) {
1593ofAppGLFWWindow * instance = setCurrent(windowP_);
1594
1595// Detect if the window is running in a retina mode
1596
1597int framebufferW, framebufferH; // <- physical pixel extents
1598glfwGetFramebufferSize(windowP_, &framebufferW, &framebufferH);
1599
1600int windowW, windowH; // <- screen coordinates, which may be scaled
1601glfwGetWindowSize(windowP_, &windowW, &windowH);
1602
1603// Find scale factor needed to transform from screen coordinates
1604// to physical pixel coordinates
1605instance->pixelScreenCoordScale = (float)framebufferW / (float)windowW;
1606
1607if(instance->settings.windowMode == OF_WINDOW){
1608instance->windowW = framebufferW;
1609instance->windowH = framebufferH;
1610}
1611
1612instance->currentW = windowW;
1613instance->currentH = windowH;
1614instance->events().notifyWindowResized(framebufferW, framebufferH);
1615instance->nFramesSinceWindowResized = 0;
1616
1617#if defined(TARGET_OSX)
1618NSWindow * cocoaWindow = glfwGetCocoaWindow(windowP_);
1619if (([cocoaWindow styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) {
1620instance->settings.windowMode = OF_FULLSCREEN;
1621}else{
1622instance->settings.windowMode = OF_WINDOW;
1623}
1624#endif
1625}
1626
1627//------------------------------------------------------------
1628void ofAppGLFWWindow::framebuffer_size_cb(GLFWwindow* windowP_, int w, int h){
1629resize_cb(windowP_, w, h);
1630}
1631
1632//--------------------------------------------
1633void ofAppGLFWWindow::exit_cb(GLFWwindow* windowP_){
1634ofAppGLFWWindow * instance = setCurrent(windowP_);
1635instance->events().notifyExit();
1636}
1637
1638//------------------------------------------------------------
1639void ofAppGLFWWindow::setVerticalSync(bool bVerticalSync){
1640if(bVerticalSync){
1641glfwSwapInterval( 1);
1642}else{
1643glfwSwapInterval(0);
1644}
1645}
1646
1647//------------------------------------------------------------
1648void ofAppGLFWWindow::setClipboardString(const std::string& text) {
1649glfwSetClipboardString(ofAppGLFWWindow::windowP, text.c_str());
1650}
1651
1652//------------------------------------------------------------
1653std::string ofAppGLFWWindow::getClipboardString() {
1654const char* clipboard = glfwGetClipboardString(ofAppGLFWWindow::windowP);
1655
1656if (clipboard) {
1657return clipboard;
1658} else {
1659return "";
1660}
1661}
1662
1663//------------------------------------------------------------
1664void ofAppGLFWWindow::listVideoModes(){
1665glfwInit();
1666int numModes;
1667const GLFWvidmode * vidModes = glfwGetVideoModes(nullptr, &numModes );
1668for(int i=0; i<numModes; i++){
1669ofLogNotice() << vidModes[i].width << " x " << vidModes[i].height
1670<< vidModes[i].redBits+vidModes[i].greenBits+vidModes[i].blueBits << "bit";
1671}
1672}
1673
1674//------------------------------------------------------------
1675void ofAppGLFWWindow::listMonitors(){
1676glfwInit();
1677int count;
1678const auto monitors = glfwGetMonitors(&count);
1679for(int i = 0; i<count; i++){
1680auto monitor = monitors[i];
1681int w,h,x,y;
1682glfwGetMonitorPhysicalSize(monitor,&w,&h);
1683glfwGetMonitorPos(monitor,&x,&y);
1684ofLogNotice() << i << ": " << glfwGetMonitorName(monitor) << ", physical size: " << w << "x" << h << "mm at " << x << ", " << y;
1685}
1686}
1687
1688//------------------------------------------------------------
1689bool ofAppGLFWWindow::isWindowIconified(){
1690return glfwGetWindowAttrib(windowP, GLFW_ICONIFIED);
1691}
1692
1693//------------------------------------------------------------
1694bool ofAppGLFWWindow::isWindowActive(){
1695// return glfwGetWindowParam(GLFW_ACTIVE);
1696return true;
1697}
1698
1699//------------------------------------------------------------
1700bool ofAppGLFWWindow::isWindowResizeable(){
1701return !glfwGetWindowAttrib(windowP, GLFW_RESIZABLE);
1702}
1703
1704//------------------------------------------------------------
1705void ofAppGLFWWindow::iconify(bool bIconify){
1706if(bIconify)
1707glfwIconifyWindow(windowP);
1708else
1709glfwRestoreWindow(windowP);
1710}
1711
1712
1713
1714void ofAppGLFWWindow::makeCurrent(){
1715glfwMakeContextCurrent(windowP);
1716}
1717
1718#if defined(TARGET_LINUX)
1719Display* ofAppGLFWWindow::getX11Display(){
1720return glfwGetX11Display();
1721}
1722
1723Window ofAppGLFWWindow::getX11Window(){
1724return glfwGetX11Window(windowP);
1725}
1726
1727XIC ofAppGLFWWindow::getX11XIC(){
1728return xic;
1729}
1730#endif
1731
1732#if defined(TARGET_LINUX) && !defined(TARGET_OPENGLES)
1733GLXContext ofAppGLFWWindow::getGLXContext(){
1734return glfwGetGLXContext(windowP);
1735}
1736#endif
1737
1738#if defined(TARGET_LINUX) && defined(TARGET_OPENGLES)
1739EGLDisplay ofAppGLFWWindow::getEGLDisplay(){
1740return glfwGetEGLDisplay();
1741}
1742
1743EGLContext ofAppGLFWWindow::getEGLContext(){
1744return glfwGetEGLContext(windowP);
1745}
1746
1747EGLSurface ofAppGLFWWindow::getEGLSurface(){
1748return glfwGetEGLSurface(windowP);
1749}
1750#endif
1751
1752#if defined(TARGET_OSX)
1753void * ofAppGLFWWindow::getNSGLContext(){
1754return (__bridge void *)glfwGetNSGLContext(windowP);
1755}
1756
1757void * ofAppGLFWWindow::getCocoaWindow(){
1758return (__bridge void *)glfwGetCocoaWindow(windowP);
1759}
1760#endif
1761
1762#if defined(TARGET_WIN32)
1763HGLRC ofAppGLFWWindow::getWGLContext(){
1764return glfwGetWGLContext(windowP);
1765}
1766
1767HWND ofAppGLFWWindow::getWin32Window(){
1768return glfwGetWin32Window(windowP);
1769}
1770
1771#endif
1772