static void *dt_control_work_res(void *ptr) { #ifdef _OPENMP // need to do this in every thread omp_set_num_threads(darktable.num_openmp_threads); #endif worker_thread_parameters_t *params = (worker_thread_parameters_t *)ptr; dt_control_t *s = params->self; threadid = params->threadid; free(params); int32_t threadid = dt_control_get_threadid_res(); while(dt_control_running()) { // dt_print(DT_DEBUG_CONTROL, "[control_work] %d\n", threadid); if(dt_control_run_job_res(s, threadid) < 0) { // wait for a new job. int old; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); dt_pthread_mutex_lock(&s->cond_mutex); dt_pthread_cond_wait(&s->cond, &s->cond_mutex); dt_pthread_mutex_unlock(&s->cond_mutex); pthread_setcancelstate(old, NULL); } } return NULL; }
static gboolean expose (GtkWidget *da, GdkEventExpose *event, gpointer user_data) { dt_control_expose(NULL); gdk_draw_drawable(da->window, da->style->fg_gc[GTK_WIDGET_STATE(da)], darktable.gui->pixmap, // Only copy the area that was exposed. event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); if(darktable.lib->proxy.colorpicker.module) { darktable.lib->proxy.colorpicker.update_panel( darktable.lib->proxy.colorpicker.module); darktable.lib->proxy.colorpicker.update_samples( darktable.lib->proxy.colorpicker.module); } // test quit cond (thread safe, 2nd pass) if(!dt_control_running()) { dt_cleanup(); gtk_main_quit(); } return TRUE; }
static gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { if(!dt_control_running()) return FALSE; update((dt_lib_module_t*)user_data, TRUE); return FALSE; }
void dt_control_signal_raise(const dt_control_signal_t *ctlsig, dt_signal_t signal, ...) { // ignore all signals on shutdown if(!dt_control_running()) return; dt_signal_description *signal_description = &_signal_description[signal]; _signal_param_t *params = (_signal_param_t *)malloc(sizeof(_signal_param_t)); if(!params) return; GValue *instance_and_params = calloc(1 + signal_description->n_params, sizeof(GValue)); if(!instance_and_params) { free(params); return; } // 0th element has to be the instance to call g_value_init(instance_and_params, _signal_type); g_value_set_object(instance_and_params, ctlsig->sink); // the rest of instance_and_params will be the params for the callback va_list extra_args; va_start(extra_args, signal); for(int i = 1; i <= signal_description->n_params; i++) { GType type = signal_description->param_types[i-1]; g_value_init(&instance_and_params[i], type); switch(type) { case G_TYPE_UINT: g_value_set_uint(&instance_and_params[i], va_arg(extra_args, guint)); break; case G_TYPE_STRING: g_value_set_string(&instance_and_params[i], va_arg(extra_args, const char *)); break; case G_TYPE_POINTER: g_value_set_pointer(&instance_and_params[i], va_arg(extra_args, void *)); break; default: fprintf(stderr, "error: unsupported parameter type `%s' for signal `%s'\n", g_type_name(type), signal_description->name); va_end(extra_args); for(int j = 0; j <= i; j++) g_value_unset(&instance_and_params[j]); free(instance_and_params); free(params); return; } } va_end(extra_args); params->instance_and_params = instance_and_params; params->signal_id = g_signal_lookup(_signal_description[signal].name, _signal_type); params->n_params = signal_description->n_params; g_main_context_invoke(NULL, _signal_raise, params); }
void gui_reset (dt_lib_module_t *self) { // make sure we don't do anything useless: if(!dt_control_running()) return; dt_lib_export_t *d = (dt_lib_export_t *)self->data; gtk_spin_button_set_value(d->width, dt_conf_get_int("plugins/lighttable/export/width")); gtk_spin_button_set_value(d->height, dt_conf_get_int("plugins/lighttable/export/height")); // Set storage gchar *storage_name = dt_conf_get_string("plugins/lighttable/export/storage_name"); int storage_index = dt_imageio_get_index_of_storage(dt_imageio_get_storage_by_name(storage_name)); g_free(storage_name); gtk_combo_box_set_active(d->storage, storage_index); gtk_combo_box_set_active(d->intent, (int)dt_conf_get_int("plugins/lighttable/export/iccintent") + 1); // iccprofile int iccfound = 0; gchar *iccprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile"); if(iccprofile) { GList *prof = d->profiles; while(prof) { dt_lib_export_profile_t *pp = (dt_lib_export_profile_t *)prof->data; if(!strcmp(pp->filename, iccprofile)) { gtk_combo_box_set_active(d->profile, pp->pos); iccfound = 1; } if(iccfound) break; prof = g_list_next(prof); } g_free(iccprofile); } // style // set it to none if the var is not set or the style doesn't exist anymore gboolean rc = FALSE; gchar *style = dt_conf_get_string("plugins/lighttable/export/style"); if (style != NULL) { rc = _combo_box_set_active_text(d->style, style); if (rc == FALSE) gtk_combo_box_set_active(d->style, 0); g_free(style); } else gtk_combo_box_set_active(d->style, 0); if(!iccfound) gtk_combo_box_set_active(d->profile, 0); dt_imageio_module_format_t *mformat = dt_imageio_get_format(); if(mformat) mformat->gui_reset(mformat); dt_imageio_module_storage_t *mstorage = dt_imageio_get_storage(); if(mstorage) mstorage->gui_reset(mstorage); }
void dt_control_queue_redraw_widget(GtkWidget *widget) { if(dt_control_running()) { gboolean i_own_lock = dt_control_gdk_lock(); gtk_widget_queue_draw(widget); if (i_own_lock) dt_control_gdk_unlock(); } }
static void *dt_control_worker_kicker(void *ptr) { dt_control_t *control = (dt_control_t *)ptr; while(dt_control_running()) { sleep(2); dt_pthread_mutex_lock(&control->cond_mutex); pthread_cond_broadcast(&control->cond); dt_pthread_mutex_unlock(&control->cond_mutex); } return NULL; }
void dt_control_signal_raise(const dt_control_signal_t *ctlsig, dt_signal_t signal,...) { va_list extra_args; // ignore all signals on shutdown, especially don't lock anything.. if(!dt_control_running()) return; va_start(extra_args,signal); gboolean i_own_lock = dt_control_gdk_lock(); //g_signal_emit_by_name(G_OBJECT(ctlsig->sink), _signal_description[signal].name); g_signal_emit_valist(G_OBJECT(ctlsig->sink),g_signal_lookup(_signal_description[signal].name,_signal_type), 0,extra_args); va_end(extra_args); if (i_own_lock) dt_control_gdk_unlock(); }
void *dt_control_work(void *ptr) { #ifdef _OPENMP // need to do this in every thread omp_set_num_threads(darktable.num_openmp_threads); #endif dt_control_t *s = (dt_control_t *)ptr; // int32_t threadid = dt_control_get_threadid(); while(dt_control_running()) { // dt_print(DT_DEBUG_CONTROL, "[control_work] %d\n", threadid); if(dt_control_run_job(s) < 0) { // wait for a new job. dt_pthread_mutex_lock(&s->cond_mutex); dt_pthread_cond_wait(&s->cond, &s->cond_mutex); dt_pthread_mutex_unlock(&s->cond_mutex); } } return NULL; }
void gui_reset (dt_lib_module_t *self) { // make sure we don't do anything useless: if(!dt_control_running()) return; dt_lib_export_t *d = (dt_lib_export_t *)self->data; gtk_spin_button_set_value(d->width, dt_conf_get_int("plugins/lighttable/export/width")); gtk_spin_button_set_value(d->height, dt_conf_get_int("plugins/lighttable/export/height")); // Set storage int k = dt_conf_get_int ("plugins/lighttable/export/storage"); gtk_combo_box_set_active(d->storage, k); gtk_combo_box_set_active(d->intent, (int)dt_conf_get_int("plugins/lighttable/export/iccintent") + 1); int iccfound = 0; gchar *iccprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile"); if(iccprofile) { GList *prof = d->profiles; while(prof) { dt_lib_export_profile_t *pp = (dt_lib_export_profile_t *)prof->data; if(!strcmp(pp->filename, iccprofile)) { gtk_combo_box_set_active(d->profile, pp->pos); iccfound = 1; } if(iccfound) break; prof = g_list_next(prof); } g_free(iccprofile); } if(!iccfound) gtk_combo_box_set_active(d->profile, 0); dt_imageio_module_format_t *mformat = dt_imageio_get_format(); if(mformat) mformat->gui_reset(mformat); dt_imageio_module_storage_t *mstorage = dt_imageio_get_storage(); if(mstorage) mstorage->gui_reset(mstorage); }
static void *dt_control_work(void *ptr) { #ifdef _OPENMP // need to do this in every thread omp_set_num_threads(darktable.num_openmp_threads); #endif worker_thread_parameters_t *params = (worker_thread_parameters_t *)ptr; dt_control_t *control = params->self; threadid = params->threadid; free(params); // int32_t threadid = dt_control_get_threadid(); while(dt_control_running()) { // dt_print(DT_DEBUG_CONTROL, "[control_work] %d\n", threadid); if(dt_control_run_job(control) < 0) { // wait for a new job. dt_pthread_mutex_lock(&control->cond_mutex); dt_pthread_cond_wait(&control->cond, &control->cond_mutex); dt_pthread_mutex_unlock(&control->cond_mutex); } } return NULL; }
// Get the display ICC profile of the monitor associated with the widget. // For X display, uses the ICC profile specifications version 0.2 from // http://burtonini.com/blog/computers/xicc // Based on code from Gimp's modules/cdisplay_lcms.c void dt_ctl_set_display_profile() { if(!dt_control_running()) return; // make sure that no one gets a broken profile // FIXME: benchmark if the try is really needed when moving/resizing the window. Maybe we can just lock it and block if(pthread_rwlock_trywrlock(&darktable.control->xprofile_lock)) return; // we are already updating the profile. Or someone is reading right now. Too bad we can't distinguish that. Whatever ... GtkWidget *widget = dt_ui_center(darktable.gui->ui); guint8 *buffer = NULL; gint buffer_size = 0; gchar *profile_source = NULL; #if defined GDK_WINDOWING_X11 // we will use the xatom no matter what configured when compiled without colord gboolean use_xatom = TRUE; #if defined USE_COLORDGTK gboolean use_colord = TRUE; gchar *display_profile_source = dt_conf_get_string("ui_last/display_profile_source"); if(display_profile_source) { if(!strcmp(display_profile_source, "xatom")) use_colord = FALSE; else if(!strcmp(display_profile_source, "colord")) use_xatom = FALSE; g_free(display_profile_source); } #endif /* let's have a look at the xatom, just in case ... */ if(use_xatom) { GdkScreen *screen = gtk_widget_get_screen(widget); if ( screen==NULL ) screen = gdk_screen_get_default(); int monitor = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window(widget)); char *atom_name; if (monitor > 0) atom_name = g_strdup_printf("_ICC_PROFILE_%d", monitor); else atom_name = g_strdup("_ICC_PROFILE"); profile_source = g_strdup_printf("xatom %s", atom_name); GdkAtom type = GDK_NONE; gint format = 0; gdk_property_get(gdk_screen_get_root_window(screen), gdk_atom_intern(atom_name, FALSE), GDK_NONE, 0, 64 * 1024 * 1024, FALSE, &type, &format, &buffer_size, &buffer); g_free(atom_name); } #ifdef USE_COLORDGTK /* also try to get the profile from colord. this will set the value asynchronously! */ if(use_colord) { CdWindow *window = cd_window_new(); GtkWidget *center_widget = dt_ui_center(darktable.gui->ui); cd_window_get_profile(window, center_widget, NULL, dt_ctl_get_display_profile_colord_callback, NULL); } #endif #elif defined GDK_WINDOWING_QUARTZ GdkScreen *screen = gtk_widget_get_screen(widget); if ( screen==NULL ) screen = gdk_screen_get_default(); int monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(widget)); CGDirectDisplayID ids[monitor + 1]; uint32_t total_ids; CMProfileRef prof = NULL; if(CGGetOnlineDisplayList(monitor + 1, &ids[0], &total_ids) == kCGErrorSuccess && total_ids == monitor + 1) CMGetProfileByAVID(ids[monitor], &prof); if ( prof!=NULL ) { CFDataRef data; data = CMProfileCopyICCData(NULL, prof); CMCloseProfile(prof); UInt8 *tmp_buffer = (UInt8 *) g_malloc(CFDataGetLength(data)); CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), tmp_buffer); buffer = (guint8 *) tmp_buffer; buffer_size = CFDataGetLength(data); CFRelease(data); } profile_source = g_strdup("osx color profile api"); #elif defined G_OS_WIN32 (void)widget; HDC hdc = GetDC (NULL); if ( hdc!=NULL ) { DWORD len = 0; GetICMProfile (hdc, &len, NULL); gchar *path = g_new (gchar, len); if (GetICMProfile (hdc, &len, path)) { gsize size; g_file_get_contents(path, (gchar**)&buffer, &size, NULL); buffer_size = size; } g_free (path); ReleaseDC (NULL, hdc); } profile_source = g_strdup("windows color profile api"); #endif int profile_changed = buffer_size > 0 && (darktable.control->xprofile_size != buffer_size || memcmp(darktable.control->xprofile_data, buffer, buffer_size) != 0); if(profile_changed) { cmsHPROFILE profile = NULL; char name[512]; // thanks to ufraw for this! g_free(darktable.control->xprofile_data); darktable.control->xprofile_data = buffer; darktable.control->xprofile_size = buffer_size; profile = cmsOpenProfileFromMem(buffer, buffer_size); if(profile) { dt_colorspaces_get_profile_name(profile, "en", "US", name, sizeof(name)); cmsCloseProfile(profile); } dt_print(DT_DEBUG_CONTROL, "[color profile] we got a new screen profile `%s' from the %s (size: %d)\n", *name?name:"(unknown)", profile_source, buffer_size); } pthread_rwlock_unlock(&darktable.control->xprofile_lock); if(profile_changed) dt_control_signal_raise(darktable.signals, DT_SIGNAL_CONTROL_PROFILE_CHANGED); g_free(profile_source); }
int32_t dt_control_indexer_job_run(dt_job_t *job) { // if no indexing was requested, bail out: if(!dt_conf_get_bool("run_similarity_indexer")) return 0; /* * First pass run thru ALL images and collect the ones who needs to update * \TODO in the future lets have a indexer table with ids filed with images * thats need some kind of reindexing.. all mark dirty functions adds image * to this table-- */ // temp memory for uncompressed images: uint8_t *scratchmem = dt_mipmap_cache_alloc_scratchmem(darktable.mipmap_cache); GList *images=NULL; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select images.id,film_rolls.folder||'/'||images.filename,images.histogram,images.lightmap from images,film_rolls where film_rolls.id = images.film_id", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { _control_indexer_img_t *idximg=g_malloc(sizeof( _control_indexer_img_t)); memset(idximg,0,sizeof(_control_indexer_img_t)); idximg->id = sqlite3_column_int(stmt,0); /* first check if image file exists on disk */ const char *filename = (const char *)sqlite3_column_text(stmt, 1); if (filename && !g_file_test(filename, G_FILE_TEST_IS_REGULAR)) idximg->flags |= _INDEXER_IMAGE_FILE_REMOVED; /* check if histogram should be updated */ if (sqlite3_column_bytes(stmt, 2) != sizeof(dt_similarity_histogram_t)) idximg->flags |= _INDEXER_UPDATE_HISTOGRAM; /* check if lightmap should be updated */ if (sqlite3_column_bytes(stmt, 3) != sizeof(dt_similarity_lightmap_t)) idximg->flags |= _INDEXER_UPDATE_LIGHTMAP; /* if image is flagged add to collection */ if (idximg->flags != 0) images = g_list_append(images, idximg); else g_free(idximg); } sqlite3_finalize(stmt); /* * Second pass, run thru collected images thats * need reindexing... */ GList *imgitem = g_list_first(images); if(imgitem) { char message[512]= {0}; double fraction=0; int total = g_list_length(images); guint *jid = NULL; /* background job plate only if more then one image is reindexed */ if (total > 1) { snprintf(message, 512, ngettext ("re-indexing %d image", "re-indexing %d images", total), total ); jid = (guint *)dt_control_backgroundjobs_create(darktable.control, 0, message); } do { // bail out if we're shutting down: if(!dt_control_running()) break; // if indexer was switched off during runtime, respect that as soon as we can: if(!dt_conf_get_bool("run_similarity_indexer")) break; /* get the _control_indexer_img_t pointer */ _control_indexer_img_t *idximg = imgitem->data; /* * Check if image has been delete from disk */ if ((idximg->flags&_INDEXER_IMAGE_FILE_REMOVED)) { /* file does not exist on disk lets delete image reference from database */ //char query[512]={0}; // \TODO dont delete move to an temp table and let user to revalidate /*sprintf(query,"delete from history where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from tagged_images where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from images where id=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL);*/ /* no need to additional work */ continue; } /* * Check if image histogram or lightmap should be updated. * those indexing that involves a image pipe should fall into this */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) || (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { /* get a mipmap of image to analyse */ dt_mipmap_buffer_t buf; dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, idximg->id, DT_MIPMAP_2, DT_MIPMAP_BLOCKING); // pointer owned by the cache or == scratchmem, no need to free this one: uint8_t *buf_decompressed = dt_mipmap_cache_decompress(&buf, scratchmem); if (!(buf.width * buf.height)) continue; /* * Generate similarity histogram data if requested */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) ) { dt_similarity_histogram_t histogram; float bucketscale = (float)DT_SIMILARITY_HISTOGRAM_BUCKETS/(float)0xff; for(int j=0; j<(4*buf.width*buf.height); j+=4) { /* swap rgb and scale to bucket index */ uint8_t rgb[3]; for(int k=0; k<3; k++) rgb[k] = (int)((buf_decompressed[j+2-k]/(float)0xff) * bucketscale); /* distribute rgb into buckets */ for(int k=0; k<3; k++) histogram.rgbl[rgb[k]][k]++; /* distribute lum into buckets */ uint8_t lum = MAX(MAX(rgb[0], rgb[1]), rgb[2]); histogram.rgbl[lum][3]++; } for(int k=0; k<DT_SIMILARITY_HISTOGRAM_BUCKETS; k++) for (int j=0; j<4; j++) histogram.rgbl[k][j] /= (buf.width*buf.height); /* store the histogram data */ dt_similarity_histogram_store(idximg->id, &histogram); } /* * Generate scaledowned similarity lightness map if requested */ if ( (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { dt_similarity_lightmap_t lightmap; memset(&lightmap,0,sizeof(dt_similarity_lightmap_t)); /* * create a pixbuf out of the image for downscaling */ /* first of setup a standard rgb buffer, swap bgr in same routine */ uint8_t *rgbbuf = g_malloc(buf.width*buf.height*3); for(int j=0; j<(buf.width*buf.height); j++) for(int k=0; k<3; k++) rgbbuf[3*j+k] = buf_decompressed[4*j+2-k]; /* then create pixbuf and scale down to lightmap size */ GdkPixbuf *source = gdk_pixbuf_new_from_data(rgbbuf,GDK_COLORSPACE_RGB,FALSE,8,buf.width,buf.height,(buf.width*3),NULL,NULL); GdkPixbuf *scaled = gdk_pixbuf_scale_simple(source,DT_SIMILARITY_LIGHTMAP_SIZE,DT_SIMILARITY_LIGHTMAP_SIZE,GDK_INTERP_HYPER); /* copy scaled data into lightmap */ uint8_t min=0xff,max=0; uint8_t *spixels = gdk_pixbuf_get_pixels(scaled); for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { /* copy rgb */ for(int k=0; k<3; k++) lightmap.pixels[4*j+k] = spixels[3*j+k]; /* average intensity into 4th channel */ lightmap.pixels[4*j+3] = (lightmap.pixels[4*j+0]+ lightmap.pixels[4*j+1]+ lightmap.pixels[4*j+2])/3.0; min = MIN(min, lightmap.pixels[4*j+3]); max = MAX(max, lightmap.pixels[4*j+3]); } /* contrast stretch each channel in lightmap * TODO: do we want this... */ float scale=0; int range = max-min; if(range==0) scale = 1.0; else scale = 0xff/range; for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { for(int k=0; k<4; k++) lightmap.pixels[4*j+k] = (lightmap.pixels[4*j+k]-min)*scale; } /* free some resources */ g_object_unref(scaled); g_object_unref(source); g_free(rgbbuf); /* store the lightmap */ dt_similarity_lightmap_store(idximg->id, &lightmap); } /* no use for buffer anymore release the mipmap */ dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf); } /* update background progress */ if (jid) { fraction+=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } } while ((imgitem=g_list_next(imgitem)) && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED); /* cleanup */ if (jid) dt_control_backgroundjobs_destroy(darktable.control, jid); } free(scratchmem); /* * Indexing opertions finished, lets reschedule the indexer * unless control is shutting down... */ if(dt_control_running()) dt_control_start_indexer(); return 0; }
static gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer user_data) { if(!dt_control_running()) return FALSE; update((dt_lib_module_t *)user_data, TRUE); return FALSE; }
static gboolean expose_borders (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { // draw arrows on borders if(!dt_control_running()) return TRUE; long int which = (long int)user_data; float width = widget->allocation.width, height = widget->allocation.height; cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); GtkStyle *style = gtk_widget_get_style(dt_ui_center(darktable.gui->ui)); cairo_set_source_rgb (cr, .5f*style->bg[GTK_STATE_NORMAL].red/65535.0, .5f*style->bg[GTK_STATE_NORMAL].green/65535.0, .5f*style->bg[GTK_STATE_NORMAL].blue/65535.0 ); // cairo_set_source_rgb (cr, .13, .13, .13); cairo_paint(cr); // draw scrollbar indicators int v = darktable.view_manager->current_view; dt_view_t *view = NULL; if(v >= 0 && v < darktable.view_manager->num_views) view = darktable.view_manager->view + v; // cairo_set_source_rgb (cr, .16, .16, .16); cairo_set_source_rgb (cr, style->bg[GTK_STATE_NORMAL].red/65535.0, style->bg[GTK_STATE_NORMAL].green/65535.0, style->bg[GTK_STATE_NORMAL].blue/65535.0 ); const float border = 0.3; if(!view) cairo_paint(cr); else { switch(which) { case 0: case 1: // left, right: vertical cairo_rectangle(cr, 0.0, view->vscroll_pos/view->vscroll_size * height, width, view->vscroll_viewport_size/view->vscroll_size * height); break; default: // bottom, top: horizontal cairo_rectangle(cr, view->hscroll_pos/view->hscroll_size * width, 0.0, view->hscroll_viewport_size/view->hscroll_size * width, height); break; } cairo_fill(cr); switch(which) { case 0: cairo_rectangle(cr, (1.0-border)*width, 0.0, border*width, height); break; case 1: cairo_rectangle(cr, 0.0, 0.0, border*width, height); break; case 2: cairo_rectangle(cr, (1.0-border)*height, (1.0-border)*height, width-2*(1.0-border)*height, border*height); break; default: cairo_rectangle(cr, (1.0-border)*height, 0.0, width-2*(1.0-border)*height, border*height); break; } cairo_fill(cr); } // draw gui arrows. cairo_set_source_rgb (cr, .6, .6, .6); switch(which) { case 0: // left if(dt_ui_panel_visible(darktable.gui->ui, DT_UI_PANEL_LEFT)) { cairo_move_to (cr, width, height/2-width); cairo_rel_line_to (cr, 0.0, 2*width); cairo_rel_line_to (cr, -width, -width); } else { cairo_move_to (cr, 0.0, height/2-width); cairo_rel_line_to (cr, 0.0, 2*width); cairo_rel_line_to (cr, width, -width); } break; case 1: // right if(dt_ui_panel_visible(darktable.gui->ui, DT_UI_PANEL_RIGHT)) { cairo_move_to (cr, 0.0, height/2-width); cairo_rel_line_to (cr, 0.0, 2*width); cairo_rel_line_to (cr, width, -width); } else { cairo_move_to (cr, width, height/2-width); cairo_rel_line_to (cr, 0.0, 2*width); cairo_rel_line_to (cr, -width, -width); } break; case 2: // top if(dt_ui_panel_visible(darktable.gui->ui, DT_UI_PANEL_CENTER_TOP)) { cairo_move_to (cr, width/2-height, height); cairo_rel_line_to (cr, 2*height, 0.0); cairo_rel_line_to (cr, -height, -height); } else { cairo_move_to (cr, width/2-height, 0.0); cairo_rel_line_to (cr, 2*height, 0.0); cairo_rel_line_to (cr, -height, height); } break; default: // bottom if(dt_ui_panel_visible(darktable.gui->ui, DT_UI_PANEL_CENTER_BOTTOM)) { cairo_move_to (cr, width/2-height, 0.0); cairo_rel_line_to (cr, 2*height, 0.0); cairo_rel_line_to (cr, -height, height); } else { cairo_move_to (cr, width/2-height, height); cairo_rel_line_to (cr, 2*height, 0.0); cairo_rel_line_to (cr, -height, -height); } break; } cairo_close_path (cr); cairo_fill(cr); cairo_destroy(cr); cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface (cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
void dt_control_queue_redraw_widget(GtkWidget *widget) { if(dt_control_running()) g_main_context_invoke(NULL, _gtk_widget_queue_draw, widget); }
/* calback for the mouse over image change signal */ static void _mouse_over_image_callback(gpointer instance,gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; if(dt_control_running()) _metadata_view_update_values(self); }