/** \file window.c * Basic window handling stuff. */ /* XTrkCad - Model Railroad CAD * Copyright (C) 2005 Dave Bullis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #define GTK_DISABLE_SINGLE_INCLUDES #define GDK_DISABLE_DEPRECATED #define GTK_DISABLE_DEPRECATED #define GSEAL_ENABLE #define MIN_WIDTH 100 #define MIN_HEIGHT 100 #include #include #include #include "gtkint.h" wWin_p gtkMainW; #define MIN_WIN_WIDTH 50 #define MIN_WIN_HEIGHT 50 #define SECTIONWINDOWSIZE "gtklib window size" #define SECTIONWINDOWPOS "gtklib window pos" extern wBool_t listHelpStrings; static wControl_p firstWin = NULL, lastWin; static int keyState; static wBool_t gtkBlockEnabled = TRUE; static wBool_t maximize_at_next_show = FALSE; #include "../../bin/bitmaps/xtc.xpm" static GdkPixbuf *windowIconPixbuf = NULL; /* ***************************************************************************** * * Window Utilities * ***************************************************************************** */ /** * Get the "monitor" size for the window (strictly the nearest or most used monitor) * Note in OSX there is one giant virtual monitor so this doesn't work to force resize down... * */ static GdkRectangle getMonitorDimensions(GtkWidget * widget) { GdkRectangle monitor_dimensions; GdkScreen *screen = NULL; int monitor; GtkWidget * toplevel = gtk_widget_get_toplevel(widget); if (gtk_widget_is_toplevel(GTK_WIDGET(toplevel)) && gtk_widget_get_parent_window(GTK_WIDGET(toplevel))) { GdkWindow * window = GDK_WINDOW(gtk_widget_get_parent_window(GTK_WIDGET( toplevel))); screen = gdk_window_get_screen(GDK_WINDOW(window)); monitor = gdk_screen_get_monitor_at_window(screen,GDK_WINDOW(window)); } else { screen = gdk_screen_get_default(); monitor = gdk_screen_get_primary_monitor(screen); } gdk_screen_get_monitor_geometry(screen,monitor,&monitor_dimensions); return monitor_dimensions; } /** * Get the window size from the resource (.rc) file. The size is saved under the key * SECTIONWINDOWSIZE.window name * * \param win IN window * \param nameStr IN window name */ static void getWinSize(wWin_p win, const char * nameStr) { /* * original w/h values in .origX/Y */ int w = win->w = win->origX; int h = win->h = win->origY; /* * Take values from Prefs if possible */ const char *cp; char *cp1, *cp2; if ((win->option&F_RESIZE) && (win->option&F_RECALLSIZE) && (cp = wPrefGetString(SECTIONWINDOWSIZE, nameStr)) && (w = strtod(cp, &cp1), cp != cp1) && (h = strtod(cp1, &cp2), cp1 != cp2)) { win->option &= ~F_AUTOSIZE; /* * Clamp window to be no bigger than one monitor size (to start - the user can always maximize) */ GdkRectangle monitor_dimensions = getMonitorDimensions(GTK_WIDGET(win->gtkwin)); wWinPix_t maxDisplayWidth = monitor_dimensions.width-10; wWinPix_t maxDisplayHeight = monitor_dimensions.height-50; if (w > maxDisplayWidth) { w = maxDisplayWidth; } if (h > maxDisplayHeight) { h = maxDisplayHeight; } if (ww = win->origX = w; win->h = win->origY = h; } } /** * Save the window size to the resource (.rc) file. The size is saved under the key * SECTIONWINDOWSIZE.window name * * \param win IN window */ static void saveSize(wWin_p win) { if ((win->option&F_RECALLSIZE) && gtk_widget_get_visible(GTK_WIDGET(win->gtkwin))) { char pos_s[32]; sprintf(pos_s, "%ld %ld", win->w, (win->h-(BORDERSIZE + ((win->option&F_MENUBAR)?MENUH:0)))); wPrefSetString(SECTIONWINDOWSIZE, win->nameStr, pos_s); } } /** * Get the window position from the resource (.rc) file. The position is saved under the key * SECTIONWINDOWPOS.window name * * \param win IN window */ static void getPos(wWin_p win) { char *cp1, *cp2; GdkRectangle monitor_dimensions = getMonitorDimensions(GTK_WIDGET(win->gtkwin)); if ((win->option&F_RECALLPOS) && (!win->shown)) { const char *cp; if ((cp = wPrefGetString(SECTIONWINDOWPOS, win->nameStr))) { int x, y; x = strtod(cp, &cp1); if (cp == cp1) { return; } y = strtod(cp1, &cp2); if (cp2 == cp1) { return; } if (y > monitor_dimensions.height+monitor_dimensions.y-win->h) { y = monitor_dimensions.height+monitor_dimensions.y-win->h; } if (x > monitor_dimensions.width+monitor_dimensions.x-win->w) { x = monitor_dimensions.width+monitor_dimensions.x-win->w; } if (x <= 0) { x = 1; } if (y <= 0) { y = 1; } gtk_window_move(GTK_WINDOW(win->gtkwin), x, y); } } } /** * Save the window position to the resource (.rc) file. The position is saved under the key * SECTIONWINDOWPOS.window name * * \param win IN window */ static void savePos(wWin_p win) { int x, y; if ((win->option&F_RECALLPOS)) { char pos_s[32]; gdk_window_get_position(gtk_widget_get_window(GTK_WIDGET(win->gtkwin)), &x, &y); x -= 5; y -= 25; sprintf(pos_s, "%d %d", x, y); wPrefSetString(SECTIONWINDOWPOS, win->nameStr, pos_s); } } /** * Returns the dimensions of . * * \param win IN window handle * \param width OUT width of window * \param height OUT height of window minus menu bar size */ void wWinGetSize( wWin_p win, /* Window */ wWinPix_t * width, /* Returned window width */ wWinPix_t * height) /* Returned window height */ { GtkRequisition requisition; wWinPix_t w, h; gtk_widget_size_request(win->gtkwin, &requisition); w = win->w; h = win->h; *width = w; *height = h - BORDERSIZE - ((win->option&F_MENUBAR)?win->menu_height:0); } /** * Sets the dimensions of window * * \param win IN window * \param width IN new width * \param height IN new height */ void wWinSetSize( wWin_p win, /* Window */ wWinPix_t width, /* Window width */ wWinPix_t height) /* Window height */ { win->busy = TRUE; win->w = width; win->h = height + BORDERSIZE + ((win->option&F_MENUBAR)?MENUH:0); if (win->option&F_RESIZE) { gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h); gtk_widget_set_size_request(win->widget, win->w-10, win->h-10); } else { gtk_widget_set_size_request(win->gtkwin, win->w, win->h); gtk_widget_set_size_request(win->widget, win->w, win->h); } win->busy = FALSE; } /** * Shows or hides window . If is created with 'F_BLOCK' option then the applications other * windows are disabled and 'wWinShow' doesnot return until the window is closed by calling * 'wWinShow(,FALSE)'. * * \param win IN window * \param show IN visibility state */ void wWinShow( wWin_p win, /* Window */ wBool_t show) /* Command */ { //GtkRequisition min_req, pref_req; if (debugWindow >= 2) { printf("Set Show %s\n", win->labelStr?win->labelStr:"No label"); } if (win->widget == 0) { abort(); } int width, height; if (show) { keyState = 0; getPos(win); if (!win->shown) { gtk_widget_show(win->gtkwin); gtk_widget_show(win->widget); } if (win->option & F_AUTOSIZE) { GtkAllocation allocation; GtkRequisition requistion; gtk_widget_size_request(win->widget,&requistion); width = win->w; height = win->h; if (requistion.width != width || requistion.height != height ) { width = requistion.width; height = requistion.height; win->w = width; win->h = height; gtk_window_set_resizable(GTK_WINDOW(win->gtkwin),TRUE); if (win->option&F_MENUBAR) { gtk_widget_set_size_request(win->menubar, win->w-20, MENUH); gtk_widget_get_allocation(win->menubar, &allocation); win->menu_height = allocation.height; } } gtk_window_resize(GTK_WINDOW(win->gtkwin), width+10, height+10); } gtk_window_present(GTK_WINDOW(win->gtkwin)); gdk_window_raise(gtk_widget_get_window(win->gtkwin)); if (win->shown && win->modalLevel > 0) { gtk_widget_set_sensitive(GTK_WIDGET(win->gtkwin), TRUE); } win->shown = show; win->modalLevel = 0; if ((!gtkBlockEnabled) || (win->option & F_BLOCK) == 0) { wFlush(); } else { wlibDoModal(win, TRUE); } if (maximize_at_next_show) { gtk_window_maximize(GTK_WINDOW(win->gtkwin)); maximize_at_next_show = FALSE; } } else { wFlush(); saveSize(win); savePos(win); win->shown = show; if (gtkBlockEnabled && (win->option & F_BLOCK) != 0) { wlibDoModal(win, FALSE); } gtk_widget_hide(win->gtkwin); gtk_widget_hide(win->widget); } } /** * Block windows against user interactions. Done during demo mode etc. * * \param enabled IN blocked if TRUE */ void wWinBlockEnable( wBool_t enabled) { gtkBlockEnabled = enabled; } /** * Returns whether the window is visible. * * \param win IN window * \return TRUE if visible, FALSE otherwise */ wBool_t wWinIsVisible( wWin_p win) { return win->shown; } /** * Returns whether the window is maximized. * * \param win IN window * \return TRUE if maximized, FALSE otherwise */ wBool_t wWinIsMaximized(wWin_p win) { return win->maximize_initially; } /** * Sets the title of to . * * \param varname1 IN window * \param varname2 IN new title */ void wWinSetTitle( wWin_p win, /* Window */ const char * title) /* New title */ { gtk_window_set_title(GTK_WINDOW(win->gtkwin), title); } /** * Sets the window <win> to busy or not busy. Sets the cursor accordingly * * \param varname1 IN window * \param varname2 IN TRUE if busy, FALSE otherwise */ void wWinSetBusy( wWin_p win, /* Window */ wBool_t busy) /* Command */ { GdkCursor * cursor; if (win->gtkwin == 0) { abort(); } if (busy) { cursor = gdk_cursor_new(GDK_WATCH); } else { cursor = NULL; } gdk_window_set_cursor(gtk_widget_get_window(win->gtkwin), cursor); if (cursor) { gdk_cursor_unref(cursor); } gtk_widget_set_sensitive(GTK_WIDGET(win->gtkwin), busy==0); } /** * Set the modality of window. All visible windows are disabled when * the window is modal. These windows are enabled again, when window * is not modal. Disabling can be performed several times and enabling * has to be repeated as well to re-enable a window. * \todo Give this recursive enabling/disabling some thought and remove * * \param win0 IN window * \param modal IN TRUE if window is application modal, FALSE otherwise * \return */ void wlibDoModal( wWin_p win0, wBool_t modal) { wWin_p win; for (win=(wWin_p)firstWin; win; win=(wWin_p)win->next) { if (win->shown && win != win0) { if (modal) { if (win->modalLevel == 0) { gtk_widget_set_sensitive(GTK_WIDGET(win->gtkwin), FALSE); } win->modalLevel++; } else { if (win->modalLevel > 0) { win->modalLevel--; if (win->modalLevel == 0) { gtk_widget_set_sensitive(GTK_WIDGET(win->gtkwin), TRUE); } } } if (win->modalLevel < 0) { fprintf(stderr, "DoModal: %s modalLevel < 0", win->nameStr?win->nameStr:"<NULL>"); abort(); } } } if (modal) { gtk_main(); } else { gtk_main_quit(); } } /** * Returns the Title of <win>. * * \param win IN window * \return pointer to window title */ const char * wWinGetTitle( wWin_p win) /* Window */ { return win->labelStr; } void wWinClear( wWin_p win, wWinPix_t x, wWinPix_t y, wWinPix_t width, wWinPix_t height) { } void wWinDoCancel( wWin_p win) { wControl_p b; for (b=win->first; b; b=b->next) { if ((b->type == B_BUTTON) && (b->option & BB_CANCEL)) { wlibButtonDoAction((wButton_p)b); } } } /* ****************************************************************************** * * Call Backs * ****************************************************************************** */ static int window_redraw( wWin_p win, wBool_t doWinProc) { wControl_p b; if (win==NULL) { return FALSE; } for (b=win->first; b != NULL; b = b->next) { if (b->repaintProc) { b->repaintProc(b); } } return FALSE; } static gint window_delete_event( GtkWidget *widget, GdkEvent *event, wWin_p win) { wControl_p b; /* if you return FALSE in the "delete_event" signal handler, * GTK will emit the "destroy" signal. Returning TRUE means * you don't want the window to be destroyed. * This is useful for popping up 'are you sure you want to quit ?' * type dialogs. */ /* Change TRUE to FALSE and the main window will be destroyed with * a "delete_event". */ for (b = win->first; b; b=b->next) if (b->doneProc) { b->doneProc(b); } if (win->winProc) { win->winProc(win, wClose_e, NULL, win->data); if (win != gtkMainW) { wWinShow(win, FALSE); } } return (TRUE); } static int fixed_expose_event( GtkWidget * widget, GdkEventExpose * event, wWin_p win) { int rc; if (event->count==0) { rc = window_redraw(win, TRUE); } else { rc = FALSE; } return rc; } static int resizeTime(wWin_p win) { if (debugWindow >= 2) { printf( "resizeTime idleCnt %d, busyCnt %d [%d %d] [%ld %ld]\n", win->timer_idle_count, win->timer_busy_count, win->resizeW, win->resizeH, win->w, win->h ); } if (win->resizeW == win->w && win->resizeH == win->h) { // If hasn't changed since last if (win->timer_idle_count>3) { win->winProc(win, wResize_e, NULL, win->data); //Trigger Redraw on last occasion if one-third of a second has elapsed win->timer_idle_count = 0; win->resizeTimer = 0; win->timer_busy_count = 0; return FALSE; //Stop Timer and don't resize } else { win->timer_idle_count++; } } if (win->busy==FALSE && win->winProc) { //Always drive once if (win->timer_busy_count>10) { win->winProc(win, wResize_e, NULL, win->data); //Redraw if ten times we saw a change (1 sec) win->timer_busy_count = 0; } else { win->winProc(win, wResize_e, (void*) 1, win->data); //No Redraw win->timer_busy_count++; } win->resizeW = win->w; //Remember this one win->resizeH = win->h; } return TRUE; //Will redrive after another timer interval } static int window_configure_event( GtkWidget * widget, GdkEventConfigure * event, wWin_p win) { if (win==NULL) { return FALSE; } if (debugWindow >= 2) { printf( "config/resize: [%d %d]\n", event->width, event->height ); } if (win->option&F_RESIZE) { if (event->width < 10 || event->height < 10) { return TRUE; } int w = win->w; int h = win->h; if (win->w != event->width || win->h != event->height) { if (debugWindow >= 2) { printf( " Update [%ld %ld]\n", event->width-win->w, event->height-win->h ); } win->w = event->width; win->h = event->height; if (win->w < MIN_WIN_WIDTH) { win->w = MIN_WIN_WIDTH; } if (win->h < MIN_WIN_HEIGHT) { win->h = MIN_WIN_HEIGHT; } if (win->option&F_MENUBAR) { GtkAllocation allocation; gtk_widget_get_allocation(win->menubar, &allocation); win->menu_height= allocation.height; gtk_widget_set_size_request(win->menubar, win->w-20, win->menu_height); } if (win->resizeTimer) { // Already have a timer return FALSE; } else { win->resizeW = w; //Remember where this started win->resizeH = h; win->timer_idle_count = 0; //Start background timer on redraw win->timer_busy_count = 0; win->resizeTimer = g_timeout_add(100,(GSourceFunc)resizeTime, win); // 100ms delay return FALSE; } } } return FALSE; } /** * Event handler for window state changes (maximize) * Handles maximize event by storing the new state in the internal structure and * calling the event handler * * \param widget gtk widget * \param event event information * \param win the wlib internal window data * \return TRUE if win is valid, */ gboolean window_state_event( GtkWidget *widget, GdkEventWindowState *event, wWin_p win) { if (!win) { return (FALSE); } win->maximize_initially = FALSE; if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) { win->maximize_initially = TRUE; } if (win->busy==FALSE && win->winProc) { win->winProc(win, wState_e, NULL, win->data); } return TRUE; } /** * Get current state of shift, ctrl or alt keys. * * \return or'ed value of WKEY_SHIFT, WKEY_CTRL and WKEY_ALT depending on state */ int wGetKeyState(void) { return keyState; } wBool_t catch_shift_ctrl_alt_keys( GtkWidget * widget, GdkEventKey *event, void * data) { int state = 0; switch (event->keyval ) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: state |= WKEY_SHIFT; break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: state |= WKEY_CTRL; break; case GDK_KEY_Alt_L: case GDK_KEY_Alt_R: state |= WKEY_ALT; break; case GDK_KEY_Meta_L: case GDK_KEY_Meta_R: // Pressing SHIFT and then ALT generates a Meta key //printf( "Meta\n" ); state |= WKEY_ALT; break; } if (state != 0) { if (event->type == GDK_KEY_PRESS) { keyState |= state; } else { keyState &= ~state; } return TRUE; } return FALSE; } static gint window_char_event( GtkWidget * widget, GdkEventKey *event, wWin_p win) { wControl_p bb; if (catch_shift_ctrl_alt_keys(widget, event, win)) { return FALSE; } if (event->type == GDK_KEY_RELEASE) { return FALSE; } if ( ( event->state & GDK_MODIFIER_MASK ) == 0 ) { if (event->keyval == GDK_KEY_Escape) { for (bb=win->first; bb; bb=bb->next) { if (bb->type == B_BUTTON && (bb->option&BB_CANCEL)) { wlibButtonDoAction((wButton_p)bb); return TRUE; } } } } if (wlibHandleAccelKey(event)) { return TRUE; } else { return FALSE; } } void wSetGeometry(wWin_p win, wWinPix_t min_width, wWinPix_t max_width, wWinPix_t min_height, wWinPix_t max_height, wWinPix_t base_width, wWinPix_t base_height, double aspect_ratio ) { GdkGeometry hints; GdkWindowHints hintMask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; hints.min_width = min_width; hints.max_width = max_width; hints.min_height = min_height; hints.max_height = max_height; hints.min_aspect = hints.max_aspect = aspect_ratio; hints.base_width = base_width; hints.base_height = base_height; if( base_width != -1 && base_height != -1 ) { hintMask |= GDK_HINT_BASE_SIZE; } if(aspect_ratio > -1.0 ) { hintMask |= GDK_HINT_ASPECT; } gtk_window_set_geometry_hints( GTK_WINDOW(win->gtkwin), win->gtkwin, &hints, hintMask); } /* ******************************************************************************* * * Main and Popup Windows * ******************************************************************************* */ /** * Create a window. * Default width and height are replaced by values stored in the configuration * file (.rc) * * \param parent IN parent window * \param winType IN type of window * \param x IN default width * \param y IN default height * \param labelStr IN window title * \param nameStr IN name of window * \param option IN misc options for placement and sizing of window * \param winProc IN window procedure * \param data IN additional data to pass to the window procedure * \return the newly created window */ static wWin_p wWinCommonCreate( wWin_p parent, int winType, wWinPix_t x, wWinPix_t y, const char * labelStr, const char * nameStr, long option, wWinCallBack_p winProc, void * data) { wWin_p w; int h; w = wlibAlloc(NULL, winType, x, y, labelStr, sizeof *w, data); w->busy = TRUE; w->option = option; w->resizeTimer = 0; h = BORDERSIZE; if (w->option&F_MENUBAR) { h += MENUH; } if (winType == W_MAIN) { w->gtkwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); } else { w->gtkwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); if (gtkMainW) { if (!(w->option&F_NOTTRANSIENT)) gtk_window_set_transient_for(GTK_WINDOW(w->gtkwin), GTK_WINDOW(gtkMainW->gtkwin)); } } getWinSize(w, nameStr); if (winType != W_MAIN) { gtk_widget_set_app_paintable (w->gtkwin,TRUE); } if (option & F_HIDE) { gtk_widget_hide(w->gtkwin); } /* center window on top of parent window */ if (option & F_CENTER) { gtk_window_set_position(GTK_WINDOW(w->gtkwin), GTK_WIN_POS_CENTER_ON_PARENT); } w->widget = gtk_fixed_new(); if (w->widget == 0) { abort(); } if (w->option&F_MENUBAR) { w->menubar = gtk_menu_bar_new(); gtk_container_add(GTK_CONTAINER(w->widget), w->menubar); gtk_widget_show(w->menubar); GtkAllocation allocation; gtk_widget_get_allocation(w->menubar, &allocation); w->menu_height = allocation.height; gtk_widget_set_size_request(w->menubar, -1, w->menu_height); } gtk_container_add(GTK_CONTAINER(w->gtkwin), w->widget); if (w->option&F_AUTOSIZE) { w->realX = 0; w->w = 0; w->realY = h; w->h = 0; } else if (w->origX != 0) { w->realX = w->origX; w->realY = w->origY+h; //gtk_widget_set_size_request(w->widget, w->w-20, w->h); if (w->option&F_MENUBAR) { gtk_widget_set_size_request(w->menubar, w->w-20, MENUH); } } w->first = w->last = NULL; w->winProc = winProc; g_signal_connect(GTK_OBJECT(w->gtkwin), "delete_event", G_CALLBACK(window_delete_event), w); g_signal_connect(GTK_OBJECT(w->widget), "expose_event", G_CALLBACK(fixed_expose_event), w); g_signal_connect(GTK_OBJECT(w->gtkwin), "configure_event", G_CALLBACK(window_configure_event), w); g_signal_connect(GTK_OBJECT(w->gtkwin), "window-state-event", G_CALLBACK(window_state_event), w); g_signal_connect(GTK_OBJECT(w->gtkwin), "key_press_event", G_CALLBACK(window_char_event), w); g_signal_connect(GTK_OBJECT(w->gtkwin), "key_release_event", G_CALLBACK(window_char_event), w); gtk_widget_set_events(w->widget, GDK_EXPOSURE_MASK); gtk_widget_set_events(GTK_WIDGET(w->gtkwin), GDK_EXPOSURE_MASK|GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK); if (w->option & F_RESIZE) { gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), TRUE); if ( ( w->option & F_AUTOSIZE ) == 0 ) { gtk_window_resize(GTK_WINDOW(w->gtkwin), w->w, w->h); } } else { gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), FALSE); } w->lastX = 0; w->lastY = h; w->shown = FALSE; w->nameStr = nameStr?strdup(nameStr):NULL; if (labelStr) { gtk_window_set_title(GTK_WINDOW(w->gtkwin), labelStr); } if (listHelpStrings) { printf("WINDOW - %s\n", nameStr?nameStr:"<NULL>"); } if (firstWin) { lastWin->next = (wControl_p)w; } else { firstWin = (wControl_p)w; } lastWin = (wControl_p)w; gtk_widget_show(w->widget); gtk_widget_realize(w->gtkwin); GtkAllocation allocation; gtk_widget_get_allocation(w->gtkwin, &allocation); w->menu_height = allocation.height; w->busy = FALSE; if (option&F_MAXIMIZE) { maximize_at_next_show = TRUE; } if ( windowIconPixbuf == NULL ) { windowIconPixbuf = gdk_pixbuf_new_from_xpm_data((const char**)&xtc_xpm); } gtk_window_set_icon( GTK_WINDOW(w->gtkwin), windowIconPixbuf ); return w; } /** * Initialize the application's main window. This function does the necessary initialization * of the application including creation of the main window. * * \param name IN internal name of the application. Used for filenames etc. * \param x IN Initial window width * \param y IN Initial window height * \param helpStr IN Help topic string * \param labelStr IN window title * \param nameStr IN Window name * \param option IN options for window creation * \param winProc IN pointer to main window procedure * \param data IN User context * \return window handle or NULL on error */ wWin_p wWinMainCreate( const char * name, /* Application name */ wWinPix_t x, /* Initial window width */ wWinPix_t y, /* Initial window height */ const char * helpStr, /* Help topic string */ const char * labelStr, /* Window title */ const char * nameStr, /* Window name */ long option, /* Options */ wWinCallBack_p winProc, /* Call back function */ void * data) /* User context */ { char *pos; long isMaximized; pos = strchr(name, ';'); if (pos) { /* if found, split application name and configuration name */ strcpy(wConfigName, pos + 1); } else { /* if not found, application name and configuration name are same */ strcpy(wConfigName, name); } wPrefGetInteger("draw", "maximized", &isMaximized, 0); option = option | (isMaximized?F_MAXIMIZE:0); gtkMainW = wWinCommonCreate(NULL, W_MAIN, x, y, labelStr, nameStr, option, winProc, data); wDrawColorWhite = wDrawFindColor(0xFFFFFF); wDrawColorBlack = wDrawFindColor(0x000000); return gtkMainW; } /** * Create a new popup window. * * \param parent IN Parent window (may be NULL) * \param x IN Initial window width * \param y IN Initial window height * \param helpStr IN Help topic string * \param labelStr IN Window title * \param nameStr IN Window name * \param option IN Options * \param winProc IN call back function * \param data IN User context information * \return handle for new window */ wWin_p wWinPopupCreate( wWin_p parent, wWinPix_t x, wWinPix_t y, const char * helpStr, const char * labelStr, const char * nameStr, long option, wWinCallBack_p winProc, void * data) { wWin_p win; if (parent == NULL) { if (gtkMainW == NULL) { abort(); } parent = gtkMainW; } win = wWinCommonCreate(parent, W_POPUP, x, y, labelStr, nameStr, option, winProc, data); return win; } /** * Terminates the applicaton with code <rc>. Before closing the main window * call back is called with wQuit_e. The program is terminated without exiting * the main message loop. * * \param rc IN exit code * \return never returns */ void wExit( int rc) /* Application return code */ { wWin_p win; for (win = (wWin_p)firstWin; win; win = (wWin_p)win->next) { if (gtk_widget_get_visible(GTK_WIDGET(win->gtkwin))) { saveSize(win); savePos(win); } } wPrefFlush(""); if (gtkMainW && gtkMainW->winProc != NULL) { gtkMainW->winProc(gtkMainW, wQuit_e, NULL, gtkMainW->data); } exit(rc); }