X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkwin.c;h=eca119eb76799476530cd471b8b105f380e49050;hb=095072fa46b2d7b8beafaddb2f873d2f500a1e10;hp=7ebccbcae79ad01285c005613b7a62e764661bf9;hpb=e22a72c66a2d876f2ebe4bd6384b246af92cda4d;p=PuTTY.git diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 7ebccbca..eca119eb 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -94,11 +94,7 @@ struct gui_data { GtkIMContext *imc; #endif unifont *fonts[4]; /* normal, bold, wide, widebold */ -#if GTK_CHECK_VERSION(2,0,0) - const char *geometry; -#else int xpos, ypos, gotpos, gravity; -#endif GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor; GdkColor cols[NALLCOLOURS]; #if !GTK_CHECK_VERSION(3,0,0) @@ -341,6 +337,8 @@ void move_window(void *frontend, int x, int y) * though. */ #if GTK_CHECK_VERSION(2,0,0) + /* in case we reset this at startup due to a geometry string */ + gtk_window_set_gravity(GTK_WINDOW(inst->window), GDK_GRAVITY_NORTH_EAST); gtk_window_move(GTK_WINDOW(inst->window), x, y); #else gdk_window_move(gtk_widget_get_window(inst->window), x, y); @@ -640,6 +638,8 @@ char *dup_keyval_name(guint keyval) } #endif +static void change_font_size(struct gui_data *inst, int increment); + gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; @@ -840,6 +840,23 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) } } + if (event->keyval == GDK_KEY_greater && + (event->state & GDK_CONTROL_MASK)) { +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl->: increase font size\n")); +#endif + change_font_size(inst, +1); + return TRUE; + } + if (event->keyval == GDK_KEY_less && + (event->state & GDK_CONTROL_MASK)) { +#ifdef KEY_EVENT_DIAGNOSTICS + debug((" - Ctrl-<: increase font size\n")); +#endif + change_font_size(inst, -1); + return TRUE; + } + /* * Shift-PgUp and Shift-PgDn don't even generate keystrokes * at all. @@ -2014,6 +2031,12 @@ void set_raw_mouse_mode(void *frontend, int activate) update_mouseptr(inst); } +#if GTK_CHECK_VERSION(2,0,0) +static void compute_whole_window_size(struct gui_data *inst, + int wchars, int hchars, + int *wpix, int *hpix); +#endif + void request_resize(void *frontend, int w, int h) { struct gui_data *inst = (struct gui_data *)frontend; @@ -2095,14 +2118,9 @@ void request_resize(void *frontend, int w, int h) #else /* GTK_CHECK_VERSION(3,0,0) */ - /* - * In GTK3, we can do this by using gtk_window_resize_to_geometry, - * which uses the fact that we've already set up the main window's - * WM hints to reflect the terminal drawing area's resize - * increment (i.e. character cell) and the fixed amount of stuff - * round the edges. - */ - gtk_window_resize_to_geometry(GTK_WINDOW(inst->window), w, h); + int wp, hp; + compute_whole_window_size(inst, w, h, &wp, &hp); + gtk_window_resize(GTK_WINDOW(inst->window), wp, hp); #endif @@ -3608,29 +3626,37 @@ char *setup_fonts_ucs(struct gui_data *inst) return NULL; } -void set_geom_hints(struct gui_data *inst) +#if GTK_CHECK_VERSION(3,0,0) +struct find_app_menu_bar_ctx { + GtkWidget *area, *menubar; +}; +static void find_app_menu_bar(GtkWidget *widget, gpointer data) { - GdkGeometry geom; - gint flags; + struct find_app_menu_bar_ctx *ctx = (struct find_app_menu_bar_ctx *)data; + if (widget != ctx->area && GTK_IS_MENU_BAR(widget)) + ctx->menubar = widget; +} +#endif +static void compute_geom_hints(struct gui_data *inst, GdkGeometry *geom) +{ /* * Unused fields in geom. */ - geom.max_width = geom.max_height = -1; - geom.min_aspect = geom.max_aspect = 0; + geom->max_width = geom->max_height = -1; + geom->min_aspect = geom->max_aspect = 0; /* * Set up the geometry fields we care about, with reference to - * just the drawing area. We'll correct for the scrollbar in a + * just the drawing area. We'll correct for other widgets in a * moment. */ - flags = GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC; - geom.min_width = inst->font_width + 2*inst->window_border; - geom.min_height = inst->font_height + 2*inst->window_border; - geom.base_width = 2*inst->window_border; - geom.base_height = 2*inst->window_border; - geom.width_inc = inst->font_width; - geom.height_inc = inst->font_height; + geom->min_width = inst->font_width + 2*inst->window_border; + geom->min_height = inst->font_height + 2*inst->window_border; + geom->base_width = 2*inst->window_border; + geom->base_height = 2*inst->window_border; + geom->width_inc = inst->font_width; + geom->height_inc = inst->font_height; /* * If we've got a scrollbar visible, then we must include its @@ -3639,8 +3665,8 @@ void set_geom_hints(struct gui_data *inst) * the scrollbar. * * In the latter case, we must also take care to arrange that - * (geom.min_height - geom.base_height) is an integer multiple of - * geom.height_inc, because if it's not, then some window managers + * (geom->min_height - geom->base_height) is an integer multiple of + * geom->height_inc, because if it's not, then some window managers * (we know of xfwm4) get confused, with the effect that they * resize our window to a height based on min_height instead of * base_height, which we then round down and the window ends up @@ -3658,20 +3684,86 @@ void set_geom_hints(struct gui_data *inst) /* Compute rounded-up scrollbar height. */ min_sb_height = req.height; - min_sb_height += geom.height_inc - 1; - min_sb_height -= ((min_sb_height - geom.base_height % geom.height_inc) - % geom.height_inc); - - geom.min_width += req.width; - geom.base_width += req.width; - if (geom.min_height < min_sb_height) - geom.min_height = min_sb_height; + min_sb_height += geom->height_inc - 1; + min_sb_height -= ((min_sb_height - geom->base_height%geom->height_inc) + % geom->height_inc); + + geom->min_width += req.width; + geom->base_width += req.width; + if (geom->min_height < min_sb_height) + geom->min_height = min_sb_height; } +#if GTK_CHECK_VERSION(3,0,0) + /* + * And if we're running a gtkapp.c based program and + * GtkApplicationWindow has given us a menu bar inside the window, + * then we must take that into account as well. + * + * In its unbounded wisdom, GtkApplicationWindow doesn't actually + * give us a direct function call to _find_ the menu bar widget. + * Fortunately, we can find it by enumerating the children of the + * top-level window and looking for one we didn't put there + * ourselves. + */ + { + struct find_app_menu_bar_ctx actx, *ctx = &actx; + ctx->area = inst->area; + ctx->menubar = NULL; + gtk_container_foreach(GTK_CONTAINER(inst->window), + find_app_menu_bar, ctx); + + if (ctx->menubar) { + GtkRequisition req; + int min_menu_width; + gtk_widget_get_preferred_size(ctx->menubar, NULL, &req); + + /* + * This time, the height adjustment is easy (the menu bar + * sits above everything), but we have to take care with + * the _width_ to ensure we keep min_width and base_width + * congruent modulo width_inc. + */ + geom->min_height += req.height; + geom->base_height += req.height; + + min_menu_width = req.width; + min_menu_width += geom->width_inc - 1; + min_menu_width -= + ((min_menu_width - geom->base_width%geom->width_inc) + % geom->width_inc); + if (geom->min_width < min_menu_width) + geom->min_width = min_menu_width; + } + } +#endif +} + +void set_geom_hints(struct gui_data *inst) +{ + GdkGeometry geom; + gint flags = GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC; + compute_geom_hints(inst, &geom); +#if GTK_CHECK_VERSION(2,0,0) + if (inst->gotpos) + flags |= GDK_HINT_USER_POS; +#endif gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), NULL, &geom, flags); } +#if GTK_CHECK_VERSION(2,0,0) +static void compute_whole_window_size(struct gui_data *inst, + int wchars, int hchars, + int *wpix, int *hpix) +{ + GdkGeometry geom; + compute_geom_hints(inst, &geom); + if (wpix) *wpix = geom.base_width + wchars * geom.width_inc; + if (hpix) *hpix = geom.base_height + hchars * geom.height_inc; +} +#endif + void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data) { struct gui_data *inst = (struct gui_data *)data; @@ -3899,6 +3991,67 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) inst->reconfiguring = FALSE; } +static void change_font_size(struct gui_data *inst, int increment) +{ + static const int conf_keys[lenof(inst->fonts)] = { + CONF_font, CONF_boldfont, CONF_widefont, CONF_wideboldfont, + }; + FontSpec *oldfonts[lenof(inst->fonts)]; + FontSpec *newfonts[lenof(inst->fonts)]; + char *errmsg = NULL; + int i; + + for (i = 0; i < lenof(newfonts); i++) + oldfonts[i] = newfonts[i] = NULL; + + for (i = 0; i < lenof(inst->fonts); i++) { + if (inst->fonts[i]) { + char *newname = unifont_size_increment(inst->fonts[i], increment); + if (!newname) + goto cleanup; + newfonts[i] = fontspec_new(newname); + sfree(newname); + } + } + + for (i = 0; i < lenof(newfonts); i++) { + if (newfonts[i]) { + oldfonts[i] = fontspec_copy( + conf_get_fontspec(inst->conf, conf_keys[i])); + conf_set_fontspec(inst->conf, conf_keys[i], newfonts[i]); + } + } + + errmsg = setup_fonts_ucs(inst); + if (errmsg) + goto cleanup; + + /* Success, so suppress putting everything back */ + for (i = 0; i < lenof(newfonts); i++) { + if (oldfonts[i]) { + fontspec_free(oldfonts[i]); + oldfonts[i] = NULL; + } + } + + set_geom_hints(inst); + request_resize(inst, conf_get_int(inst->conf, CONF_width), + conf_get_int(inst->conf, CONF_height)); + term_invalidate(inst->term); + gtk_widget_queue_draw(inst->area); + + cleanup: + for (i = 0; i < lenof(oldfonts); i++) { + if (oldfonts[i]) { + conf_set_fontspec(inst->conf, conf_keys[i], oldfonts[i]); + fontspec_free(oldfonts[i]); + } + if (newfonts[i]) + fontspec_free(newfonts[i]); + } + sfree(errmsg); +} + void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { struct gui_data *inst = (struct gui_data *)gdata; @@ -4138,11 +4291,8 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string) inst->cumulative_scroll = 0.0; #endif +#ifndef NOT_X_WINDOWS if (geometry_string) { -#if GTK_CHECK_VERSION(2,0,0) - inst->geometry = geometry_string; -#else - /* On GTK 1, we have to do this using raw Xlib */ int flags, x, y; unsigned int w, h; flags = XParseGeometry(geometry_string, &x, &y, &w, &h); @@ -4158,8 +4308,8 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string) inst->gravity = ((flags & XNegative ? 1 : 0) | (flags & YNegative ? 2 : 0)); } -#endif } +#endif if (!compound_text_atom) compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); @@ -4218,11 +4368,21 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string) show_scrollbar(inst, conf_get_int(inst->conf, CONF_scrollbar)); gtk_widget_show(GTK_WIDGET(inst->hbox)); + /* + * We must call gtk_widget_realize before setting up the geometry + * hints, so that GtkApplicationWindow will have actually created + * its menu bar (if it's going to) and hence compute_geom_hints + * can find it to take its size into account. + */ + gtk_widget_realize(inst->window); set_geom_hints(inst); #if GTK_CHECK_VERSION(3,0,0) - gtk_window_set_default_geometry(GTK_WINDOW(inst->window), - inst->width, inst->height); + { + int wp, hp; + compute_whole_window_size(inst, inst->width, inst->height, &wp, &hp); + gtk_window_set_default_size(GTK_WINDOW(inst->window), wp, hp); + } #else { int w = inst->font_width * inst->width + 2*inst->window_border; @@ -4236,8 +4396,21 @@ struct gui_data *new_session_window(Conf *conf, const char *geometry_string) #endif #if GTK_CHECK_VERSION(2,0,0) - if (inst->geometry) { - gtk_window_parse_geometry(GTK_WINDOW(inst->window), inst->geometry); + if (inst->gotpos) { + static const GdkGravity gravities[] = { + GDK_GRAVITY_NORTH_WEST, + GDK_GRAVITY_NORTH_EAST, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_SOUTH_EAST, + }; + int x = inst->xpos, y = inst->ypos; + int wp, hp; + compute_whole_window_size(inst, inst->width, inst->height, &wp, &hp); + if (inst->gravity & 1) x += (gdk_screen_width() - wp); + if (inst->gravity & 2) y += (gdk_screen_height() - hp); + gtk_window_set_gravity(GTK_WINDOW(inst->window), + gravities[inst->gravity & 3]); + gtk_window_move(GTK_WINDOW(inst->window), x, y); } #else if (inst->gotpos) {