From 47462c7a88ed4f844fa4eaf32a84533aa847b7d5 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Thu, 10 Aug 2017 15:43:21 -0600 Subject: [PATCH 1/1] titler/crikey grab window warns, c41 rework --- cinelerra-5.1/plugins/C41/c41.C | 860 +++++++++++++------- cinelerra-5.1/plugins/C41/c41.h | 195 +++++ cinelerra-5.1/plugins/crikey/crikeywindow.C | 36 +- cinelerra-5.1/plugins/titler/titlerwindow.C | 41 +- 4 files changed, 791 insertions(+), 341 deletions(-) create mode 100644 cinelerra-5.1/plugins/C41/c41.h diff --git a/cinelerra-5.1/plugins/C41/c41.C b/cinelerra-5.1/plugins/C41/c41.C index c9b3fbe6..32f5afe3 100644 --- a/cinelerra-5.1/plugins/C41/c41.C +++ b/cinelerra-5.1/plugins/C41/c41.C @@ -17,155 +17,35 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - -#include "bcdisplayinfo.h" -#include "bchash.h" +#include "c41.h" +#include "cicolors.h" #include "clip.h" +#include "edlsession.h" #include "filexml.h" -#include "guicast.h" #include "language.h" -#include "cicolors.h" -#include "pluginvclient.h" #include "vframe.h" -#include -#include - -/* Class declarations */ -class C41Effect; -class C41Window; - -struct magic -{ - float min_r; - float min_g; - float min_b; - float light; - float gamma_g; - float gamma_b; -}; - -class C41Config -{ -public: - C41Config(); - - void copy_from(C41Config &src); - int equivalent(C41Config &src); - void interpolate(C41Config &prev, - C41Config &next, - long prev_frame, - long next_frame, - long current_frame); - - int active; - int compute_magic; - float fix_min_r; - float fix_min_g; - float fix_min_b; - float fix_light; - float fix_gamma_g; - float fix_gamma_b; -}; - -class C41Enable : public BC_CheckBox -{ -public: - C41Enable(C41Effect *plugin, int *output, int x, int y, char *text); - int handle_event(); - C41Effect *plugin; - int *output; -}; - -class C41TextBox : public BC_TextBox -{ -public: - C41TextBox(C41Effect *plugin, float *value, int x, int y); - int handle_event(); - C41Effect *plugin; - float *boxValue; -}; - -class C41Button : public BC_GenericButton -{ -public: - C41Button(C41Effect *plugin, C41Window *window, int x, int y); - int handle_event(); - C41Effect *plugin; - C41Window *window; - float *boxValue; -}; - -class C41Window : public PluginClientWindow -{ -public: - C41Window(C41Effect *plugin); - void create_objects(); - void update(); - void update_magic(); - C41Enable *active; - C41Enable *compute_magic; - BC_Title *min_r; - BC_Title *min_g; - BC_Title *min_b; - BC_Title *light; - BC_Title *gamma_g; - BC_Title *gamma_b; - C41TextBox *fix_min_r; - C41TextBox *fix_min_g; - C41TextBox *fix_min_b; - C41TextBox *fix_light; - C41TextBox *fix_gamma_g; - C41TextBox *fix_gamma_b; - C41Button *lock; - C41Effect *plugin; -}; - - -class C41Effect : public PluginVClient -{ -public: - C41Effect(PluginServer *server); - ~C41Effect(); - PLUGIN_CLASS_MEMBERS(C41Config); - - int process_buffer(VFrame *frame, - int64_t start_position, - double frame_rate); - int is_realtime(); - void save_data(KeyFrame *keyframe); - void read_data(KeyFrame *keyframe); - void update_gui(); - void render_gui(void* data); - int show_gui(); - void raise_window(); - float myLog2(float i) __attribute__ ((optimize(0))); - float myPow2(float i) __attribute__ ((optimize(0))); - float myPow(float a, float b); - double difftime_nano(timespec start, timespec end); - - struct magic values; -}; - - REGISTER_PLUGIN(C41Effect); - -/* Methods decarations */ - -// C41Config C41Config::C41Config() { active = 0; compute_magic = 0; + postproc = 0; + show_box = 0; - fix_min_r = fix_min_g = fix_min_b = fix_light = fix_gamma_g = fix_gamma_b = 0.; + fix_min_r = fix_min_g = fix_min_b = fix_light = 0.; + fix_gamma_g = fix_gamma_b = fix_coef1 = fix_coef2 = 0.; + min_col = max_col = min_row = max_row = 0; + window_w = 500; window_h = 510; } void C41Config::copy_from(C41Config &src) { active = src.active; compute_magic = src.compute_magic; + postproc = src.postproc; + show_box = src.show_box; fix_min_r = src.fix_min_r; fix_min_g = src.fix_min_g; @@ -173,39 +53,60 @@ void C41Config::copy_from(C41Config &src) fix_light = src.fix_light; fix_gamma_g = src.fix_gamma_g; fix_gamma_b = src.fix_gamma_b; + fix_coef1 = src.fix_coef1; + fix_coef2 = src.fix_coef2; + min_row = src.min_row; + max_row = src.max_row; + min_col = src.min_col; + max_col = src.max_col; } int C41Config::equivalent(C41Config &src) { - return (src.active == active && + return (active == src.active && compute_magic == src.compute_magic && - EQUIV(src.fix_min_r, fix_min_r) && - EQUIV(src.fix_min_g, fix_min_g) && - EQUIV(src.fix_min_b, fix_min_b) && - EQUIV(src.fix_light, fix_light) && - EQUIV(src.fix_gamma_g, fix_gamma_g) && - EQUIV(src.fix_gamma_b, fix_gamma_b)); + postproc == src.postproc && + show_box == src.show_box && + EQUIV(fix_min_r, src.fix_min_r) && + EQUIV(fix_min_g, src.fix_min_g) && + EQUIV(fix_min_b, src.fix_min_b) && + EQUIV(fix_light, src.fix_light) && + EQUIV(fix_gamma_g, src.fix_gamma_g) && + EQUIV(fix_gamma_b, src.fix_gamma_b) && + EQUIV(fix_coef1, src.fix_coef1) && + EQUIV(fix_coef2, src.fix_coef2) && + min_row == src.min_row && + max_row == src.max_row && + min_col == src.min_col && + max_col == src.max_col); } -void C41Config::interpolate(C41Config &prev, - C41Config &next, - long prev_frame, - long next_frame, - long current_frame) +void C41Config::interpolate(C41Config &prev, C41Config &next, + long prev_frame, long next_frame, long current_frame) { active = prev.active; compute_magic = prev.compute_magic; - - fix_min_r = prev.fix_min_r; - fix_min_g = prev.fix_min_g; - fix_min_b = prev.fix_min_b; - fix_light = prev.fix_light; - fix_gamma_g = prev.fix_gamma_g; - fix_gamma_b = prev.fix_gamma_b; + postproc = prev.postproc; + show_box = prev.show_box; + + double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); + double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); + fix_min_r = prev.fix_min_r * prev_scale + next.fix_min_r * next_scale; + fix_min_g = prev.fix_min_g * prev_scale + next.fix_min_g * next_scale; + fix_min_b = prev.fix_min_b * prev_scale + next.fix_min_b * next_scale; + fix_light = prev.fix_light * prev_scale + next.fix_light * next_scale; + fix_gamma_g = prev.fix_gamma_g * prev_scale + next.fix_gamma_g * next_scale; + fix_gamma_b = prev.fix_gamma_b * prev_scale + next.fix_gamma_b * next_scale; + fix_coef1 = prev.fix_coef1 * prev_scale + next.fix_coef1 * next_scale; + fix_coef2 = prev.fix_coef2 * prev_scale + next.fix_coef2 * next_scale; + min_row = round(prev.min_row * prev_scale + next.min_row * next_scale); + min_col = round(prev.min_col * prev_scale + next.min_col * next_scale); + max_row = round(prev.max_row * prev_scale + next.max_row * next_scale); + max_col = round(prev.max_col * prev_scale + next.max_col * next_scale); } // C41Enable -C41Enable::C41Enable(C41Effect *plugin, int *output, int x, int y, char *text) +C41Enable::C41Enable(C41Effect *plugin, int *output, int x, int y, const char *text) : BC_CheckBox(x, y, *output, text) { this->plugin = plugin; @@ -237,7 +138,7 @@ int C41TextBox::handle_event() // C41Button C41Button::C41Button(C41Effect *plugin, C41Window *window, int x, int y) - : BC_GenericButton(x, y, _("Lock parameters")) + : BC_GenericButton(x, y, _("Apply values")) { this->plugin = plugin; this->window = window; @@ -251,45 +152,107 @@ int C41Button::handle_event() plugin->config.fix_light = plugin->values.light; plugin->config.fix_gamma_g = plugin->values.gamma_g; plugin->config.fix_gamma_b = plugin->values.gamma_b; + if( plugin->values.coef1 > 0 ) + plugin->config.fix_coef1 = plugin->values.coef1; + if( plugin->values.coef2 > 0 ) + plugin->config.fix_coef2 = plugin->values.coef2; window->update(); + plugin->send_configure_change(); return 1; } -// C41Window -C41Window::C41Window(C41Effect *plugin) - : PluginClientWindow(plugin, 270, 620, 1, 0, 1) + +C41BoxButton::C41BoxButton(C41Effect *plugin, C41Window *window, int x, int y) + : BC_GenericButton(x, y, _("Apply box")) { this->plugin = plugin; + this->window = window; } -void C41Window::create_objects() +int C41BoxButton::handle_event() { - int x = 10; - int y = 10; + plugin->config.min_row = plugin->values.shave_min_row; + plugin->config.max_row = plugin->values.shave_max_row; + plugin->config.min_col = plugin->values.shave_min_col; + plugin->config.max_col = plugin->values.shave_max_col; + + window->update(); + + plugin->send_configure_change(); + return 1; +} - add_subwindow(active = new C41Enable(plugin, &plugin->config.active, x, y, _("Activate processing"))); + +C41Slider::C41Slider(C41Effect *plugin, int *output, int x, int y, int is_row) + : BC_ISlider(x, y, 0, 200, 200, 0, is_row ? + plugin->get_edlsession()->output_h : + plugin->get_edlsession()->output_w , *output) +{ + this->plugin = plugin; + this->output = output; + this->is_row = is_row; + EDLSession *session = plugin->get_edlsession(); + this->max = is_row ? session->output_h : session->output_w; +} + +int C41Slider::handle_event() +{ + *output = get_value(); + plugin->send_configure_change(); + return 1; +} + +int C41Slider::update(int v) +{ + EDLSession *session = plugin->get_edlsession(); + int max = is_row ? session->output_h : session->output_w; + bclamp(v, 0, max); + if( this->max != max ) return BC_ISlider::update(200, v, 0, this->max = max); + if( v != get_value() ) return BC_ISlider::update(v); + return 1; +} + +const char* C41Effect::plugin_title() { return _("C41"); } +int C41Effect::is_realtime() { return 1; } +int C41Effect::is_synthesis() { return 1; } + +NEW_WINDOW_MACRO(C41Effect, C41Window); +LOAD_CONFIGURATION_MACRO(C41Effect, C41Config) + +// C41Window +C41Window::C41Window(C41Effect *plugin) + : PluginClientWindow(plugin, + plugin->config.window_w, plugin->config.window_h, + 500, 510, 1) +{ + int x = 10, y = 10; + + add_subwindow(active = new C41Enable(plugin, + &plugin->config.active, x, y, _("Activate processing"))); y += 40; - add_subwindow(compute_magic = new C41Enable(plugin, &plugin->config.compute_magic, x, y, _("Compute negfix values"))); + add_subwindow(compute_magic = new C41Enable(plugin, + &plugin->config.compute_magic, x, y, _("Compute negfix values"))); y += 20; + add_subwindow(new BC_Title(x + 20, y, _("(uncheck for faster rendering)"))); y += 40; add_subwindow(new BC_Title(x, y, _("Computed negfix values:"))); y += 30; - add_subwindow(new BC_Title(x, y, _("Min R:"))); - add_subwindow(min_r = new BC_Title(x + 80, y, "0.0000")); + add_subwindow(new BC_Title(x, y, _("Min/Max R:"))); + add_subwindow(min_r = new BC_Title(x + 80, y, "0.0000 / 0.0000")); y += 30; - add_subwindow(new BC_Title(x, y, _("Min G:"))); - add_subwindow(min_g = new BC_Title(x + 80, y, "0.0000")); + add_subwindow(new BC_Title(x, y, _("Min/Max G:"))); + add_subwindow(min_g = new BC_Title(x + 80, y, "0.0000 / 0.0000")); y += 30; - add_subwindow(new BC_Title(x, y, _("Min B:"))); - add_subwindow(min_b = new BC_Title(x + 80, y, "0.0000")); + add_subwindow(new BC_Title(x, y, _("Min/Max B:"))); + add_subwindow(min_b = new BC_Title(x + 80, y, "0.0000 / 0.0000")); y += 30; add_subwindow(new BC_Title(x, y, _("Light:"))); @@ -304,45 +267,114 @@ void C41Window::create_objects() add_subwindow(gamma_b = new BC_Title(x + 80, y, "0.0000")); y += 30; + add_subwindow(new BC_Title(x, y, _("Coef 1:"))); + add_subwindow(coef1 = new BC_Title(x + 80, y, "0.0000")); + y += 30; + + add_subwindow(new BC_Title(x, y, _("Coef 2:"))); + add_subwindow(coef2 = new BC_Title(x + 80, y, "0.0000")); + y += 30; + add_subwindow(lock = new C41Button(plugin, this, x, y)); y += 30; - y += 20; +#define BOX_COL 120 + add_subwindow(new BC_Title(x, y, _("Box col:"))); + add_subwindow(box_col_min = new BC_Title(x + 80, y, "0")); + add_subwindow(box_col_max = new BC_Title(x + BOX_COL, y, "0")); + y += 30; + + add_subwindow(new BC_Title(x, y, _("Box row:"))); + add_subwindow(box_row_min = new BC_Title(x + 80, y, "0")); + add_subwindow(box_row_max = new BC_Title(x + BOX_COL, y, "0")); + y += 30; + + add_subwindow(boxlock = new C41BoxButton(plugin, this, x, y)); + + y = 10; + x = 250; + add_subwindow(show_box = new C41Enable(plugin, + &plugin->config.show_box, x, y, _("Show active area"))); + y += 40; + + add_subwindow(postproc = new C41Enable(plugin, + &plugin->config.postproc, x, y, _("Postprocess"))); + y += 60; + add_subwindow(new BC_Title(x, y, _("negfix values to apply:"))); y += 30; add_subwindow(new BC_Title(x, y, _("Min R:"))); - add_subwindow(fix_min_r = new C41TextBox(plugin, &plugin->config.fix_min_r, x + 80, y)); + add_subwindow(fix_min_r = new C41TextBox(plugin, + &plugin->config.fix_min_r, x + 80, y)); y += 30; add_subwindow(new BC_Title(x, y, _("Min G:"))); - add_subwindow(fix_min_g = new C41TextBox(plugin, &plugin->config.fix_min_g, x + 80, y)); + add_subwindow(fix_min_g = new C41TextBox(plugin, + &plugin->config.fix_min_g, x + 80, y)); y += 30; add_subwindow(new BC_Title(x, y, _("Min B:"))); - add_subwindow(fix_min_b = new C41TextBox(plugin, &plugin->config.fix_min_b, x + 80, y)); + add_subwindow(fix_min_b = new C41TextBox(plugin, + &plugin->config.fix_min_b, x + 80, y)); y += 30; add_subwindow(new BC_Title(x, y, _("Light:"))); - add_subwindow(fix_light = new C41TextBox(plugin, &plugin->config.fix_light, x + 80, y)); + add_subwindow(fix_light = new C41TextBox(plugin, + &plugin->config.fix_light, x + 80, y)); y += 30; add_subwindow(new BC_Title(x, y, _("Gamma G:"))); - add_subwindow(fix_gamma_g = new C41TextBox(plugin, &plugin->config.fix_gamma_g, x + 80, y)); + add_subwindow(fix_gamma_g = new C41TextBox(plugin, + &plugin->config.fix_gamma_g, x + 80, y)); y += 30; add_subwindow(new BC_Title(x, y, _("Gamma B:"))); - add_subwindow(fix_gamma_b = new C41TextBox(plugin, &plugin->config.fix_gamma_b, x + 80, y)); + add_subwindow(fix_gamma_b = new C41TextBox(plugin, + &plugin->config.fix_gamma_b, x + 80, y)); y += 30; - show_window(); - flush(); + + add_subwindow(new BC_Title(x, y, _("Coef 1:"))); + add_subwindow(fix_coef1 = new C41TextBox(plugin, + &plugin->config.fix_coef1, x + 80, y)); + y += 30; + + add_subwindow(new BC_Title(x, y, _("Coef 2:"))); + add_subwindow(fix_coef2 = new C41TextBox(plugin, + &plugin->config.fix_coef2, x + 80, y)); + y += 30; + + x += 40; + add_subwindow(new BC_Title(x - 40, y, _("Col:"))); + add_subwindow(min_col = new C41Slider(plugin, + &plugin->config.min_col, x, y, 0)); + y += 25; + + add_subwindow(max_col = new C41Slider(plugin, + &plugin->config.max_col, x, y, 0)); + y += 25; + + add_subwindow(new BC_Title(x - 40, y, _("Row:"))); + add_subwindow(min_row = new C41Slider(plugin, + &plugin->config.min_row, x, y, 1)); + y += 25; + + add_subwindow(max_row = new C41Slider(plugin, + &plugin->config.max_row, x, y, 1)); + y += 25; + update_magic(); + show_window(1); } void C41Window::update() { + C41Effect *plugin = (C41Effect *)client; + // Updating the GUI itself active->update(plugin->config.active); compute_magic->update(plugin->config.compute_magic); + postproc->update(plugin->config.postproc); + show_box->update(plugin->config.show_box); fix_min_r->update(plugin->config.fix_min_r); fix_min_g->update(plugin->config.fix_min_g); @@ -350,61 +382,74 @@ void C41Window::update() fix_light->update(plugin->config.fix_light); fix_gamma_g->update(plugin->config.fix_gamma_g); fix_gamma_b->update(plugin->config.fix_gamma_b); + fix_coef1->update(plugin->config.fix_coef1); + fix_coef2->update(plugin->config.fix_coef2); + + min_row->update(plugin->config.min_row); + max_row->update(plugin->config.max_row); + min_col->update(plugin->config.min_col); + max_col->update(plugin->config.max_col); update_magic(); } void C41Window::update_magic() { - min_r->update(plugin->values.min_r); - min_g->update(plugin->values.min_g); - min_b->update(plugin->values.min_b); + C41Effect *plugin = (C41Effect *)client; + char text[BCSTRLEN]; + sprintf(text, "%0.4f / %0.4f", plugin->values.min_r, plugin->values.max_r); + min_r->update(text); + sprintf(text, "%0.4f / %0.4f", plugin->values.min_g, plugin->values.max_g); + min_g->update(text); + sprintf(text, "%0.4f / %0.4f", plugin->values.min_b, plugin->values.max_b); + min_b->update(text); light->update(plugin->values.light); gamma_g->update(plugin->values.gamma_g); gamma_b->update(plugin->values.gamma_b); + // Avoid blinking + if( plugin->values.coef1 > 0 || plugin->values.coef2 > 0 ) { + coef1->update(plugin->values.coef1); + coef2->update(plugin->values.coef2); + } + sprintf(text, "%d", plugin->values.shave_min_col); + box_col_min->update(text); + sprintf(text, "%d", plugin->values.shave_max_col); + box_col_max->update(text); + sprintf(text, "%d", plugin->values.shave_min_row); + box_row_min->update(text); + sprintf(text, "%d", plugin->values.shave_max_row); + box_row_max->update(text); } // C41Effect C41Effect::C41Effect(PluginServer *server) - : PluginVClient(server) +: PluginVClient(server) { + frame = 0; + tmp_frame = 0; + blurry_frame = 0; memset(&values, 0, sizeof(values)); } C41Effect::~C41Effect() { -} - -const char* C41Effect::plugin_title() { return _("C41"); } - -int C41Effect::is_realtime() { return 1; } - -LOAD_CONFIGURATION_MACRO(C41Effect, C41Config) - - -NEW_WINDOW_MACRO(C41Effect, C41Window) - -void C41Effect::update_gui() -{ - if(thread && load_configuration()) - { - C41Window *window = (C41Window *)thread->window; - window->lock_window("C41Effect::update_gui"); - window->update(); - window->unlock_window(); - } + delete frame; + delete tmp_frame; + delete blurry_frame; } void C41Effect::render_gui(void* data) { // Updating values computed by process_frame struct magic *vp = (struct magic *)data; - values = *vp; - if(thread) { - C41Window *window = (C41Window *)thread->window; + + if( thread ) { + C41Window *window = (C41Window *) thread->window; + window->lock_window("C41Effect::render_gui"); window->update_magic(); + window->unlock_window(); } } @@ -412,9 +457,12 @@ void C41Effect::save_data(KeyFrame *keyframe) { FileXML output; output.set_shared_output(keyframe->get_data(), MESSAGESIZE); + output.tag.set_title("C41"); output.tag.set_property("ACTIVE", config.active); output.tag.set_property("COMPUTE_MAGIC", config.compute_magic); + output.tag.set_property("POSTPROC", config.postproc); + output.tag.set_property("SHOW_BOX", config.show_box); output.tag.set_property("FIX_MIN_R", config.fix_min_r); output.tag.set_property("FIX_MIN_G", config.fix_min_g); @@ -422,7 +470,12 @@ void C41Effect::save_data(KeyFrame *keyframe) output.tag.set_property("FIX_LIGHT", config.fix_light); output.tag.set_property("FIX_GAMMA_G", config.fix_gamma_g); output.tag.set_property("FIX_GAMMA_B", config.fix_gamma_b); - + output.tag.set_property("FIX_COEF1", config.fix_coef1); + output.tag.set_property("FIX_COEF2", config.fix_coef2); + output.tag.set_property("MIN_ROW", config.min_row); + output.tag.set_property("MAX_ROW", config.max_row); + output.tag.set_property("MIN_COL", config.min_col); + output.tag.set_property("MAX_COL", config.max_col); output.append_tag(); output.tag.set_title("/C41"); output.append_tag(); @@ -433,35 +486,37 @@ void C41Effect::read_data(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); + while(!input.read_tag()) { - if(input.tag.title_is("C41")) - { + if( input.tag.title_is("C41") ) { config.active = input.tag.get_property("ACTIVE", config.active); config.compute_magic = input.tag.get_property("COMPUTE_MAGIC", config.compute_magic); - + config.postproc = input.tag.get_property("POSTPROC", config.postproc); + config.show_box = input.tag.get_property("SHOW_BOX", config.show_box); config.fix_min_r = input.tag.get_property("FIX_MIN_R", config.fix_min_r); config.fix_min_g = input.tag.get_property("FIX_MIN_G", config.fix_min_g); config.fix_min_b = input.tag.get_property("FIX_MIN_B", config.fix_min_b); config.fix_light = input.tag.get_property("FIX_LIGHT", config.fix_light); config.fix_gamma_g = input.tag.get_property("FIX_GAMMA_G", config.fix_gamma_g); config.fix_gamma_b = input.tag.get_property("FIX_GAMMA_B", config.fix_gamma_b); + config.fix_coef1 = input.tag.get_property("FIX_COEF1", config.fix_coef2); + config.fix_coef2 = input.tag.get_property("FIX_COEF2", config.fix_coef2); + config.min_row = input.tag.get_property("MIN_ROW", config.min_row); + config.max_row = input.tag.get_property("MAX_ROW", config.max_row); + config.min_col = input.tag.get_property("MIN_COL", config.min_col); + config.max_col = input.tag.get_property("MAX_COL", config.max_col); } } } +#if defined(C41_FAST_POW) -/* Faster pow() approximation; borrowed from http://www.dctsystems.co.uk/Software/power.html - * Tests on real-world data showed a max error of 4% and avg. error or .1 to .5%, - * while accelerating rendering by a factor of 4. - */ float C41Effect::myLog2(float i) { - float x; - float y; + float x, y; float LogBodge = 0.346607f; - union { float f; int i; } v; - v.f = i; x = v.i; + x = *(int *)&i; x *= 1.0 / (1 << 23); // 1/pow(2,23); x = x - 127; @@ -479,8 +534,7 @@ float C41Effect::myPow2(float i) x = i + 127 - y; x *= (1 << 23); - union { float f; int i; } v; - v.i = (int)x; x = v.f; + *(int*)&x = (int)x; return x; } @@ -489,129 +543,313 @@ float C41Effect::myPow(float a, float b) return myPow2(b * myLog2(a)); } +#endif -int C41Effect::process_buffer(VFrame *vframe, - int64_t start_position, - double frame_rate) +int C41Effect::process_realtime(VFrame *input, VFrame *output) { load_configuration(); - VFrame *frame = vframe; - read_frame(frame, 0, start_position, frame_rate, 0); - - int frame_w = frame->get_w(); - int frame_h = frame->get_h(); - int color_model = frame->get_color_model(); - int active_model = BC_CModels::has_alpha(color_model) ? - BC_RGBA_FLOAT : BC_RGB_FLOAT; - int components = active_model == BC_RGBA_FLOAT ? 4 : 3; - - if( color_model != active_model ) { - new_temp(frame_w, frame_h, active_model); - frame = get_temp(); - frame->transfer_from(vframe); + + int frame_w = input->get_w(), frame_h = input->get_h(); + int input_model = input->get_color_model(); + int has_alpha = BC_CModels::has_alpha(input_model); + int color_model = has_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT; + + if( input_model != color_model ) { + if( frame && + ( frame->get_w() != frame_w || frame->get_h() != frame_h || + frame->get_color_model() != color_model ) ) { + delete frame; frame = 0; + } + if( !frame ) + frame = new VFrame(frame_w, frame_h, color_model); + frame->transfer_from(input); + } + else { + delete frame; + frame = input; } - if(config.compute_magic) { - // Box blur! - VFrame* tmp_frame = new VFrame(*frame); - VFrame* blurry_frame = new VFrame(*frame); + pix_max = BC_CModels::calculate_max(color_model); + pix_len = BC_CModels::components(color_model); - float** rows = (float**)frame->get_rows(); - float** tmp_rows = (float**)tmp_frame->get_rows(); - float** blurry_rows = (float**)blurry_frame->get_rows(); - for(int i = 0; i < frame_h; i++) - for(int j = 0; j < (components*frame_w); j++) - blurry_rows[i][j] = rows[i][j]; + min_row = config.min_row; bclamp(min_row, 0,frame_h); + max_row = config.max_row; bclamp(max_row, 0,frame_h); + min_col = config.min_col; bclamp(min_col, 0,frame_w); + max_col = config.max_col; bclamp(max_col, 0,frame_w); + + if( config.compute_magic ) { + // Convert frame to RGB for magic computing + if( tmp_frame && + (tmp_frame->get_w() != frame_w || tmp_frame->get_h() != frame_h) ) { + delete tmp_frame; tmp_frame = 0; + } + if( !tmp_frame ) + tmp_frame = new VFrame(frame_w, frame_h, BC_RGB_FLOAT); + if( blurry_frame && + (blurry_frame->get_w() != frame_w || blurry_frame->get_h() != frame_h) ) { + delete blurry_frame; blurry_frame = 0; + } + if( !blurry_frame ) + blurry_frame = new VFrame(frame_w, frame_h, BC_RGB_FLOAT); + + float **rows = (float **)frame->get_rows(); + float **tmp_rows = (float **)tmp_frame->get_rows(); + float **blurry_rows = (float **)blurry_frame->get_rows(); + + for( int i=0; i=0; row+=pix_len ) { + *tmp++ = fix_exepts(row[0]); + *tmp++ = fix_exepts(row[1]); + *tmp++ = fix_exepts(row[2]); + } + } - int boxw = 5, boxh = 5; // 10 passes of Box blur should be good - int pass, x, y, y_up, y_down, x_right, x_left; - float component; - for(pass=0; pass<10; pass++) { - for(y = 0; y < frame_h; y++) - for(x = 0; x < (components * frame_w); x++) - tmp_rows[y][x] = blurry_rows[y][x]; - for(y = 0; y < frame_h; y++) { - y_up = (y - boxh < 0)? 0 : y - boxh; - y_down = (y + boxh >= frame_h)? frame_h - 1 : y + boxh; - for(x = 0; x < (components*frame_w); x++) { - x_left = (x-(components*boxw) < 0)? 0 : x-(components*boxw); - x_right = (x+(components*boxw) >= (components*frame_w)) ? - (components*frame_w)-1 : x+(components*boxw); - component = (tmp_rows[y_down][x_right] - +tmp_rows[y_up][x_left] - +tmp_rows[y_up][x_right] - +tmp_rows[y_down][x_right])/4; - blurry_rows[y][x] = component; + int dx = 5, dy = 5, y_up, y_dn, x_rt, x_lt; + float **src = tmp_rows, **tgt = blurry_rows; + for( int pass = 0; pass < 10; pass++ ) { + for( int y = 0; y < frame_h; y++ ) { + if( (y_up=y-dy) < 0 ) y_up = 0; + if( (y_dn=y+dy) >= frame_h ) y_dn = frame_h-1; + float *up = src[y_up], *dn = src[y_dn], *row = tgt[y]; + for( int x = 0; x < frame_w; ++x ) { + if( (x_lt=x-dx) < 0 ) x_lt = 0; + if( (x_rt=x+dx) >= frame_w ) x_lt = frame_w-1; + float *dn_l = dn + 3*x_lt, *dn_r = dn + 3*x_rt; + float *up_l = up + 3*x_lt, *up_r = up + 3*x_rt; + row[0] = (dn_l[0] + dn_r[0] + up_l[0] + up_r[0]) / 4; + row[1] = (dn_l[1] + dn_r[1] + up_l[1] + up_r[1]) / 4; + row[2] = (dn_l[2] + dn_r[2] + up_l[2] + up_r[2]) / 4; + row += 3; } } + float **rows = src; src = tgt; tgt = rows; + } + + // Shave image: cut off border areas where min max difference + // is less than C41_SHAVE_TOLERANCE, starting/ending at C41_SHAVE_MARGIN + + shave_min_row = shave_min_col = 0; + shave_max_col = frame_w; + shave_max_row = frame_h; + int min_w = frame_w * C41_SHAVE_MARGIN; + int max_w = frame_w * (1-C41_SHAVE_MARGIN); + int min_h = frame_h * C41_SHAVE_MARGIN; + int max_h = frame_h * (1-C41_SHAVE_MARGIN); + + float yv_min[frame_h], yv_max[frame_h]; + for( int y=0; y yv ) yv_min[y] = yv; + if( yv_max[y] < yv ) yv_max[y] = yv; + } + } + + for( shave_min_row = min_h; shave_min_row < max_h; shave_min_row++ ) + if( yv_max[shave_min_row] - yv_min[shave_min_row] > C41_SHAVE_TOLERANCE ) + break; + for( shave_max_row = max_h - 1; shave_max_row > shave_min_row; shave_max_row-- ) + if( yv_max[shave_max_row] - yv_min[shave_max_row] > C41_SHAVE_TOLERANCE ) + break; + shave_max_row++; + + float xv_min[frame_w], xv_max[frame_w]; + for( int x=0; x xv ) xv_min[x] = xv; + if( xv_max[x] < xv ) xv_max[x] = xv; + } + } + + for( shave_min_col = min_w; shave_min_col < max_w; shave_min_col++ ) + if( xv_max[shave_min_col] - xv_min[shave_min_col] > C41_SHAVE_TOLERANCE ) + break; + for( shave_max_col = max_w - 1; shave_max_col > shave_min_col; shave_max_col-- ) + if( xv_max[shave_max_col] - xv_min[shave_max_col] > C41_SHAVE_TOLERANCE ) + break; + shave_max_col++; + // Compute magic negfix values float minima_r = 50., minima_g = 50., minima_b = 50.; - float maxima_r = 0., maxima_g = 0., maxima_b = 0.; - - // Shave the image in order to avoid black borders - // Tolerance default: 5%, i.e. 0.05 -#define TOLERANCE 0.20 -#define SKIP_ROW if (i < (TOLERANCE * frame_h) || i > ((1-TOLERANCE)*frame_h)) continue -#define SKIP_COL if (j < (TOLERANCE * frame_w) || j > ((1-TOLERANCE)*frame_w)) continue -for(int i = 0; i < frame_h; i++) - { - SKIP_ROW; - float *row = (float*)blurry_frame->get_rows()[i]; - for(int j = 0; j < frame_w; j++, row += components) { - SKIP_COL; - if(row[0] < minima_r) minima_r = row[0]; - if(row[0] > maxima_r) maxima_r = row[0]; - - if(row[1] < minima_g) minima_g = row[1]; - if(row[1] > maxima_g) maxima_g = row[1]; - - if(row[2] < minima_b) minima_b = row[2]; - if(row[2] > maxima_b) maxima_b = row[2]; - } + float maxima_r = 0., maxima_g = 0., maxima_b = 0.; + + // Check if config_parameters are usable + if( config.min_col >= config.max_col || config.min_row >= config.max_row ) { + min_col = shave_min_col; + max_col = shave_max_col; + min_row = shave_min_row; + max_row = shave_max_row; } - // Delete the VFrames we used for blurring - delete tmp_frame; - delete blurry_frame; - - if( minima_r < 1e-3) minima_r = 1e-3; - if( minima_g < 1e-3) minima_g = 1e-3; - if( minima_b < 1e-3) minima_b = 1e-3; - values.min_r = minima_r; - values.min_g = minima_g; - values.min_b = minima_b; - values.light = (minima_r / maxima_r) * 0.95; - values.gamma_g = fabs(maxima_g - minima_g) < 1e-3 ? 1. : - logf(maxima_r / minima_r) / logf(maxima_g / minima_g); - values.gamma_b = fabs(maxima_b - minima_b) < 1e-3 ? 1. : - logf(maxima_r / minima_r) / logf(maxima_b / minima_b); + for( int i = min_row; i < max_row; i++ ) { + float *row = blurry_rows[i] + 3 * min_col; + for( int j = min_col; j < max_col; j++, row+=3 ) { + if( row[0] < minima_r ) minima_r = row[0]; + if( row[0] > maxima_r ) maxima_r = row[0]; + if( row[1] < minima_g ) minima_g = row[1]; + if( row[1] > maxima_g ) maxima_g = row[1]; + if( row[2] < minima_b ) minima_b = row[2]; + if( row[2] > maxima_b ) maxima_b = row[2]; + } + } + if( minima_r < 1e-6 ) minima_r = 1e-6; + if( minima_g < 1e-6 ) minima_g = 1e-6; + if( minima_b < 1e-6 ) minima_b = 1e-6; + values.min_r = minima_r; values.max_r = maxima_r; + values.min_g = minima_g; values.max_g = maxima_g; + values.min_b = minima_b; values.max_b = maxima_b; + values.light = maxima_r < 1e-6 ? 1.0 : minima_r / maxima_r; + values.gamma_g = logf(maxima_r / minima_r) / logf(maxima_g / minima_g); + values.gamma_b = logf(maxima_r / minima_r) / logf(maxima_b / minima_b); + values.shave_min_col = shave_min_col; + values.shave_max_col = shave_max_col; + values.shave_min_row = shave_min_row; + values.shave_max_row = shave_max_row; + values.coef1 = -1; + values.coef2 = -1; // Update GUI send_render_gui(&values); } // Apply the transformation - if(config.active) { - // Get the values from the config instead of the computed ones - for(int i = 0; i < frame_h; i++) { + if( config.active ) { + for( int i = 0; i < frame_h; i++ ) { float *row = (float*)frame->get_rows()[i]; - for(int j = 0; j < frame_w; j++, row += components) { - row[0] = row[0] < 1e-3 ? 1.f : - (config.fix_min_r / row[0]) - config.fix_light; - row[1] = row[1] < 1e-3 ? 1.f : - myPow((config.fix_min_g / row[1]), config.fix_gamma_g) - config.fix_light; - row[2] = row[2] < 1e-3 ? 1.f : - myPow((config.fix_min_b / row[2]), config.fix_gamma_b) - config.fix_light; + for( int j = 0; j < frame_w; j++, row += pix_len ) { + float r0 = row[0] >= 1e-6 ? row[0] : 1e-6; + float v0 = config.fix_min_r / r0 - config.fix_light; + row[0] = normalize_pixel(v0 - config.fix_light); + float r1 = row[1] >= 1e-6 ? row[1] : 1e-6; + float v1 = POWF((config.fix_min_g / r1), config.fix_gamma_g); + row[1] = normalize_pixel(v1 - config.fix_light); + float r2 = row[2] >= 1e-6 ? row[2] : 1e-6; + float v2 = POWF((config.fix_min_b / r2), config.fix_gamma_b); + row[2] = normalize_pixel(v2 - config.fix_light); + } + } + if( config.compute_magic && !config.postproc ) { + float minima_r = 50., minima_g = 50., minima_b = 50.; + float maxima_r = 0., maxima_g = 0., maxima_b = 0.; + + for( int i = min_row; i < max_row; i++ ) { + float *row = (float*)frame->get_rows()[i]; + row += 3 * shave_min_col; + for( int j = min_col; j < max_col; j++, row += 3 ) { + if( row[0] < minima_r ) minima_r = row[0]; + if( row[0] > maxima_r ) maxima_r = row[0]; + + if( row[1] < minima_g ) minima_g = row[1]; + if( row[1] > maxima_g ) maxima_g = row[1]; + + if( row[2] < minima_b ) minima_b = row[2]; + if( row[2] > maxima_b ) maxima_b = row[2]; + } + } + + // Calculate postprocessing coeficents + values.coef2 = minima_r; + if( minima_g < values.coef2 ) + values.coef2 = minima_g; + if( minima_b < values.coef2 ) + values.coef2 = minima_b; + values.coef1 = maxima_r; + if( maxima_g > values.coef1 ) + values.coef1 = maxima_g; + if( maxima_b > values.coef1 ) + values.coef1 = maxima_b; + // Try not to overflow RGB601 + // (235 - 16) / 256 * 0.9 + float den = values.coef1 - values.coef2; + if( fabs(den) < 1e-6 ) + den = den < 0 ? -1e-6 : 1e-6; + values.coef1 = 0.770 / den; + values.coef2 = 0.065 - values.coef2 * values.coef1; + send_render_gui(&values); + } + } + + if( config.show_box ) { + float **rows = (float **)frame->get_rows(); + if( min_row < max_row - 1 ) { + float *row1 = (float *)rows[min_row]; + float *row2 = (float *)rows[max_row - 1]; + + for( int i = 0; i < frame_w; i++ ) { + for( int j = 0; j < 3; j++ ) { + row1[j] = pix_max - row1[j]; + row2[j] = pix_max - row2[j]; + } + if( has_alpha ) { + row1[3] = pix_max; + row2[3] = pix_max; + } + row1 += pix_len; + row2 += pix_len; + } + } + + if( min_col < max_col - 1 ) { + int pix1 = pix_len * min_col; + int pix2 = pix_len * (max_col - 1); + + for( int i = 0; i < frame_h; i++ ) { + float *row1 = rows[i] + pix1; + float *row2 = rows[i] + pix2; + + for( int j = 0; j < 3; j++ ) { + row1[j] = pix_max - row1[j]; + row2[j] = pix_max - row2[j]; + } + if( has_alpha ) { + row1[3] = pix_max; + row2[3] = pix_max; + } } } } - if( vframe != frame ) - vframe->transfer_from(frame); + if( frame != output ) + output->transfer_from(frame); + if( frame == input ) + frame = 0; return 0; } +float C41Effect::normalize_pixel(float ival) +{ + float val = fix_exepts(ival); + + if( config.postproc ) + val = config.fix_coef1 * val + config.fix_coef2; + + CLAMP(val, 0., pix_max); + return val; +} + +float C41Effect::fix_exepts(float ival) +{ + switch( fpclassify(ival) ) { + case FP_NAN: + case FP_SUBNORMAL: return 0; + case FP_INFINITE: return ival < 0 ? 0 : pix_max; + } + return ival; +} + diff --git a/cinelerra-5.1/plugins/C41/c41.h b/cinelerra-5.1/plugins/C41/c41.h new file mode 100644 index 00000000..e2ec0278 --- /dev/null +++ b/cinelerra-5.1/plugins/C41/c41.h @@ -0,0 +1,195 @@ +#ifndef __C41_H__ +#define __C41_H__ + +#include "guicast.h" +#include "pluginvclient.h" +#include "vframe.inc" + +// C41_FAST_POW increases processing speed more than 10 times +// Depending on gcc version, used optimizations and cpu C41_FAST_POW may not work +// With gcc versiion >= 4.4 it seems safe to enable C41_FAST_POW +// Test some samples after you have enabled it +#define C41_FAST_POW + +#ifdef C41_FAST_POW +#define POWF myPow +#else +#define POWF powf +#endif + +// Shave the image in order to avoid black borders +// The min max pixel value difference must be at least 0.05 +#define C41_SHAVE_TOLERANCE 0.05 +#define C41_SHAVE_MARGIN 0.1 + +#include +#include + +class C41Effect; +class C41Window; +class C41Config; +class C41Enable; +class C41TextBox; +class C41Button; +class C41BoxButton; +class C41Slider; + +struct magic +{ + float min_r, max_r; + float min_g, max_g; + float min_b, max_b; + float light; + float gamma_g, gamma_b; + float coef1, coef2; + int shave_min_row, shave_max_row; + int shave_min_col, shave_max_col; +}; + +class C41Config +{ +public: + C41Config(); + + void copy_from(C41Config &src); + int equivalent(C41Config &src); + void interpolate(C41Config &prev, C41Config &next, + long prev_frame, long next_frame, long current_frame); + + int active, compute_magic; + int postproc, show_box; + float fix_min_r, fix_min_g, fix_min_b; + float fix_light, fix_gamma_g, fix_gamma_b; + float fix_coef1, fix_coef2; + int min_col, max_col, min_row, max_row; + int window_w, window_h; +}; + +class C41Enable : public BC_CheckBox +{ +public: + C41Enable(C41Effect *plugin, int *output, int x, int y, const char *text); + int handle_event(); + + C41Effect *plugin; + int *output; +}; + +class C41TextBox : public BC_TextBox +{ +public: + C41TextBox(C41Effect *plugin, float *value, int x, int y); + int handle_event(); + + C41Effect *plugin; + float *boxValue; +}; + +class C41Button : public BC_GenericButton +{ +public: + C41Button(C41Effect *plugin, C41Window *window, int x, int y); + int handle_event(); + + C41Effect *plugin; + C41Window *window; +}; + +class C41BoxButton : public BC_GenericButton +{ +public: + C41BoxButton(C41Effect *plugin, C41Window *window, int x, int y); + int handle_event(); + + C41Effect *plugin; + C41Window *window; +}; + +class C41Slider : public BC_ISlider +{ +public: + C41Slider(C41Effect *plugin, int *output, int x, int y, int is_row); + + int handle_event(); + int update(int v); + + C41Effect *plugin; + int is_row, max; + int *output; +}; + +class C41Window : public PluginClientWindow +{ +public: + C41Window(C41Effect *client); + + void update(); + void update_magic(); + + C41Enable *active; + C41Enable *compute_magic; + C41Enable *postproc; + C41Enable *show_box; + BC_Title *min_r; + BC_Title *min_g; + BC_Title *min_b; + BC_Title *light; + BC_Title *gamma_g; + BC_Title *gamma_b; + BC_Title *coef1; + BC_Title *coef2; + BC_Title *box_col_min; + BC_Title *box_col_max; + BC_Title *box_row_min; + BC_Title *box_row_max; + C41TextBox *fix_min_r; + C41TextBox *fix_min_g; + C41TextBox *fix_min_b; + C41TextBox *fix_light; + C41TextBox *fix_gamma_g; + C41TextBox *fix_gamma_b; + C41TextBox *fix_coef1; + C41TextBox *fix_coef2; + C41Button *lock; + C41BoxButton *boxlock; + C41Slider *min_row; + C41Slider *max_row; + C41Slider *min_col; + C41Slider *max_col; + + int slider_max_col; + int slider_max_row; +}; + +class C41Effect : public PluginVClient +{ +public: + C41Effect(PluginServer *server); + ~C41Effect(); + + PLUGIN_CLASS_MEMBERS(C41Config); + int is_realtime(); + int is_synthesis(); + + int process_realtime(VFrame *input_ptr, VFrame *output_ptr); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + void render_gui(void* data); + float fix_exepts(float ival); + float normalize_pixel(float ival); +#if defined(C41_FAST_POW) + float myLog2(float i) __attribute__ ((optimize(0))); + float myPow2(float i) __attribute__ ((optimize(0))); + float myPow(float a, float b); +#endif + VFrame *frame, *tmp_frame, *blurry_frame; + struct magic values; + + int shave_min_row, shave_max_row, shave_min_col, shave_max_col; + int min_col, max_col, min_row, max_row; + float pix_max; + int pix_len; +}; + + +#endif diff --git a/cinelerra-5.1/plugins/crikey/crikeywindow.C b/cinelerra-5.1/plugins/crikey/crikeywindow.C index 3f72f3de..e774bae8 100644 --- a/cinelerra-5.1/plugins/crikey/crikeywindow.C +++ b/cinelerra-5.1/plugins/crikey/crikeywindow.C @@ -29,6 +29,7 @@ #include "edl.h" #include "edlsession.h" #include "language.h" +#include "mainerror.h" #include "mwindow.h" #include "plugin.h" #include "pluginserver.h" @@ -171,8 +172,8 @@ CriKeyWindow::CriKeyWindow(CriKey *plugin) this->plugin = plugin; this->color_button = 0; this->color_picker = 0; - this->title_x = 0; this->point_x = 0; - this->title_y = 0; this->point_y = 0; + this->title_x = 0; this->point_x = 0; + this->title_y = 0; this->point_y = 0; this->new_point = 0; this->del_point = 0; this->point_up = 0; this->point_dn = 0; this->drag = 0; this->dragging = 0; @@ -225,7 +226,13 @@ void CriKeyWindow::create_objects() x1 += del_point->get_w() + margin; add_subwindow(point_dn = new CriKeyPointDn(this, x1, y)); y += point_y->get_h() + margin + 10; + add_subwindow(drag = new CriKeyDrag(this, x, y)); + if( plugin->config.drag ) { + if( !grab(plugin->server->mwindow->cwindow->gui) ) + eprintf("drag enabled, but compositor already grabbed\n"); + } + x1 = x + drag->get_w() + margin + 20; add_subwindow(cur_point = new CriKeyCurPoint(this, plugin, x1, y+3)); cur_point->update(plugin->config.selected); @@ -233,9 +240,6 @@ void CriKeyWindow::create_objects() add_subwindow(points = new CriKeyPoints(this, plugin, x, y)); points->update(plugin->config.selected); - if( plugin->config.drag ) - grab(plugin->server->mwindow->cwindow->gui); - show_window(1); } @@ -359,7 +363,7 @@ int CriKeyWindow::grab_event(XEvent *event) void CriKeyWindow::done_event(int result) { - ungrab(client->server->mwindow->cwindow->gui); + ungrab(client->server->mwindow->cwindow->gui); if( color_picker ) color_picker->close_window(); } @@ -582,15 +586,19 @@ CriKeyDrag::CriKeyDrag(CriKeyWindow *gui, int x, int y) } int CriKeyDrag::handle_event() { - int value = get_value(); - gui->plugin->config.drag = value; CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui; - if( value ) - gui->grab(cwindow_gui); - else - gui->ungrab(cwindow_gui); - gui->plugin->send_configure_change(); - return 1; + int value = get_value(); + if( value ) { + if( !gui->grab(cwindow_gui) ) { + update(value = 0); + flicker(10,50); + } + } + else + gui->ungrab(cwindow_gui); + gui->plugin->config.drag = value; + gui->plugin->send_configure_change(); + return 1; } CriKeyNewPoint::CriKeyNewPoint(CriKeyWindow *gui, CriKey *plugin, int x, int y) diff --git a/cinelerra-5.1/plugins/titler/titlerwindow.C b/cinelerra-5.1/plugins/titler/titlerwindow.C index f52d3f21..9bd8cfe7 100644 --- a/cinelerra-5.1/plugins/titler/titlerwindow.C +++ b/cinelerra-5.1/plugins/titler/titlerwindow.C @@ -32,7 +32,9 @@ #include "edlsession.h" #include "keys.h" #include "language.h" +#include "mainerror.h" #include "mwindow.h" +#include "mwindowgui.h" #include "plugin.h" #include "pluginserver.h" #include "theme.h" @@ -255,10 +257,13 @@ void TitleWindow::create_objects() int w1 = italic->get_w(); add_tool(bold = new TitleBold(client, this, x, y + 50)); if( bold->get_w() > w1 ) w1 = bold->get_w(); + add_tool(drag = new TitleDrag(client, this, x, y + 80)); if( drag->get_w() > w1 ) w1 = drag->get_w(); - if( client->config.drag ) - grab(client->server->mwindow->cwindow->gui); + if( client->config.drag ) { + if( !grab(client->server->mwindow->cwindow->gui) ) + eprintf("drag enabled, but compositor already grabbed\n"); + } x += w1 + margin; add_tool(justify_title = new BC_Title(x, y, _("Justify:"))); @@ -1086,11 +1091,11 @@ int TitleText::handle_event() if( text_len >= avail ) { // back off last utf8 char char text[2*sizeof(client->config.wtext)]; strcpy(text, get_text()); - text_len = avail; - while( text_len > 0 && (text[text_len-1] & 0xc0) == 0x80 ) - text[--text_len] = 0; - if( text_len > 0 ) - text[--text_len] = 0; + text_len = avail; + while( text_len > 0 && (text[text_len-1] & 0xc0) == 0x80 ) + text[--text_len] = 0; + if( text_len > 0 ) + text[--text_len] = 0; update(text); } int len = sizeof(client->config.wtext) / sizeof(wchar_t); @@ -1379,11 +1384,16 @@ TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y) int TitleDrag::handle_event() { int value = get_value(); - client->config.drag = value; - if( value ) - window->grab(client->server->mwindow->cwindow->gui); + CWindowGUI *cwindow_gui = client->server->mwindow->cwindow->gui; + if( value ) { + if( !window->grab(cwindow_gui) ) { + update(value = 0); + flicker(10,50); + } + } else - window->ungrab(client->server->mwindow->cwindow->gui); + window->ungrab(cwindow_gui); + client->config.drag = value; client->send_configure_change(); return 1; } @@ -1665,13 +1675,12 @@ void TitlePngPopup::handle_done_event(int result) BC_Window *TitlePngPopup::new_gui() { - BC_DisplayInfo display_info; - int x = display_info.get_abs_cursor_x(); - int y = display_info.get_abs_cursor_y(); + MWindow *mwindow = client->server->mwindow; + int x, y; mwindow->gui->get_abs_cursor_xy(x, y); - BC_Window *gui = new BrowseButtonWindow(client->server->mwindow->theme, + BC_Window *gui = new BrowseButtonWindow(mwindow->theme, x-25, y-100, window, "", _("Png file"), _("Png path"), 0); - gui->create_objects(); + gui->create_objects(); return gui; } -- 2.26.2