void vte_init(void) { if (vte_info.have_vte == FALSE) { /* vte_info.have_vte can be false even if VTE is compiled in, think of command line option */ geany_debug("Disabling terminal support"); return; } if (!EMPTY(vte_info.lib_vte)) { module = g_module_open(vte_info.lib_vte, G_MODULE_BIND_LAZY); } #ifdef VTE_MODULE_PATH else { module = g_module_open(VTE_MODULE_PATH, G_MODULE_BIND_LAZY); } #endif if (module == NULL) { gint i; const gchar *sonames[] = { #if GTK_CHECK_VERSION(3, 0, 0) "libvte2_90.so", "libvte2_90.so.9", #else "libvte.so", "libvte.so.4", "libvte.so.8", "libvte.so.9", #endif NULL }; for (i = 0; sonames[i] != NULL && module == NULL; i++) { module = g_module_open(sonames[i], G_MODULE_BIND_LAZY); } } if (module == NULL) { vte_info.have_vte = FALSE; geany_debug("Could not load libvte.so, embedded terminal support disabled"); return; } else { vf = g_new0(struct VteFunctions, 1); if (vte_register_symbols(module)) vte_info.have_vte = TRUE; else { vte_info.have_vte = FALSE; g_free(vf); /* FIXME: is closing the module safe? see vte_close() and test on FreeBSD */ /*g_module_close(module);*/ module = NULL; return; } } create_vte(); /* setup the F10 menu override (so it works before the widget is first realised). */ override_menu_key(); }
/* (Unix domain) socket support to replace the old FIFO code * (taken from Sylpheed, thanks) * Returns the created socket, -1 if an error occurred or -2 if another socket exists and files * were sent to it. */ gint socket_init(gint argc, gchar **argv) { gint sock; #ifdef G_OS_WIN32 HANDLE hmutex; HWND hwnd; socket_init_win32(); hmutex = CreateMutexA(NULL, FALSE, "AGK"); if (! hmutex) { geany_debug("cannot create Mutex\n"); return -1; } if (GetLastError() != ERROR_ALREADY_EXISTS) { /* To support multiple instances with different configuration directories (as we do on * non-Windows systems) we would need to use different port number s but it might be * difficult to get a port number which is unique for a configuration directory (path) * and which is unused. This port number has to be guessed by the first and new instance * and the only data is the configuration directory path. * For now we use one port number, that is we support only one instance at all. */ sock = socket_fd_open_inet(REMOTE_CMD_PORT); if (sock < 0) return 0; return sock; } sock = socket_fd_connect_inet(REMOTE_CMD_PORT); if (sock < 0) return -1; #else gchar *display_name = gdk_get_display(); const gchar *hostname = g_get_host_name(); gchar *p; if (display_name == NULL) display_name = g_strdup("NODISPLAY"); /* these lines are taken from dcopc.c in kdelibs */ if ((p = strrchr(display_name, '.')) > strrchr(display_name, ':') && p != NULL) *p = '\0'; /* remove characters that may not be acceptable in a filename */ for (p = display_name; *p; p++) { if (*p == ':' || *p == '/') *p = '_'; } if (socket_info.file_name == NULL) socket_info.file_name = g_strdup_printf("%s%cgeany_socket_%s_%s", app->configdir, G_DIR_SEPARATOR, hostname, display_name); g_free(display_name); /* check whether the real user id is the same as this of the socket file */ check_socket_permissions(); sock = socket_fd_connect_unix(socket_info.file_name); if (sock < 0) { remove_socket_link_full(); /* deletes the socket file and the symlink */ return socket_fd_open_unix(socket_info.file_name); } #endif /* remote command mode, here we have another running instance and want to use it */ #ifdef G_OS_WIN32 /* first we send a request to retrieve the window handle and focus the window */ socket_fd_write_all(sock, "window\n", 7); if (socket_fd_read(sock, (gchar *)&hwnd, sizeof(hwnd)) == sizeof(hwnd)) SetForegroundWindow(hwnd); #endif /* now we send the command line args */ if (argc > 1) { send_open_command(sock, argc, argv); } if (cl_options.list_documents) { socket_get_document_list(sock); } socket_fd_close(sock); return -2; }
static gint get_page_count(GtkPrintContext *context, DocInfo *dinfo) { gdouble width, height; gint layout_h; gint i, j, lines_left; gchar *line_buf; if (dinfo == NULL) return -1; width = gtk_print_context_get_width(context); height = gtk_print_context_get_height(context); if (printing_prefs.print_line_numbers) /* remove line number margin space from overall width */ width -= dinfo->max_line_number_margin * dinfo->font_width; pango_layout_set_width(dinfo->layout, width * PANGO_SCALE); /* add test text to get line height */ pango_layout_set_text(dinfo->layout, "Test 1", -1); pango_layout_get_size(dinfo->layout, NULL, &layout_h); if (layout_h <= 0) { geany_debug("Invalid layout_h (%d). Falling back to default height (%d)", layout_h, 100 * PANGO_SCALE); layout_h = 100 * PANGO_SCALE; } dinfo->line_height = (gdouble)layout_h / PANGO_SCALE; dinfo->lines_per_page = ceil((height - dinfo->line_height) / dinfo->line_height); #ifdef GEANY_PRINT_DEBUG geany_debug("max lines_per_page: %d", dinfo->lines_per_page); #endif if (printing_prefs.print_page_numbers) dinfo->lines_per_page -= 2; if (printing_prefs.print_page_header) dinfo->lines_per_page -= 3; lines_left = dinfo->lines_per_page; i = 0; for (j = 0; j < dinfo->lines; j++) { gint lines = 1; gint line_width; line_buf = sci_get_line(dinfo->doc->editor->sci, j); line_width = (g_utf8_strlen(line_buf, -1) + 1) * dinfo->font_width; if (line_width > width) lines = ceil(line_width / width); #ifdef GEANY_PRINT_DEBUG if (lines != 1) geany_debug("%d %d", j+1, lines); #endif while (lines_left < lines) { lines -= lines_left; lines_left = dinfo->lines_per_page; i++; } lines_left -= lines; g_free(line_buf); } return i + 1; }
static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) { DocInfo *dinfo = user_data; GeanyEditor *editor; cairo_t *cr; gdouble width, height; gdouble x, y; /*gint layout_h;*/ gint count; GString *str; if (dinfo == NULL || page_nr >= dinfo->n_pages) return; editor = dinfo->doc->editor; if (dinfo->n_pages > 0) { gdouble fraction = (page_nr + 1) / (gdouble) dinfo->n_pages; gchar *text = g_strdup_printf(_("Page %d of %d"), page_nr, dinfo->n_pages); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_widgets.progressbar), fraction); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), text); g_free(text); } #ifdef GEANY_PRINT_DEBUG geany_debug("draw_page = %d, pages = %d, (real) lines_per_page = %d", page_nr, dinfo->n_pages, dinfo->lines_per_page); #endif str = g_string_sized_new(256); cr = gtk_print_context_get_cairo_context(context); width = gtk_print_context_get_width(context); height = gtk_print_context_get_height(context); cairo_set_source_rgb(cr, 0, 0, 0); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.2); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_move_to(cr, 0, 0); pango_layout_set_width(dinfo->layout, width * PANGO_SCALE); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_LEFT); pango_layout_set_ellipsize(dinfo->layout, FALSE); pango_layout_set_justify(dinfo->layout, FALSE); if (printing_prefs.print_page_header) add_page_header(dinfo, cr, width, page_nr); count = 0; /* the actual line counter for the current page, might be different from * dinfo->cur_line due to possible line breaks */ while (count < dinfo->lines_per_page) { gchar c = 'a'; gint style = -1; PangoAttrList *layout_attr; PangoAttribute *attr; gint colours[3] = { 0 }; gboolean add_linenumber = TRUE; gboolean at_eol; while (count < dinfo->lines_per_page && c != '\0') { at_eol = FALSE; g_string_erase(str, 0, str->len); /* clear the string */ /* line numbers */ if (printing_prefs.print_line_numbers && add_linenumber) { /* if we had a wrapped line on the last page which needs to be continued, don't * add a line number */ if (dinfo->long_line) { add_linenumber = FALSE; } else { gchar *line_number = NULL; gint cur_line_number_margin = get_line_numbers_arity(dinfo->cur_line + 1); gchar *fill = g_strnfill( dinfo->max_line_number_margin - cur_line_number_margin - 1, ' '); line_number = g_strdup_printf("%s%d ", fill, dinfo->cur_line + 1); g_string_append(str, line_number); dinfo->cur_line++; /* increase document line */ add_linenumber = FALSE; style = STYLE_LINENUMBER; c = 'a'; /* dummy value */ g_free(fill); g_free(line_number); } } /* data */ else { style = sci_get_style_at(dinfo->doc->editor->sci, dinfo->cur_pos); c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c == '\0' || style == -1) { /* if c gets 0, we are probably out of document boundaries, * so stop to break out of outer loop */ count = dinfo->lines_per_page; break; } dinfo->cur_pos++; /* convert tabs to spaces which seems to be better than using Pango tabs */ if (c == '\t') { gint tab_width = sci_get_tab_width(editor->sci); gchar *s = g_strnfill(tab_width, ' '); g_string_append(str, s); g_free(s); } /* don't add line breaks, they are handled manually below */ else if (c == '\r' || c == '\n') { gchar c_next = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); at_eol = TRUE; if (c == '\r' && c_next == '\n') dinfo->cur_pos++; /* skip LF part of CR/LF */ } else { g_string_append_c(str, c); /* finally add the character */ /* handle UTF-8: since we add char by char (better: byte by byte), we need to * keep UTF-8 characters together(e.g. two bytes for one character) * the input is always UTF-8 and c is signed, so all non-Ascii * characters are less than 0 and consist of all bytes less than 0. * style doesn't change since it is only one character with multiple bytes. */ while (c < 0) { c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c < 0) { /* only add the byte when it is part of the UTF-8 character * otherwise we could add e.g. a '\n' and it won't be visible in the * printed document */ g_string_append_c(str, c); dinfo->cur_pos++; } } } } if (! at_eol) { /* set text */ pango_layout_set_text(dinfo->layout, str->str, -1); /* attributes */ layout_attr = pango_attr_list_new(); /* foreground colour */ get_rgb_values(dinfo->styles[style][FORE], &colours[0], &colours[1], &colours[2]); attr = pango_attr_foreground_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* background colour */ get_rgb_values(dinfo->styles[style][BACK], &colours[0], &colours[1], &colours[2]); attr = pango_attr_background_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* bold text */ if (dinfo->styles[style][BOLD]) { attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); ADD_ATTR(layout_attr, attr); } /* italic text */ if (dinfo->styles[style][ITALIC]) { attr = pango_attr_style_new(PANGO_STYLE_ITALIC); ADD_ATTR(layout_attr, attr); } pango_layout_set_attributes(dinfo->layout, layout_attr); pango_layout_context_changed(dinfo->layout); pango_attr_list_unref(layout_attr); } cairo_get_current_point(cr, &x, &y); /* normal line break at eol character in document */ if (at_eol) { /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, 0, y + (gdouble)layout_h / PANGO_SCALE);*/ cairo_move_to(cr, 0, y + dinfo->line_height); count++; /* we added a new document line so request a new line number */ add_linenumber = TRUE; } else { gint x_offset = 0; /* maybe we need to force a line break because of too long line */ if (x >= (width - dinfo->font_width)) { /* don't start the line at horizontal origin because we need to skip the * line number margin */ if (printing_prefs.print_line_numbers) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; } /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, x_offset, y + (gdouble)layout_h / PANGO_SCALE);*/ /* this is faster but not exactly the same as above */ cairo_move_to(cr, x_offset, y + dinfo->line_height); cairo_get_current_point(cr, &x, &y); count++; } if (count < dinfo->lines_per_page) { /* str->len is counted in bytes not characters, so use g_utf8_strlen() */ x_offset = (g_utf8_strlen(str->str, -1) * dinfo->font_width); if (dinfo->long_line && count == 0) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; dinfo->long_line = FALSE; } pango_cairo_show_layout(cr, dinfo->layout); cairo_move_to(cr, x + x_offset, y); } else /* we are on a wrapped line but we are out of lines on this page, so continue * the current line on the next page and remember to continue in current line */ dinfo->long_line = TRUE; } } } if (printing_prefs.print_line_numbers) { /* print a thin line between the line number margin and the data */ gint y_start = 0; if (printing_prefs.print_page_header) y_start = (dinfo->line_height * 3) - 2; /* "- 2": to connect the line number line to * the page header frame */ cairo_set_line_width(cr, 0.3); cairo_move_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y_start); cairo_line_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y + dinfo->line_height); /* y is last added line, we reuse it */ cairo_stroke(cr); } if (printing_prefs.print_page_numbers) { gchar *line = g_strdup_printf("<small>- %d -</small>", page_nr + 1); pango_layout_set_markup(dinfo->layout, line, -1); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_CENTER); cairo_move_to(cr, 0, height - dinfo->line_height); pango_cairo_show_layout(cr, dinfo->layout); g_free(line); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.3); cairo_move_to(cr, 0, height - (1.25 * dinfo->line_height)); cairo_line_to(cr, width - 1, height - (1.25 * dinfo->line_height)); cairo_stroke(cr); #endif } g_string_free(str, TRUE); }
static gchar *encodings_convert_to_utf8_with_suggestion(const gchar *buffer, gsize size, const gchar *suggested_charset, gchar **used_encoding) { const gchar *locale_charset = NULL; const gchar *charset; gchar *utf8_content; gboolean check_suggestion = suggested_charset != NULL; gboolean check_locale = FALSE; gint i, preferred_charset; if ((gint)size == -1) { size = strlen(buffer); } /* current locale is not UTF-8, we have to check this charset */ check_locale = ! g_get_charset(&locale_charset); /* First check for preferred charset, if specified */ preferred_charset = file_prefs.default_open_encoding; if (preferred_charset == encodings[GEANY_ENCODING_NONE].idx || preferred_charset < 0 || preferred_charset >= GEANY_ENCODINGS_MAX) { preferred_charset = -1; } /* -1 means "Preferred charset" */ for (i = -1; i < GEANY_ENCODINGS_MAX; i++) { if (G_UNLIKELY(i == encodings[GEANY_ENCODING_NONE].idx)) continue; if (check_suggestion) { check_suggestion = FALSE; charset = encodings_normalize_charset(suggested_charset); if (charset == NULL) /* we failed at normalizing suggested encoding, try it as is */ charset = suggested_charset; i = -2; /* keep i below the start value to have it again at -1 on the next loop run */ } else if (check_locale) { check_locale = FALSE; charset = locale_charset; i = -2; /* keep i below the start value to have it again at -1 on the next loop run */ } else if (i == -1) { if (preferred_charset >= 0) { charset = encodings[preferred_charset].charset; geany_debug("Using preferred charset: %s", charset); } else continue; } else if (i >= 0) charset = encodings[i].charset; else /* in this case we have i == -2, continue to increase i and go ahead */ continue; if (G_UNLIKELY(charset == NULL)) continue; geany_debug("Trying to convert %" G_GSIZE_FORMAT " bytes of data from %s into UTF-8.", size, charset); utf8_content = encodings_convert_to_utf8_from_charset(buffer, size, charset, FALSE); if (G_LIKELY(utf8_content != NULL)) { if (used_encoding != NULL) { if (G_UNLIKELY(*used_encoding != NULL)) { geany_debug("%s:%d", __FILE__, __LINE__); g_free(*used_encoding); } *used_encoding = g_strdup(charset); } return utf8_content; } } return NULL; }