#include <config.h>
#include "Fl_Cocoa_Screen_Driver.H"
#include "Fl_Cocoa_Window_Driver.H"
#include "../Quartz/Fl_Font.H"
#include <FL/Fl.H>
#include <FL/platform.H>
#include <FL/Fl_Graphics_Driver.H>
#include <FL/Fl_Input.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Image_Surface.H>
#include <stdio.h>
extern "C" void NSBeep(void);
extern void (*fl_lock_function)();
extern void (*fl_unlock_function)();
int Fl_Cocoa_Screen_Driver::next_marked_length = 0;
Fl_Screen_Driver::Keyname darwin_key_table[] = {
{' ', "Space"},
{FL_BackSpace, "⌫"}, {FL_Tab, "⇥"}, {FL_Enter, "↩"}, {FL_Pause, "Pause"},
{FL_Scroll_Lock, "Scroll_Lock"},
{FL_Escape, "⎋"}, {FL_Home, "↖"}, {FL_Left, "←"}, {FL_Up, "↑"}, {FL_Right, "→"}, {FL_Down, "↓"}, {FL_Page_Up, "⇞"}, {FL_Page_Down, "⇟"}, {FL_End, "↘"}, {FL_Print, "Print"},
{FL_Insert, "Insert"},
{FL_Menu, "Menu"},
{FL_Num_Lock, "Num_Lock"},
{FL_KP_Enter, "⌤"}, {FL_Shift_L, "Shift_L"},
{FL_Shift_R, "Shift_R"},
{FL_Control_L, "Control_L"},
{FL_Control_R, "Control_R"},
{FL_Caps_Lock, "⇪"}, {FL_Meta_L, "Meta_L"},
{FL_Meta_R, "Meta_R"},
{FL_Alt_L, "Alt_L"},
{FL_Alt_R, "Alt_R"},
{FL_Delete, "⌦"} };
static Fl_Text_Editor::Key_Binding extra_bindings[] = {
{ 'z', FL_COMMAND, Fl_Text_Editor::kf_undo ,0},
{ 'z', FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_redo ,0},
{ 'x', FL_COMMAND, Fl_Text_Editor::kf_cut ,0},
{ 'c', FL_COMMAND, Fl_Text_Editor::kf_copy ,0},
{ 'v', FL_COMMAND, Fl_Text_Editor::kf_paste ,0},
{ 'a', FL_COMMAND, Fl_Text_Editor::kf_select_all ,0},
{ FL_Left, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0},
{ FL_Right, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0},
{ FL_Up, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0},
{ FL_Down, FL_COMMAND, Fl_Text_Editor::kf_meta_move ,0},
{ FL_Left, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0},
{ FL_Right, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0},
{ FL_Up, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0},
{ FL_Down, FL_COMMAND|FL_SHIFT, Fl_Text_Editor::kf_m_s_move ,0},
{ 0, 0, 0 ,0}
};
Fl_Cocoa_Screen_Driver::Fl_Cocoa_Screen_Driver() {
text_editor_extra_key_bindings = extra_bindings;
scale_ = 1.;
default_icon = nil;
key_table = darwin_key_table;
key_table_size = sizeof(darwin_key_table)/sizeof(*darwin_key_table);
}
void Fl_Cocoa_Screen_Driver::init()
{
open_display();
CGDirectDisplayID displays[MAX_SCREENS];
CGDisplayCount count, i;
CGRect r;
CGGetActiveDisplayList(MAX_SCREENS, displays, &count);
for( i = 0; i < count; i++) {
r = CGDisplayBounds(displays[i]);
screens[i].x = int(r.origin.x);
screens[i].y = int(r.origin.y);
screens[i].width = int(r.size.width);
screens[i].height = int(r.size.height);
if (&CGDisplayScreenSize != NULL) {
CGSize s = CGDisplayScreenSize(displays[i]); dpi_h[i] = screens[i].width / (s.width/25.4);
dpi_v[i] = screens[i].height / (s.height/25.4);
} else {
dpi_h[i] = dpi_v[i] = 75.;
}
}
num_screens = count;
}
void Fl_Cocoa_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n)
{
if (num_screens < 0) init();
if ((n < 0) || (n >= num_screens))
n = 0;
float s = scale(0);
X = screens[n].x/s;
Y = screens[n].y/s;
W = screens[n].width/s;
H = screens[n].height/s;
}
void Fl_Cocoa_Screen_Driver::screen_dpi(float &h, float &v, int n)
{
if (num_screens < 0) init();
h = v = 0.0f;
if (n >= 0 && n < num_screens) {
h = dpi_h[n];
v = dpi_v[n];
}
}
void Fl_Cocoa_Screen_Driver::beep(int type) {
switch (type) {
case FL_BEEP_DEFAULT :
case FL_BEEP_ERROR :
NSBeep();
break;
default :
break;
}
}
extern void fl_fix_focus();
extern void *fl_capture;
void Fl_Cocoa_Screen_Driver::grab(Fl_Window* win)
{
if (win) {
if (!Fl::grab_) {
fl_capture = (FLWindow*)(Fl_X::flx(Fl::first_window())->xid);
Fl_Cocoa_Window_Driver::driver(Fl::first_window())->set_key_window();
}
Fl::grab_ = win;
} else {
if (Fl::grab_) {
fl_capture = 0;
Fl::grab_ = 0;
fl_fix_focus();
}
}
}
static void set_selection_color(uchar r, uchar g, uchar b)
{
Fl::set_color(FL_SELECTION_COLOR,r,g,b);
}
void Fl_Cocoa_Screen_Driver::get_system_colors()
{
open_display();
Fl_Screen_Driver::get_system_colors();
if (!bg2_set) Fl::background2(0xff, 0xff, 0xff);
if (!fg_set) Fl::foreground(0, 0, 0);
if (!bg_set) Fl::background(0xd8, 0xd8, 0xd8);
#if 0#else
set_selection_color(0x00, 0x00, 0x80);
#endif
}
int Fl_Cocoa_Screen_Driver::has_marked_text() const {
return 1;
}
int Fl_Cocoa_Screen_Driver::insertion_point_x = 0;
int Fl_Cocoa_Screen_Driver::insertion_point_y = 0;
int Fl_Cocoa_Screen_Driver::insertion_point_height = 0;
bool Fl_Cocoa_Screen_Driver::insertion_point_location_is_valid = false;
void Fl_Cocoa_Screen_Driver::reset_marked_text() {
Fl::compose_state = 0;
next_marked_length = 0;
insertion_point_location_is_valid = false;
}
int Fl_Cocoa_Screen_Driver::insertion_point_location(int *px, int *py, int *pheight)
{
if ( ! insertion_point_location_is_valid ) return false;
*px = insertion_point_x;
*py = insertion_point_y;
*pheight = insertion_point_height;
return true;
}
void Fl_Cocoa_Screen_Driver::insertion_point_location(int x, int y, int height) {
insertion_point_location_is_valid = true;
insertion_point_x = x;
insertion_point_y = y;
insertion_point_height = height;
}
int Fl_Cocoa_Screen_Driver::compose(int &del) {
int condition;
int has_text_key = Fl::compose_state || Fl::e_keysym <= '~' || Fl::e_keysym == FL_Iso_Key ||
Fl::e_keysym == FL_JIS_Underscore || Fl::e_keysym == FL_Yen ||
(Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last && Fl::e_keysym != FL_KP_Enter);
condition = Fl::e_state&(FL_META | FL_CTRL) ||
(Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || !has_text_key ;
if (condition) { del = 0; return 0;} del = Fl::compose_state;
Fl::compose_state = next_marked_length;
return 1;
}
int Fl_Cocoa_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned shift, Fl_Input *input)
{
switch (key) {
case FL_Delete: {
if (mods==0) return input->kf_delete_char_right(); if (mods==FL_CTRL) return input->kf_delete_char_right(); if (mods==FL_ALT) return input->kf_delete_word_right(); return 0; }
case FL_Left:
if (mods==0) return input->kf_move_char_left(); if (mods==FL_ALT) return input->kf_move_word_left(); if (mods==FL_META) return input->kf_move_sol(); if (mods==FL_CTRL) return input->kf_move_sol(); return 0;
case FL_Right:
if (mods==0) return input->kf_move_char_right(); if (mods==FL_ALT) return input->kf_move_word_right(); if (mods==FL_META) return input->kf_move_eol(); if (mods==FL_CTRL) return input->kf_move_eol(); return 0;
case FL_Up:
if (mods==0) return input->kf_lines_up(1); if (mods==FL_CTRL) return input->kf_page_up(); if (mods==FL_ALT) return input->kf_move_up_and_sol(); if (mods==FL_META) return input->kf_top(); return 0;
case FL_Down:
if (mods==0) return input->kf_lines_down(1); if (mods==FL_CTRL) return input->kf_page_down(); if (mods==FL_ALT) return input->kf_move_down_and_eol(); if (mods==FL_META) return input->kf_bottom(); return 0;
case FL_Page_Up:
if (mods==0) return input->kf_page_up(); if (mods==FL_ALT) return input->kf_page_up(); if (mods==FL_META) return input->kf_top(); return 0;
case FL_Page_Down:
if (mods==0) return input->kf_page_down(); if (mods==FL_ALT) return input->kf_page_down(); if (mods==FL_META) return input->kf_bottom(); return 0;
case FL_Home:
if (mods==0) return input->kf_top(); if (mods==FL_ALT) return input->kf_top(); return 0;
case FL_End:
if (mods==0) return input->kf_bottom(); if (mods==FL_ALT) return input->kf_bottom(); return 0;
case FL_BackSpace:
if (mods==0) return input->kf_delete_char_left(); if (mods==FL_CTRL) return input->kf_delete_char_left(); if (mods==FL_ALT) return input->kf_delete_word_left(); if (mods==FL_META) return input->kf_delete_sol(); return 0; }
return -1;
}
void Fl_Cocoa_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height)
{
width = (int)CGBitmapContextGetWidth((CGContextRef)off);
height = (int)CGBitmapContextGetHeight((CGContextRef)off);
}
Fl_RGB_Image *Fl_Cocoa_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h, Fl_Window *window,
bool may_capture_subwins, bool *did_capture_subwins)
{
int bpp, bpr;
uchar *base, *p;
if (!window) { float s = 1;
CGContextRef src = (CGContextRef)Fl_Surface_Device::surface()->driver()->gc(); base = (uchar *)CGBitmapContextGetData(src); if(!base) return NULL;
int sw = (int)CGBitmapContextGetWidth(src);
int sh = (int)CGBitmapContextGetHeight(src);
if( (sw - X < w) || (sh - Y < h) ) return NULL;
bpr = (int)CGBitmapContextGetBytesPerRow(src);
bpp = (int)CGBitmapContextGetBitsPerPixel(src)/8;
Fl_Image_Surface *imgs = (Fl_Image_Surface*)Fl_Surface_Device::surface();
int fltk_w, fltk_h;
imgs->printable_rect(&fltk_w, &fltk_h);
s = sw / float(fltk_w);
X *= s; Y *= s; w *= s; h *= s;
if (X + w > sw) w = sw - X;
if (Y + h > sh) h = sh - Y;
int idx, idy; uchar *pdst, *psrc;
p = new uchar[w * h * 4];
for (idy = Y, pdst = p; idy < h + Y; idy ++) {
for (idx = 0, psrc = base + idy * bpr + X * bpp; idx < w; idx ++, psrc += bpp, pdst += 4) {
pdst[0] = psrc[0]; pdst[1] = psrc[1]; pdst[2] = psrc[2]; }
}
bpr = 0;
} else { Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window);
CGImageRef cgimg = d->CGImage_from_window_rect(X, Y, w, h, may_capture_subwins);
if (did_capture_subwins) *did_capture_subwins = may_capture_subwins;
if (!cgimg) {
return NULL;
}
w = (int)CGImageGetWidth(cgimg);
h = (int)CGImageGetHeight(cgimg);
Fl_Image_Surface *surf = new Fl_Image_Surface(w, h);
Fl_Surface_Device::push_current(surf);
((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(cgimg, 0, 0, w, h, 0, 0, w, h);
CGContextRef gc = (CGContextRef)fl_graphics_driver->gc();
w = (int)CGBitmapContextGetWidth(gc);
h = (int)CGBitmapContextGetHeight(gc);
bpr = (int)CGBitmapContextGetBytesPerRow(gc);
bpp = (int)CGBitmapContextGetBitsPerPixel(gc)/8;
base = (uchar*)CGBitmapContextGetData(gc);
p = new uchar[bpr * h];
memcpy(p, base, bpr * h);
Fl_Surface_Device::pop_current();
delete surf;
CFRelease(cgimg);
}
Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, 4, bpr);
rgb->alloc_array = 1;
return rgb;
}
void Fl_Cocoa_Screen_Driver::set_spot(int , int size, int X, int Y, int , int , Fl_Window* ) {
Fl_Cocoa_Screen_Driver::insertion_point_location(X, Y, size);
}
void Fl_Cocoa_Screen_Driver::reset_spot() {
Fl_Cocoa_Screen_Driver::reset_marked_text();
}