forked from Mirrors/openclonk
Remove the GTK platform (USE_GTK)
The GTK code does not work with the Qt editor. The simpler SDL2 platform does, so we have little reason to keep the GTK code. Note that GTK is still a dependency for mape. Discussion: http://forum.openclonk.org/topic_show.pl?tid=3328qteditor
parent
c12c51b44d
commit
b7359e0c27
|
@ -46,7 +46,6 @@ option(PROJECT_FOLDERS "Put source files into subfolders in project file" ON)
|
|||
CMAKE_DEPENDENT_OPTION(USE_COCOA "Use Apple Cocoa widgets." ON "APPLE" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(USE_WIN32_WINDOWS "Use Microsoft Desktop App User Interface widgets." ON "WIN32" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(USE_SDL_MAINLOOP "Use SDL to create windows etc. Qt editor." ON "NOT USE_COCOA AND NOT USE_WIN32_WINDOWS" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(USE_GTK "Use GTK+ widgets." ON "NOT USE_COCOA AND NOT USE_WIN32_WINDOWS AND NOT USE_SDL_MAINLOOP" OFF)
|
||||
option(WITH_AUTOMATIC_UPDATE "Automatic updates are downloaded from the project website." OFF)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ${PROJECT_FOLDERS})
|
||||
|
@ -298,9 +297,6 @@ CHECK_CXX_SOURCE_COMPILES("#include <GL/glew.h>\nvoid GLAPIENTRY OpenGLDebugProc
|
|||
|
||||
if(UNIX AND NOT APPLE)
|
||||
FINDLIB(X11_LIBRARIES X11)
|
||||
if(USE_GTK)
|
||||
FINDLIB(XRANDR_LIBRARIES Xrandr)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
|
@ -323,13 +319,6 @@ endif()
|
|||
SET(HAVE_LIBREADLINE ${READLINE_FOUND} CACHE INTERNAL "libreadline available")
|
||||
|
||||
find_package(GTK3 COMPONENTS gthread gio gobject glib OPTIONAL_COMPONENTS gtksourceview)
|
||||
if(USE_GTK)
|
||||
SET(WITH_GLIB ${GTK3_FOUND})
|
||||
include_directories(SYSTEM ${GTK3_INCLUDE_DIRS})
|
||||
# Set GTK link directory. This needs to be done before add_executable,
|
||||
# otherwise the path is not used for linking clonk
|
||||
link_directories(${GTK3_LIBRARY_DIRS})
|
||||
endif()
|
||||
|
||||
# Select an audio library
|
||||
find_package("Audio")
|
||||
|
@ -384,31 +373,6 @@ add_custom_command(
|
|||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT engine-resource.c
|
||||
COMMAND
|
||||
${GLIB_COMPILE_RESOURCES} "--internal" "--generate"
|
||||
"--target" "engine-resource.c"
|
||||
"--sourcedir" ${CMAKE_CURRENT_SOURCE_DIR}/src/res
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/res/engine.xml"
|
||||
MAIN_DEPENDENCY src/res/engine.xml
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Brush_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Halt_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Picker_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Cursor_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Play_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Dynamic_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Line_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Rect_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Exact_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Mouse_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Static_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/Fill_Trans.png
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/res/oc.ico
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
############################################################################
|
||||
# Mac OS bundle setup
|
||||
############################################################################
|
||||
|
@ -966,16 +930,7 @@ elseif(UPNP_STYLE STREQUAL "miniupnpc")
|
|||
endif()
|
||||
|
||||
# source files specific to a GUI library
|
||||
if(USE_GTK)
|
||||
list(APPEND OC_GUI_SOURCES
|
||||
src/editor/C4ConsoleGTK.cpp
|
||||
src/editor/C4ConsoleGTKDlg.cpp
|
||||
src/editor/C4ConsoleGTKDlg.h
|
||||
src/platform/C4AppGTK.cpp
|
||||
src/platform/C4WindowGTK.cpp
|
||||
engine-resource.c
|
||||
)
|
||||
elseif(USE_SDL_MAINLOOP)
|
||||
if(USE_SDL_MAINLOOP)
|
||||
list(APPEND OC_GUI_SOURCES
|
||||
src/platform/C4AppSDL.cpp
|
||||
src/platform/C4WindowSDL.cpp
|
||||
|
@ -1188,9 +1143,6 @@ target_link_libraries(openclonk
|
|||
libc4script
|
||||
libmisc
|
||||
)
|
||||
if(USE_GTK)
|
||||
target_link_libraries(openclonk ${GTK3_LIBRARIES})
|
||||
endif()
|
||||
if(USE_COCOA)
|
||||
target_link_libraries(openclonk "-framework Cocoa -framework AppKit -framework Quartz -framework OpenAL -framework AudioToolbox")
|
||||
endif()
|
||||
|
@ -1217,7 +1169,6 @@ target_link_libraries(openclonk-server
|
|||
${READLINE_LIBRARIES}
|
||||
${Audio_LIBRARIES}
|
||||
${GETOPT_LIBRARIES}
|
||||
${GTK3_glib_LIBRARIES}
|
||||
${TinyXML_LIBRARIES}
|
||||
${DBGHELP_LIBRARIES}
|
||||
${UPNP_LIBRARIES}
|
||||
|
|
|
@ -583,7 +583,7 @@ void C4Console::RegisterRecentInput(const char *input, RecentScriptInputLists se
|
|||
mru.erase(mru.begin());
|
||||
}
|
||||
|
||||
#if !(defined(USE_WIN32_WINDOWS) || defined(USE_COCOA) || defined(USE_GTK) || defined(WITH_QT_EDITOR))
|
||||
#if !(defined(USE_WIN32_WINDOWS) || defined(USE_COCOA) || defined(WITH_QT_EDITOR))
|
||||
class C4ConsoleGUI::State: public C4ConsoleGUI::InternalState<class C4ConsoleGUI>
|
||||
{
|
||||
public: State(C4ConsoleGUI *console): Super(console) {}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2007-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||
* Copyright (c) 2010-2016, The OpenClonk Team and contributors
|
||||
*
|
||||
* Distributed under the terms of the ISC license; see accompanying file
|
||||
* "COPYING" for details.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||
* See accompanying file "TRADEMARK" for details.
|
||||
*
|
||||
* To redistribute this file separately, substitute the full license texts
|
||||
* for the above references.
|
||||
*/
|
||||
|
||||
/* Common window for drawing and property tool dialogs in console mode */
|
||||
|
||||
#include "C4Include.h"
|
||||
#include "editor/C4ConsoleGTKDlg.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
GtkWidget* C4DevmodeDlg::window = NULL;
|
||||
GtkWidget* C4DevmodeDlg::notebook = NULL;
|
||||
|
||||
int C4DevmodeDlg::x = -1;
|
||||
int C4DevmodeDlg::y = -1;
|
||||
|
||||
namespace
|
||||
{
|
||||
gboolean OnDeleteEvent(GtkWidget* widget, gpointer user_data)
|
||||
{
|
||||
// Just hide the window, don't destroy it
|
||||
C4DevmodeDlg::SwitchPage(NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void C4DevmodeDlg::OnDestroy(GtkWidget* window, gpointer user_data)
|
||||
{
|
||||
C4DevmodeDlg::window = NULL;
|
||||
C4DevmodeDlg::notebook = NULL;
|
||||
}
|
||||
|
||||
void C4DevmodeDlg::AddPage(GtkWidget* widget, GtkWindow* parent, const char* title)
|
||||
{
|
||||
// Create Window if necessary
|
||||
if (window == NULL)
|
||||
{
|
||||
notebook = gtk_notebook_new();
|
||||
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), false);
|
||||
gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), false);
|
||||
gtk_widget_show(GTK_WIDGET(notebook));
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_container_add(GTK_CONTAINER(window), notebook);
|
||||
|
||||
gtk_window_set_resizable(GTK_WINDOW(window), true);
|
||||
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_UTILITY);
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 320, 320);
|
||||
gtk_window_set_role(GTK_WINDOW(window), "toolbox");
|
||||
|
||||
gtk_window_set_transient_for(GTK_WINDOW(window), parent);
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(OnDeleteEvent), NULL);
|
||||
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(OnDestroy), NULL);
|
||||
}
|
||||
|
||||
// Add page to notebook
|
||||
GtkWidget* label = gtk_label_new(title);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, label);
|
||||
}
|
||||
|
||||
void C4DevmodeDlg::RemovePage(GtkWidget* widget)
|
||||
{
|
||||
int page_num = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), widget);
|
||||
assert(page_num != -1); // Make sure it is contained
|
||||
|
||||
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page_num);
|
||||
|
||||
if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook)) == 0)
|
||||
gtk_widget_destroy(window);
|
||||
}
|
||||
|
||||
void C4DevmodeDlg::SwitchPage(GtkWidget* widget)
|
||||
{
|
||||
bool is_visible = gtk_widget_get_visible(GTK_WIDGET(window));
|
||||
|
||||
// Remember window position
|
||||
if (window != NULL && is_visible)
|
||||
gtk_window_get_position(GTK_WINDOW(window), &x, &y);
|
||||
|
||||
if (widget != NULL)
|
||||
{
|
||||
assert(window != NULL);
|
||||
|
||||
// Show required page
|
||||
int page_num = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), widget);
|
||||
assert(page_num != -1); // Make sure it is contained
|
||||
|
||||
gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page_num);
|
||||
gtk_window_set_title(GTK_WINDOW(window), gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(notebook), widget));
|
||||
|
||||
// Show window if not visible
|
||||
if (!is_visible)
|
||||
{
|
||||
gtk_widget_show(window);
|
||||
if (x != -1 || y != -1)
|
||||
gtk_window_move(GTK_WINDOW(window), x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window != NULL && is_visible)
|
||||
gtk_widget_hide(window);
|
||||
}
|
||||
}
|
||||
|
||||
void C4DevmodeDlg::SetTitle(GtkWidget* widget, const char* title)
|
||||
{
|
||||
gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), widget, title);
|
||||
int page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
|
||||
if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num) == widget)
|
||||
gtk_window_set_title(GTK_WINDOW(window), title);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||
* Copyright (c) 2013-2016, The OpenClonk Team and contributors
|
||||
*
|
||||
* Distributed under the terms of the ISC license; see accompanying file
|
||||
* "COPYING" for details.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||
* See accompanying file "TRADEMARK" for details.
|
||||
*
|
||||
* To redistribute this file separately, substitute the full license texts
|
||||
* for the above references.
|
||||
*/
|
||||
|
||||
/* Common window for drawing and property tool dialogs in console mode */
|
||||
|
||||
#ifndef INC_C4DevmodeDlg
|
||||
#define INC_C4DevmodeDlg
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif // USE_GTK
|
||||
|
||||
// TODO: Threadsafety?
|
||||
class C4DevmodeDlg
|
||||
{
|
||||
// Make sure all developer tools are held in the same window
|
||||
#ifdef USE_GTK
|
||||
private:
|
||||
static GtkWidget* window;
|
||||
static GtkWidget* notebook;
|
||||
|
||||
static int x, y;
|
||||
|
||||
static void OnDestroy(GtkWidget* widget, gpointer user_data);
|
||||
|
||||
public:
|
||||
static GtkWidget* GetWindow() { return window; }
|
||||
static void AddPage(GtkWidget* widget, GtkWindow* parent, const char* title);
|
||||
static void RemovePage(GtkWidget* widget);
|
||||
static void SwitchPage(GtkWidget* widget);
|
||||
|
||||
static void SetTitle(GtkWidget* widget, const char* title);
|
||||
#endif // USE_GTK
|
||||
};
|
||||
|
||||
#endif //INC_C4DevmodeDlg
|
|
@ -41,9 +41,6 @@
|
|||
#include "res/resource.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
StdStrBuf C4EditCursorSelection::GetDataString() const
|
||||
{
|
||||
|
@ -176,22 +173,6 @@ bool C4EditCursor::Init()
|
|||
#ifdef USE_WIN32_WINDOWS
|
||||
if (!(hMenu = LoadMenu(Application.GetInstance(),MAKEINTRESOURCE(IDR_CONTEXTMENUS))))
|
||||
return false;
|
||||
#elif defined(USE_GTK)
|
||||
menuContext = gtk_menu_new();
|
||||
|
||||
itemDelete = gtk_menu_item_new_with_label(LoadResStr("IDS_MNU_DELETE"));
|
||||
itemDuplicate = gtk_menu_item_new_with_label(LoadResStr("IDS_MNU_DUPLICATE"));
|
||||
itemGrabContents = gtk_menu_item_new_with_label(LoadResStr("IDS_MNU_CONTENTS"));
|
||||
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menuContext), itemDelete);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menuContext), itemDuplicate);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menuContext), itemGrabContents);
|
||||
|
||||
g_signal_connect(G_OBJECT(itemDelete), "activate", G_CALLBACK(OnDelete), this);
|
||||
g_signal_connect(G_OBJECT(itemDuplicate), "activate", G_CALLBACK(OnDuplicate), this);
|
||||
g_signal_connect(G_OBJECT(itemGrabContents), "activate", G_CALLBACK(OnGrabContents), this);
|
||||
|
||||
gtk_widget_show_all(menuContext);
|
||||
#endif
|
||||
Console.UpdateModeCtrls(Mode);
|
||||
|
||||
|
@ -1142,16 +1123,6 @@ void C4EditCursor::AppendMenuItem(int num, const StdStrBuf & label)
|
|||
AppendMenu(GetSubMenu(hMenu,0), MF_STRING, IDM_VPORTDYN_FIRST + num, label.GetWideChar());
|
||||
else
|
||||
AppendMenu(GetSubMenu(hMenu,0), MF_SEPARATOR, IDM_VPORTDYN_FIRST, NULL);
|
||||
#elif defined(USE_GTK)
|
||||
GtkWidget * wdg;
|
||||
if (num)
|
||||
wdg = gtk_menu_item_new_with_label(label.getData());
|
||||
else
|
||||
wdg = gtk_separator_menu_item_new();
|
||||
itemsObjselect[num].MenuItem = wdg;
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menuContext), wdg);
|
||||
if (num)
|
||||
g_signal_connect(G_OBJECT(wdg), "activate", G_CALLBACK(OnObjselect), &itemsObjselect[num]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1167,10 +1138,6 @@ bool C4EditCursor::DoContextMenu(DWORD dwKeyState)
|
|||
SetMenuItemText(hContext,IDM_VIEWPORT_DELETE,LoadResStr("IDS_MNU_DELETE"));
|
||||
SetMenuItemText(hContext,IDM_VIEWPORT_DUPLICATE,LoadResStr("IDS_MNU_DUPLICATE"));
|
||||
SetMenuItemText(hContext,IDM_VIEWPORT_CONTENTS,LoadResStr("IDS_MNU_CONTENTS"));
|
||||
#elif defined(USE_GTK)
|
||||
gtk_widget_set_sensitive(itemDelete, fObjectSelected && Console.Editing);
|
||||
gtk_widget_set_sensitive(itemDuplicate, fObjectSelected && Console.Editing);
|
||||
gtk_widget_set_sensitive(itemGrabContents, fObjectSelected && Selection.GetObject()->Contents.ObjectCount() && Console.Editing);
|
||||
#endif
|
||||
|
||||
// Add selection and custom command entries for any objects at the cursor
|
||||
|
@ -1274,9 +1241,6 @@ bool C4EditCursor::DoContextMenu(DWORD dwKeyState)
|
|||
break;
|
||||
}
|
||||
ObjselectDelItems();
|
||||
#elif defined(USE_GTK)
|
||||
gtk_widget_show_all(menuContext);
|
||||
gtk_menu_popup(GTK_MENU(menuContext), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -1439,53 +1403,12 @@ void C4EditCursor::EMControl(C4PacketType eCtrlType, C4ControlPacket *pCtrl)
|
|||
::Control.DoInput(eCtrlType, pCtrl, CDT_Decide);
|
||||
}
|
||||
|
||||
#ifdef USE_GTK
|
||||
// GTK+ callbacks
|
||||
void C4EditCursor::OnDelete(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
static_cast<C4EditCursor*>(data)->Delete();
|
||||
}
|
||||
|
||||
void C4EditCursor::OnDuplicate(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
static_cast<C4EditCursor*>(data)->Duplicate();
|
||||
}
|
||||
|
||||
void C4EditCursor::OnGrabContents(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
static_cast<C4EditCursor*>(data)->GrabContents();
|
||||
}
|
||||
|
||||
void C4EditCursor::OnObjselect(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
bool IsShiftDown = false;
|
||||
GdkEvent* event = gtk_get_current_event();
|
||||
if(event)
|
||||
{
|
||||
if(event->type == GDK_BUTTON_PRESS)
|
||||
IsShiftDown = ( ((GdkEventButton*)event)->state & MK_SHIFT) != 0;
|
||||
else if(event->type == GDK_KEY_PRESS)
|
||||
IsShiftDown = ( ((GdkEventKey*)event)->state & MK_SHIFT) != 0;
|
||||
|
||||
gdk_event_free(event);
|
||||
}
|
||||
ObjselItemDt* it = static_cast<ObjselItemDt*>(data);
|
||||
if (it->Command.getLength())
|
||||
it->EditCursor->DoContextObjCommand(it->Object, it->Command.getData());
|
||||
else
|
||||
it->EditCursor->DoContextObjsel(it->Object, !IsShiftDown);
|
||||
it->EditCursor->ObjselectDelItems();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void C4EditCursor::ObjselectDelItems() {
|
||||
if(!itemsObjselect.size()) return;
|
||||
std::vector<ObjselItemDt>::iterator it = itemsObjselect.begin();
|
||||
while(it != itemsObjselect.end()) {
|
||||
#if defined(USE_GTK)
|
||||
gtk_widget_destroy(it->MenuItem);
|
||||
#elif defined(USE_WIN32_WINDOWS)
|
||||
#if defined(USE_WIN32_WINDOWS)
|
||||
if(!it->ItemId) { ++it; continue; }
|
||||
HMENU hContext = GetSubMenu(hMenu,0);
|
||||
DeleteMenu(hContext, it->ItemId, MF_BYCOMMAND);
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
#include <vector>
|
||||
#include "object/C4DefGraphics.h"
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
// Currently selected elements in editcursor. May be objects and other prop lists.
|
||||
class C4EditCursorSelection : public std::list<C4Value>
|
||||
|
@ -69,19 +66,11 @@ protected:
|
|||
StdCopyStrBuf Command;
|
||||
#if defined(USE_WIN32_WINDOWS)
|
||||
UINT_PTR ItemId;
|
||||
#elif defined(USE_GTK)
|
||||
GtkWidget* MenuItem;
|
||||
#endif
|
||||
};
|
||||
std::vector<ObjselItemDt> itemsObjselect;
|
||||
#ifdef USE_WIN32_WINDOWS
|
||||
HMENU hMenu;
|
||||
#elif defined(USE_GTK)
|
||||
GtkWidget* menuContext;
|
||||
GtkWidget* itemDelete;
|
||||
GtkWidget* itemDuplicate;
|
||||
GtkWidget* itemGrabContents;
|
||||
GtkWidget* itemProperties;
|
||||
#endif
|
||||
// Selection may either be any number of objects or a single non-object prop list
|
||||
C4EditCursorSelection selection;
|
||||
|
@ -151,12 +140,6 @@ public:
|
|||
void PerformDuplicationLegacy(int32_t *pObjects, int32_t iObjectNum, bool fLocalCall);
|
||||
|
||||
protected:
|
||||
#ifdef USE_GTK
|
||||
static void OnDelete(GtkWidget* widget, gpointer data);
|
||||
static void OnDuplicate(GtkWidget* widget, gpointer data);
|
||||
static void OnGrabContents(GtkWidget* widget, gpointer data);
|
||||
static void OnObjselect(GtkWidget* widget, gpointer data);
|
||||
#endif
|
||||
public:
|
||||
void AddToSelection(C4PropList *add_obj); // add object to selection and do script callback. Doesn't do OnSelectionChanged().
|
||||
bool RemoveFromSelection(C4PropList *remove_obj); // remove object from selection and do script callback. return true if object was in selection before. Doesn't do OnSelectionChanged().
|
||||
|
|
|
@ -23,819 +23,6 @@
|
|||
#include "object/C4GameObjects.h"
|
||||
#include "script/C4Effect.h"
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
/* Some boilerplate GObject defines. 'klass' is used instead of 'class', because 'class' is a C++ keyword */
|
||||
|
||||
#define C4_TYPE_LIST (c4_list_get_type ())
|
||||
#define C4_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), C4_TYPE_LIST, C4List))
|
||||
#define C4_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), C4_TYPE_LIST, C4ListClass))
|
||||
#define C4_IS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), C4_TYPE_LIST))
|
||||
#define C4_IS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), C4_TYPE_LIST))
|
||||
#define C4_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), C4_TYPE_LIST, C4ListClass))
|
||||
|
||||
/* The data columns that we export via the tree model interface */
|
||||
|
||||
enum
|
||||
{
|
||||
C4_LIST_COL_OBJECT,
|
||||
C4_LIST_N_COLUMNS
|
||||
};
|
||||
|
||||
typedef struct _C4List C4List;
|
||||
typedef struct _C4ListClass C4ListClass;
|
||||
|
||||
struct _C4List
|
||||
{
|
||||
GObject parent; /* this MUST be the first member */
|
||||
|
||||
C4ObjectList * data;
|
||||
|
||||
gint stamp; /* A random integer to check if an iter belongs to this model */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* more boilerplate GObject stuff */
|
||||
|
||||
struct _C4ListClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GObjectClass *parent_class = NULL;
|
||||
|
||||
GType c4_list_get_type (void);
|
||||
|
||||
// Initialise an instance
|
||||
static void
|
||||
c4_list_init (C4List *c4_list)
|
||||
{
|
||||
c4_list->data = &::Objects;
|
||||
|
||||
c4_list->stamp = g_random_int(); /* Random int to check whether iters belong to this model */
|
||||
}
|
||||
|
||||
// destructor
|
||||
static void
|
||||
c4_list_finalize (GObject *object)
|
||||
{
|
||||
/* must chain up - finalize parent */
|
||||
(* parent_class->finalize) (object);
|
||||
}
|
||||
|
||||
|
||||
static GtkTreeModelFlags
|
||||
c4_list_get_flags (GtkTreeModel *tree_model)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST(tree_model), (GtkTreeModelFlags)0);
|
||||
|
||||
// neither is this a flat list nor do the iters persist changes in the model
|
||||
//return GtkTreeModelFlags(GTK_TREE_MODEL_ITERS_PERSIST);
|
||||
return GtkTreeModelFlags(0);
|
||||
}
|
||||
|
||||
// converts 'path' into an iterator and stores that in 'iter'
|
||||
static gboolean
|
||||
c4_list_get_iter (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path)
|
||||
{
|
||||
gint *indices, depth;
|
||||
|
||||
g_assert(C4_IS_LIST(tree_model));
|
||||
g_assert(path!=NULL);
|
||||
|
||||
C4List * c4_list = C4_LIST(tree_model);
|
||||
|
||||
indices = gtk_tree_path_get_indices(path);
|
||||
depth = gtk_tree_path_get_depth(path);
|
||||
|
||||
iter->stamp = c4_list->stamp;
|
||||
|
||||
|
||||
C4ObjectLink * pLnk = C4_LIST(tree_model)->data->First;
|
||||
// Skip Contained Objects in the main list
|
||||
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
|
||||
for (int i = 0; i < depth; ++i)
|
||||
{
|
||||
if (!pLnk)
|
||||
return false;
|
||||
if (indices[i] < 0)
|
||||
return false;
|
||||
for (int j = 0; j < indices[i]; ++j)
|
||||
{
|
||||
pLnk = pLnk->Next;
|
||||
// Skip Contained Objects in the main list
|
||||
while (i == 0 && pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
|
||||
if (!pLnk)
|
||||
return false;
|
||||
}
|
||||
iter->user_data = pLnk;
|
||||
iter->user_data2 = pLnk->Obj->Contained;
|
||||
pLnk = pLnk->Obj->Contents.First;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// converts 'iter' into a new tree path and returns that.
|
||||
// Note: This is called by OnObjectRemove with an iter which is not in the
|
||||
// list anymore, but with the object and prev still usable.
|
||||
static GtkTreePath *
|
||||
c4_list_get_path (GtkTreeModel * tree_model, GtkTreeIter * iter)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST(tree_model), NULL);
|
||||
g_return_val_if_fail (iter != NULL, NULL);
|
||||
g_return_val_if_fail (iter->user_data != NULL, NULL);
|
||||
|
||||
GtkTreePath *path = gtk_tree_path_new();
|
||||
|
||||
C4List * c4_list = C4_LIST(tree_model);
|
||||
|
||||
C4Object * pObj = ((C4ObjectLink *) iter->user_data)->Obj;
|
||||
|
||||
int i = 0;
|
||||
for (C4ObjectLink * pLnk = ((C4ObjectLink *) iter->user_data)->Prev; pLnk; pLnk = pLnk->Prev)
|
||||
{
|
||||
// Skip Contained Objects in the main list
|
||||
if (pObj->Contained != pLnk->Obj->Contained) continue;
|
||||
++i;
|
||||
}
|
||||
gtk_tree_path_prepend_index(path, i);
|
||||
|
||||
pObj = (C4Object *) iter->user_data2;
|
||||
while (pObj)
|
||||
{
|
||||
i = 0;
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
if (pObj->Contained)
|
||||
pList = &pObj->Contained->Contents;
|
||||
for (C4ObjectLink * pLnk = pList->First; pLnk && pLnk->Obj != pObj; pLnk = pLnk->Next)
|
||||
{
|
||||
// Skip Contained Objects in the main list
|
||||
if (pObj->Contained != pLnk->Obj->Contained) continue;
|
||||
++i;
|
||||
}
|
||||
gtk_tree_path_prepend_index(path, i);
|
||||
pObj = pObj->Contained;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// ++iter
|
||||
static gboolean
|
||||
c4_list_iter_next (GtkTreeModel * tree_model, GtkTreeIter * iter)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
|
||||
|
||||
if (iter == NULL || iter->user_data == NULL)
|
||||
return false;
|
||||
|
||||
C4ObjectLink * pLnk = (C4ObjectLink *) iter->user_data;
|
||||
|
||||
pLnk = pLnk->Next;
|
||||
|
||||
// Skip Contained Objects in the main list
|
||||
if (!(C4Object *)iter->user_data2)
|
||||
while (pLnk && pLnk->Obj->Contained)
|
||||
pLnk = pLnk->Next;
|
||||
if (!pLnk)
|
||||
return false;
|
||||
|
||||
iter->user_data = pLnk;
|
||||
iter->user_data2 = pLnk->Obj->Contained;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set 'iter' to the first child of 'parent', or the first top-level row if
|
||||
// 'parent' is 0, or return false if there aren't any children.
|
||||
static gboolean
|
||||
c4_list_iter_children (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent)
|
||||
{
|
||||
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
|
||||
|
||||
C4List *c4_list = C4_LIST(tree_model);
|
||||
|
||||
C4ObjectLink * pLnk;
|
||||
if (parent)
|
||||
{
|
||||
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
|
||||
pLnk = pList->First;
|
||||
}
|
||||
else
|
||||
{
|
||||
pLnk = c4_list->data->First;
|
||||
// Skip...
|
||||
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
|
||||
}
|
||||
if (!pLnk)
|
||||
return false;
|
||||
|
||||
/* Set iter to first item in list */
|
||||
iter->stamp = c4_list->stamp;
|
||||
iter->user_data = pLnk;
|
||||
iter->user_data2 = pLnk->Obj->Contained;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return true if 'parent' has children.
|
||||
static gboolean
|
||||
c4_list_iter_has_child (GtkTreeModel *tree_model,
|
||||
GtkTreeIter *parent)
|
||||
{
|
||||
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
|
||||
|
||||
C4List *c4_list = C4_LIST(tree_model);
|
||||
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
if (parent)
|
||||
pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
|
||||
return pList->First != 0;
|
||||
}
|
||||
|
||||
// Counts the children 'parent' has.
|
||||
static gint
|
||||
c4_list_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *parent)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), -1);
|
||||
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, -1);
|
||||
|
||||
C4List *c4_list = C4_LIST(tree_model);
|
||||
|
||||
int i = 0;
|
||||
if (parent)
|
||||
{
|
||||
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
|
||||
C4ObjectLink * pLnk = pList->First;
|
||||
while (pLnk)
|
||||
{
|
||||
++i;
|
||||
pLnk = pLnk->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
C4ObjectLink * pLnk = c4_list->data->First;
|
||||
while (pLnk)
|
||||
{
|
||||
if (!pLnk->Obj->Contained)
|
||||
++i;
|
||||
pLnk = pLnk->Next;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// Sets 'iter' to the 'n'-th child of 'parent'.
|
||||
static gboolean
|
||||
c4_list_iter_nth_child (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
|
||||
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
|
||||
|
||||
C4List *c4_list = C4_LIST(tree_model);
|
||||
|
||||
C4ObjectLink * pLnk;
|
||||
if (parent)
|
||||
{
|
||||
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
|
||||
pLnk = pList->First;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (!pLnk)
|
||||
return false;
|
||||
pLnk = pLnk->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pLnk = c4_list->data->First;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (!pLnk)
|
||||
return false;
|
||||
pLnk = pLnk->Next;
|
||||
// Skip...
|
||||
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
|
||||
}
|
||||
}
|
||||
if (!pLnk)
|
||||
return false;
|
||||
|
||||
iter->stamp = c4_list->stamp;
|
||||
iter->user_data = pLnk;
|
||||
iter->user_data2 = pLnk->Obj->Contained;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper function.
|
||||
static gboolean c4_list_iter_for_C4Object (GtkTreeModel * tree_model, GtkTreeIter * iter, C4ObjectList * pList, C4Object * pObj)
|
||||
{
|
||||
if (!pObj)
|
||||
return false;
|
||||
|
||||
C4List * c4_list = C4_LIST(tree_model);
|
||||
|
||||
for (C4ObjectLink * pLnk = pList->First; pLnk; pLnk = pLnk->Next)
|
||||
{
|
||||
if (pLnk->Obj == pObj)
|
||||
{
|
||||
iter->stamp = c4_list->stamp;
|
||||
iter->user_data = pLnk;
|
||||
iter->user_data2 = pLnk->Obj->Contained;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
g_return_val_if_reached(false);
|
||||
}
|
||||
|
||||
// Sets 'iter' to the parent row of 'child'.
|
||||
static gboolean
|
||||
c4_list_iter_parent (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * child)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
|
||||
g_return_val_if_fail (child == NULL || child->user_data != NULL, false);
|
||||
|
||||
C4List * c4_list = C4_LIST(tree_model);
|
||||
|
||||
C4Object * pObj = (C4Object *) child->user_data2;
|
||||
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
if (pObj->Contained)
|
||||
pList = &pObj->Contained->Contents;
|
||||
return c4_list_iter_for_C4Object(tree_model, iter, pList, pObj);
|
||||
}
|
||||
|
||||
static C4Object *
|
||||
c4_list_iter_get_C4Object(GtkTreeModel * tree_model, GtkTreeIter * iter)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST (tree_model), NULL);
|
||||
g_return_val_if_fail (iter != NULL && iter->user_data != NULL, NULL);
|
||||
|
||||
return ((C4ObjectLink *) iter->user_data)->Obj;
|
||||
}
|
||||
|
||||
// How many columns does this model have?
|
||||
static gint
|
||||
c4_list_get_n_columns (GtkTreeModel * tree_model)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST(tree_model), 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// What sort of data is in the column?
|
||||
static GType
|
||||
c4_list_get_column_type (GtkTreeModel * tree_model, gint index)
|
||||
{
|
||||
g_return_val_if_fail (C4_IS_LIST(tree_model), G_TYPE_INVALID);
|
||||
g_return_val_if_fail (index < 1 && index >= 0, G_TYPE_INVALID);
|
||||
|
||||
return G_TYPE_POINTER;
|
||||
}
|
||||
|
||||
// gets the data for the 'column' in the row at 'iter' and stores that in 'value'.
|
||||
static void
|
||||
c4_list_get_value (GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value)
|
||||
{
|
||||
g_return_if_fail (C4_IS_LIST (tree_model));
|
||||
g_return_if_fail (iter != NULL);
|
||||
g_return_if_fail (column == 0);
|
||||
|
||||
C4Object * pObj = ((C4ObjectLink *) iter->user_data)->Obj;
|
||||
g_return_if_fail (pObj != NULL);
|
||||
|
||||
g_value_init (value, G_TYPE_POINTER);
|
||||
g_value_set_pointer(value, pObj);
|
||||
|
||||
// g_value_set_string(value, pObj->GetName());
|
||||
}
|
||||
|
||||
// Wrapper around g_object_new.
|
||||
static C4List *
|
||||
c4_list_new (void)
|
||||
{
|
||||
C4List * list;
|
||||
|
||||
list = (C4List *) g_object_new (C4_TYPE_LIST, NULL);
|
||||
|
||||
g_assert(list != NULL);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Called once for the class.
|
||||
static void
|
||||
c4_list_class_init (C4ListClass * klass)
|
||||
{
|
||||
GObjectClass * object_class;
|
||||
|
||||
parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
|
||||
object_class = (GObjectClass*) klass;
|
||||
|
||||
object_class->finalize = c4_list_finalize;
|
||||
}
|
||||
|
||||
// fill in the GtkTreeModel interface with the functions above.
|
||||
static void
|
||||
c4_list_tree_model_init (GtkTreeModelIface *iface)
|
||||
{
|
||||
iface->get_flags = c4_list_get_flags;
|
||||
iface->get_n_columns = c4_list_get_n_columns;
|
||||
iface->get_column_type = c4_list_get_column_type;
|
||||
iface->get_iter = c4_list_get_iter;
|
||||
iface->get_path = c4_list_get_path;
|
||||
iface->get_value = c4_list_get_value;
|
||||
iface->iter_next = c4_list_iter_next;
|
||||
iface->iter_children = c4_list_iter_children;
|
||||
iface->iter_has_child = c4_list_iter_has_child;
|
||||
iface->iter_n_children = c4_list_iter_n_children;
|
||||
iface->iter_nth_child = c4_list_iter_nth_child;
|
||||
iface->iter_parent = c4_list_iter_parent;
|
||||
}
|
||||
|
||||
// Return the type, registering it on first call.
|
||||
GType
|
||||
c4_list_get_type (void)
|
||||
{
|
||||
static GType c4_list_type = 0;
|
||||
|
||||
if (c4_list_type == 0)
|
||||
{
|
||||
// Some boilerplate type registration stuff
|
||||
static const GTypeInfo c4_list_info =
|
||||
{
|
||||
sizeof (C4ListClass), /* class_size */
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
(GClassInitFunc) c4_list_class_init, /* class_init */
|
||||
NULL, /* class finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (C4List), /* instance_size */
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) c4_list_init, /* instance_init */
|
||||
NULL /* value_table */
|
||||
};
|
||||
|
||||
c4_list_type = g_type_register_static (G_TYPE_OBJECT, "C4List",
|
||||
&c4_list_info, (GTypeFlags)0);
|
||||
|
||||
/* register the GtkTreeModel interface with the type system */
|
||||
static const GInterfaceInfo tree_model_info =
|
||||
{
|
||||
(GInterfaceInitFunc) c4_list_tree_model_init,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
g_type_add_interface_static (c4_list_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
|
||||
}
|
||||
|
||||
return c4_list_type;
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
{
|
||||
if (!model) return;
|
||||
|
||||
C4List * c4_list = C4_LIST(model);
|
||||
C4Object * Contained = pLnk->Obj->Contained;
|
||||
GtkTreeIter iter;
|
||||
iter.stamp = c4_list->stamp;
|
||||
iter.user_data = pLnk;
|
||||
iter.user_data2 = Contained;
|
||||
|
||||
// While pLnk is not in the list anymore, with pLnk->Prev and Contained a path can still be made
|
||||
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
|
||||
|
||||
gtk_tree_model_row_deleted(GTK_TREE_MODEL(model), path);
|
||||
gtk_tree_path_free(path);
|
||||
|
||||
// Removed from a now empty container?
|
||||
if (Contained && !Contained->Contents.First)
|
||||
{
|
||||
printf("Removed from a now empty container\n");
|
||||
GtkTreeIter parent;
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
if (Contained->Contained)
|
||||
pList = &Contained->Contained->Contents;
|
||||
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &parent, pList, Contained);
|
||||
|
||||
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &parent);
|
||||
|
||||
gtk_tree_model_row_has_child_toggled(GTK_TREE_MODEL(model), path, &parent);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
|
||||
|
||||
// Cheat: For the signals it must look as if the object had it's parent removed already
|
||||
pLnk->Obj->Contained = 0;
|
||||
// if removed from contents, it get's added to main list
|
||||
if (pList != c4_list->data)
|
||||
{
|
||||
printf("Removed from a container\n");
|
||||
GtkTreeIter iter;
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &iter, pList, pLnk->Obj);
|
||||
|
||||
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
|
||||
|
||||
gtk_tree_model_row_inserted(GTK_TREE_MODEL(model), path, &iter);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
|
||||
// End-of-cheat
|
||||
pLnk->Obj->Contained = Contained;
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
{
|
||||
if (!model) return;
|
||||
|
||||
C4List * c4_list = C4_LIST(model);
|
||||
|
||||
// Inserted into a container? Remove from main list
|
||||
if (pList != c4_list->data)
|
||||
{
|
||||
printf("Inserted into a container\n");
|
||||
GtkTreePath *path = gtk_tree_path_new();
|
||||
int i = 0;
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
C4Object * pObj = pLnk->Obj;
|
||||
for (C4ObjectLink * pLnk2 = pList->First; pLnk2 && pLnk2->Obj != pObj; pLnk2 = pLnk2->Next)
|
||||
{
|
||||
// Skip Contained Objects in the main list
|
||||
if (pLnk2->Obj->Contained) continue;
|
||||
++i;
|
||||
}
|
||||
gtk_tree_path_prepend_index(path, i);
|
||||
|
||||
gtk_tree_model_row_deleted(GTK_TREE_MODEL(model), path);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
|
||||
GtkTreeIter iter;
|
||||
iter.stamp = c4_list->stamp;
|
||||
iter.user_data = pLnk;
|
||||
iter.user_data2 = pLnk->Obj->Contained;
|
||||
|
||||
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
|
||||
|
||||
gtk_tree_model_row_inserted(GTK_TREE_MODEL(model), path, &iter);
|
||||
gtk_tree_path_free(path);
|
||||
|
||||
// Inserted into a previously empty container?
|
||||
if (pLnk->Obj->Contained &&
|
||||
pLnk->Obj->Contained->Contents.First == pLnk->Obj->Contained->Contents.Last)
|
||||
{
|
||||
printf("Inserted into a previously empty container\n");
|
||||
GtkTreeIter parent;
|
||||
c4_list_iter_parent(GTK_TREE_MODEL(model), &parent, &iter);
|
||||
|
||||
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &parent);
|
||||
|
||||
gtk_tree_model_row_has_child_toggled(GTK_TREE_MODEL(model), path, &parent);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnDestroy(GtkWidget* widget, C4ObjectListDlg* dlg)
|
||||
{
|
||||
dlg->window = 0;
|
||||
dlg->model = 0;
|
||||
dlg->treeview = 0;
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnRowActivated(GtkTreeView * tree_view, GtkTreePath * path, GtkTreeViewColumn * column, C4ObjectListDlg * dlg)
|
||||
{
|
||||
Console.EditCursor.SetMode(C4CNS_ModeEdit);
|
||||
Console.EditCursor.OpenPropTools();
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnSelectionChanged(GtkTreeSelection* selection, C4ObjectListDlg* dlg)
|
||||
{
|
||||
if (dlg->updating_selection) return;
|
||||
dlg->updating_selection = true;
|
||||
|
||||
GList* list = gtk_tree_selection_get_selected_rows(selection, NULL);
|
||||
|
||||
Console.EditCursor.GetSelection().Clear();
|
||||
for (GList * i = list; i; i = i->next)
|
||||
{
|
||||
GtkTreePath * path = (GtkTreePath *)i->data;
|
||||
GtkTreeIter iter;
|
||||
c4_list_get_iter(GTK_TREE_MODEL(dlg->model), &iter, path);
|
||||
Console.EditCursor.GetSelection().Add(((C4ObjectLink *)iter.user_data)->Obj, C4ObjectList::stNone);
|
||||
}
|
||||
|
||||
g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
|
||||
g_list_free (list);
|
||||
|
||||
Console.EditCursor.OnSelectionChanged();
|
||||
dlg->updating_selection = false;
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::Update(C4EditCursorSelection &rSelection)
|
||||
{
|
||||
if (updating_selection) return;
|
||||
if (!window) return;
|
||||
updating_selection = true;
|
||||
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
|
||||
gtk_tree_selection_unselect_all(selection);
|
||||
|
||||
for (auto val : rSelection)
|
||||
{
|
||||
C4Object *obj = val.getObj();
|
||||
if (!obj) continue; // it's a non-object proplist or deleted object
|
||||
GtkTreeIter iter;
|
||||
C4List * c4_list = C4_LIST(model);
|
||||
C4ObjectList * pList = c4_list->data;
|
||||
if (obj->Contained)
|
||||
pList = &obj->Contained->Contents;
|
||||
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &iter, pList, obj);
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
}
|
||||
|
||||
updating_selection = false;
|
||||
}
|
||||
|
||||
C4ObjectListDlg::C4ObjectListDlg():
|
||||
window(0),
|
||||
treeview(0),
|
||||
model(0),
|
||||
updating_selection(false)
|
||||
{
|
||||
}
|
||||
|
||||
C4ObjectListDlg::~C4ObjectListDlg()
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::Execute()
|
||||
{
|
||||
}
|
||||
|
||||
static void name_cell_data_func(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
|
||||
{
|
||||
C4Object* object = c4_list_iter_get_C4Object(model, iter);
|
||||
|
||||
g_object_set(G_OBJECT(renderer), "text", object->GetName(), (gpointer)NULL);
|
||||
}
|
||||
|
||||
enum { ICON_SIZE = 24 };
|
||||
|
||||
#ifdef _UNUSED_
|
||||
static void icon_cell_data_func(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
|
||||
{
|
||||
C4Object* object = c4_list_iter_get_C4Object(model, iter);
|
||||
|
||||
// Icons for objects with ColorByOwner are cached by object, others by Def
|
||||
// FIXME: Invalidate cache when objects change color, and redraw.
|
||||
gpointer key = object->Def;
|
||||
if (object->Def->ColorByOwner) key = object;
|
||||
|
||||
GHashTable* table = static_cast<GHashTable*>(data);
|
||||
GdkPixbuf* pixbuf = GDK_PIXBUF(g_hash_table_lookup(table, key));
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
/* Not yet cached, create from Graphics */
|
||||
C4Surface* surface = object->Def->Graphics.Bmp.Bitmap;
|
||||
if (object->Def->Graphics.Bmp.BitmapClr) surface = object->Def->Graphics.Bmp.BitmapClr;
|
||||
|
||||
const C4Rect& picture = object->Def->PictureRect;
|
||||
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, picture.Wdt, picture.Hgt);
|
||||
guchar* pixels = gdk_pixbuf_get_pixels(pixbuf);
|
||||
surface->Lock();
|
||||
for (int y = 0; y < picture.Hgt; ++ y) for (int x = 0; x < picture.Wdt; ++ x)
|
||||
{
|
||||
DWORD dw = surface->GetPixDw(picture.x + x, picture.y + y, true);
|
||||
*pixels = (dw >> 16) & 0xff; ++ pixels;
|
||||
*pixels = (dw >> 8 ) & 0xff; ++ pixels;
|
||||
*pixels = (dw ) & 0xff; ++ pixels;
|
||||
*pixels = 0xff - ((dw >> 24) & 0xff); ++ pixels;
|
||||
}
|
||||
surface->Unlock();
|
||||
|
||||
// Scale down to ICON_SIZE, keeping aspect ratio
|
||||
guint dest_width, dest_height;
|
||||
if (picture.Wdt >= picture.Hgt)
|
||||
{
|
||||
double factor = static_cast<double>(picture.Hgt) / static_cast<double>(picture.Wdt);
|
||||
dest_width = ICON_SIZE;
|
||||
dest_height = dest_width * factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
double factor = static_cast<double>(picture.Wdt) / static_cast<double>(picture.Hgt);
|
||||
dest_height = ICON_SIZE;
|
||||
dest_width = dest_height * factor;
|
||||
}
|
||||
|
||||
GdkPixbuf* scaled = gdk_pixbuf_scale_simple(pixbuf, dest_width, dest_height, GDK_INTERP_HYPER);
|
||||
g_object_unref(G_OBJECT(pixbuf));
|
||||
pixbuf = scaled;
|
||||
|
||||
g_hash_table_insert(table, key, pixbuf);
|
||||
}
|
||||
|
||||
g_object_set(G_OBJECT(renderer), "pixbuf", pixbuf, NULL);
|
||||
}
|
||||
#endif // _UNUSED_
|
||||
|
||||
void C4ObjectListDlg::Open()
|
||||
{
|
||||
// Create Window if necessary
|
||||
if (window == NULL)
|
||||
{
|
||||
// The Windows
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
gtk_window_set_resizable(GTK_WINDOW(window), true);
|
||||
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_UTILITY);
|
||||
gtk_window_set_role(GTK_WINDOW(window), "objectlist");
|
||||
gtk_window_set_title(GTK_WINDOW(window), "Objects");
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 180, 300);
|
||||
|
||||
gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(Console.window));
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(OnDestroy), this);
|
||||
|
||||
// The Tree
|
||||
GtkWidget* scrolled_wnd = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_SHADOW_IN);
|
||||
|
||||
model = G_OBJECT(c4_list_new());
|
||||
|
||||
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
||||
|
||||
g_object_unref(model); /* destroy store automatically with view */
|
||||
|
||||
g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(OnRowActivated), this);
|
||||
|
||||
GtkTreeViewColumn * col = gtk_tree_view_column_new();
|
||||
GtkCellRenderer * renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_column_pack_start(col, renderer, true);
|
||||
gtk_tree_view_column_set_cell_data_func(col, renderer, name_cell_data_func, NULL, NULL);
|
||||
|
||||
gtk_tree_view_column_set_title(col, "Name");
|
||||
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview),col);
|
||||
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), false);
|
||||
gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), true);
|
||||
|
||||
GtkTreeSelection * selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
|
||||
|
||||
g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(OnSelectionChanged), this);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(scrolled_wnd), treeview);
|
||||
gtk_widget_set_vexpand(scrolled_wnd, true);
|
||||
gtk_widget_set_hexpand(scrolled_wnd, true);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), scrolled_wnd);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_window_present_with_time(GTK_WINDOW(window), gtk_get_current_event_time());
|
||||
}
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnObjectContainerChanged(C4Object *obj, C4Object *old_container, C4Object *new_container)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectAdded(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
C4ObjectListDlg::C4ObjectListDlg()
|
||||
{
|
||||
|
@ -928,6 +115,5 @@ void C4ObjectListDlg::OnEffectRemoved(C4Effect *fx)
|
|||
|
||||
#endif WITH_QT_EDITOR
|
||||
|
||||
#endif
|
||||
|
||||
C4ObjectListChangeListener & ObjectListChangeListener = Console.ObjectListDlg;
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
#ifndef INC_C4ObjectListDlg
|
||||
#define INC_C4ObjectListDlg
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif // USE_GTK
|
||||
|
||||
#include "object/C4ObjectList.h"
|
||||
|
||||
|
@ -48,17 +45,6 @@ public:
|
|||
virtual void OnEffectAdded(class C4Effect *fx) override;
|
||||
virtual void OnEffectRemoved(class C4Effect *fx) override;
|
||||
|
||||
#ifdef USE_GTK
|
||||
private:
|
||||
GtkWidget * window;
|
||||
GtkWidget * treeview;
|
||||
GObject * model;
|
||||
bool updating_selection;
|
||||
|
||||
static void OnDestroy(GtkWidget * widget, C4ObjectListDlg * dlg);
|
||||
static void OnRowActivated(GtkTreeView * tree_view, GtkTreePath * path, GtkTreeViewColumn * column, C4ObjectListDlg * dlg);
|
||||
static void OnSelectionChanged(GtkTreeSelection * selection, C4ObjectListDlg * dlg);
|
||||
#endif // USE_GTK
|
||||
};
|
||||
|
||||
#endif //INC_C4ObjectListDlg
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
#ifndef INC_C4ToolsDlg
|
||||
#define INC_C4ToolsDlg
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#include "config/C4Constants.h"
|
||||
#include "landscape/C4Landscape.h"
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
#include "landscape/C4Landscape.h"
|
||||
#include "player/C4PlayerList.h"
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_QT_EDITOR
|
||||
#include "editor/C4ConsoleQtViewport.h"
|
||||
|
@ -117,70 +114,7 @@ bool C4Viewport::ScrollBarsByViewPosition()
|
|||
return true;
|
||||
}
|
||||
|
||||
#elif defined(USE_GTK)
|
||||
bool C4Viewport::TogglePlayerLock()
|
||||
{
|
||||
if (PlayerLock)
|
||||
{
|
||||
PlayerLock = false;
|
||||
gtk_widget_show(pWindow->h_scrollbar);
|
||||
gtk_widget_show(pWindow->v_scrollbar);
|
||||
ScrollBarsByViewPosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerLock = true;
|
||||
gtk_widget_hide(pWindow->h_scrollbar);
|
||||
gtk_widget_hide(pWindow->v_scrollbar);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C4Viewport::ScrollBarsByViewPosition()
|
||||
{
|
||||
if (PlayerLock) return false;
|
||||
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(GTK_WIDGET(pWindow->render_widget), &allocation);
|
||||
|
||||
GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(pWindow->h_scrollbar));
|
||||
|
||||
gtk_adjustment_configure(adjustment,
|
||||
GetViewX(), // value
|
||||
0, // lower
|
||||
::Landscape.GetWidth(), // upper
|
||||
ViewportScrollSpeed, // step_increment
|
||||
allocation.width / Zoom, // page_increment
|
||||
allocation.width / Zoom // page_size
|
||||
);
|
||||
|
||||
adjustment = gtk_range_get_adjustment(GTK_RANGE(pWindow->v_scrollbar));
|
||||
gtk_adjustment_configure(adjustment,
|
||||
GetViewY(), // value
|
||||
0, // lower
|
||||
::Landscape.GetHeight(), // upper
|
||||
ViewportScrollSpeed, // step_increment
|
||||
allocation.height / Zoom, // page_increment
|
||||
allocation.height / Zoom // page_size
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C4Viewport::ViewPositionByScrollBars()
|
||||
{
|
||||
if (PlayerLock) return false;
|
||||
|
||||
GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(pWindow->h_scrollbar));
|
||||
SetViewX(gtk_adjustment_get_value(adjustment));
|
||||
|
||||
adjustment = gtk_range_get_adjustment(GTK_RANGE(pWindow->v_scrollbar));
|
||||
SetViewY(gtk_adjustment_get_value(adjustment));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // USE_GTK
|
||||
#endif
|
||||
|
||||
void C4ViewportWindow::PerformUpdate()
|
||||
{
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
|
||||
#include "platform/C4Window.h"
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
#ifdef WITH_QT_EDITOR
|
||||
#define C4ViewportWindowStyle (WS_VISIBLE)
|
||||
#else
|
||||
|
@ -37,10 +34,6 @@ class C4ViewportWindow: public C4Window
|
|||
public:
|
||||
C4Viewport * cvp;
|
||||
C4ViewportWindow(C4Viewport * cvp): cvp(cvp) { }
|
||||
#if defined(USE_GTK)
|
||||
GtkWidget* h_scrollbar;
|
||||
GtkWidget* v_scrollbar;
|
||||
#endif
|
||||
void EditCursorMove(int X, int Y, uint32_t);
|
||||
using C4Window::Init;
|
||||
C4Window * Init(int32_t iPlayer);
|
||||
|
|
|
@ -1855,19 +1855,6 @@ bool C4Game::SaveGameTitle(C4Group &hGroup)
|
|||
|
||||
bool C4Game::DoKeyboardInput(C4KeyCode vk_code, C4KeyEventType eEventType, bool fAlt, bool fCtrl, bool fShift, bool fRepeated, class C4GUI::Dialog *pForDialog, bool fPlrCtrlOnly, int32_t iStrength)
|
||||
{
|
||||
#ifdef USE_GTK
|
||||
static std::map<C4KeyCode, bool> PressedKeys;
|
||||
// Keyrepeats are send as down, down, ..., down, up, where all downs are not distinguishable from the first.
|
||||
if (eEventType == KEYEV_Down)
|
||||
{
|
||||
if (PressedKeys[vk_code]) fRepeated = true;
|
||||
else PressedKeys[vk_code] = true;
|
||||
}
|
||||
else if (eEventType == KEYEV_Up)
|
||||
{
|
||||
PressedKeys[vk_code] = false;
|
||||
}
|
||||
#endif
|
||||
// compose key
|
||||
C4KeyCodeEx Key(vk_code, C4KeyShiftState(fAlt*KEYS_Alt + fCtrl*KEYS_Control + fShift*KEYS_Shift), fRepeated);
|
||||
return DoKeyboardInput(Key, eEventType, pForDialog, fPlrCtrlOnly, iStrength);
|
||||
|
|
|
@ -60,16 +60,7 @@ bool C4Viewport::UpdateOutputSize(int32_t new_width, int32_t new_height)
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_GTK
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(GTK_WIDGET(pWindow->render_widget), &allocation);
|
||||
|
||||
// Use only size of drawing area without scrollbars
|
||||
rect.x = allocation.x;
|
||||
rect.y = allocation.y;
|
||||
rect.Wdt = allocation.width;
|
||||
rect.Hgt = allocation.height;
|
||||
#elif defined(WITH_QT_EDITOR)
|
||||
#if defined(WITH_QT_EDITOR)
|
||||
// Never query the window - size is always passed from Qt.
|
||||
return false;
|
||||
#else
|
||||
|
|
|
@ -127,8 +127,6 @@ protected:
|
|||
C4Window * pWindow; // window to draw in
|
||||
#ifdef USE_WGL
|
||||
HDC hDC; // device context handle
|
||||
#elif defined(USE_GTK)
|
||||
/*GLXContext*/void * ctx;
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
void * ctx;
|
||||
#endif
|
||||
|
|
|
@ -438,153 +438,6 @@ bool CStdGLCtx::PageFlip()
|
|||
return true;
|
||||
}
|
||||
|
||||
#elif defined(USE_GTK)
|
||||
#include <GL/glxew.h>
|
||||
#include <GL/glx.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
namespace {
|
||||
void InitGLXPointers()
|
||||
{
|
||||
glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)(glXGetProcAddress((const GLubyte*)"glXGetVisualFromFBConfig"));
|
||||
glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)(glXGetProcAddress((const GLubyte*)"glXChooseFBConfig"));
|
||||
glXCreateNewContext = (PFNGLXCREATENEWCONTEXTPROC)(glXGetProcAddress((const GLubyte*)"glXCreateNewContext"));
|
||||
}
|
||||
}
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), ctx(0), this_context(contexts.end()) { }
|
||||
|
||||
void CStdGLCtx::Clear(bool multisample_change)
|
||||
{
|
||||
Deselect();
|
||||
if (ctx)
|
||||
{
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
glXDestroyContext(dpy, (GLXContext)ctx);
|
||||
ctx = 0;
|
||||
}
|
||||
pWindow = 0;
|
||||
|
||||
if (this_context != contexts.end())
|
||||
{
|
||||
contexts.erase(this_context);
|
||||
this_context = contexts.end();
|
||||
}
|
||||
}
|
||||
|
||||
bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
||||
{
|
||||
// safety
|
||||
if (!pGL) return false;
|
||||
// store window
|
||||
this->pWindow = pWindow;
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
InitGLXPointers();
|
||||
if (!glXGetVisualFromFBConfig || !glXChooseFBConfig || !glXCreateNewContext)
|
||||
{
|
||||
return pGL->Error(" gl: Unable to retrieve GLX 1.4 entry points");
|
||||
}
|
||||
XVisualInfo *vis_info = glXGetVisualFromFBConfig(dpy, pWindow->Info);
|
||||
// Create base context so we can initialize GLEW
|
||||
GLXContext dummy_ctx = glXCreateContext(dpy, vis_info, 0, True);
|
||||
XFree(vis_info);
|
||||
glXMakeCurrent(dpy, pWindow->renderwnd, dummy_ctx);
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK)
|
||||
{
|
||||
return pGL->Error((const char*)glewGetErrorString(err));
|
||||
}
|
||||
|
||||
// Create Context with sharing (if this is the main context, our ctx will be 0, so no sharing)
|
||||
const int attribs[] = {
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, REQUESTED_GL_CTX_MAJOR,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, REQUESTED_GL_CTX_MINOR,
|
||||
GLX_CONTEXT_FLAGS_ARB, (Config.Graphics.DebugOpenGL ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
None
|
||||
};
|
||||
GLXContext share_context = (pGL->pMainCtx != this) ? static_cast<GLXContext>(pGL->pMainCtx->ctx) : 0;
|
||||
|
||||
if (glXCreateContextAttribsARB)
|
||||
{
|
||||
gdk_x11_display_error_trap_push(gdk_display_get_default());
|
||||
ctx = glXCreateContextAttribsARB(dpy, pWindow->Info, share_context, True, attribs);
|
||||
gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default());
|
||||
}
|
||||
if(!ctx) {
|
||||
Log(" gl: falling back to attribute-less context creation.");
|
||||
ctx = glXCreateNewContext(dpy, pWindow->Info, GLX_RGBA_TYPE, share_context, True);
|
||||
}
|
||||
|
||||
glXMakeCurrent(dpy, None, NULL);
|
||||
glXDestroyContext(dpy, dummy_ctx);
|
||||
|
||||
// No luck?
|
||||
if (!ctx) return pGL->Error(" gl: Unable to create context");
|
||||
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE;
|
||||
err = glewInit();
|
||||
if (GLEW_OK != err)
|
||||
{
|
||||
// Problem: glewInit failed, something is seriously wrong.
|
||||
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
}
|
||||
|
||||
this_context = contexts.insert(contexts.end(), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CStdGLCtx::Select(bool verbose)
|
||||
{
|
||||
// safety
|
||||
if (!pGL || !ctx)
|
||||
{
|
||||
if (verbose) pGL->Error(" gl: pGL is zero");
|
||||
return false;
|
||||
}
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
// make context current
|
||||
if (!pWindow->renderwnd || !glXMakeCurrent(dpy, pWindow->renderwnd, (GLXContext)ctx))
|
||||
{
|
||||
if (verbose) pGL->Error(" gl: glXMakeCurrent failed");
|
||||
return false;
|
||||
}
|
||||
SelectCommon();
|
||||
// update clipper - might have been done by UpdateSize
|
||||
// however, the wrong size might have been assumed
|
||||
if (!pGL->UpdateClipper())
|
||||
{
|
||||
if (verbose) pGL->Error(" gl: UpdateClipper failed");
|
||||
return false;
|
||||
}
|
||||
// success
|
||||
return true;
|
||||
}
|
||||
|
||||
void CStdGLCtx::Deselect()
|
||||
{
|
||||
if (pGL && pGL->pCurrCtx == this)
|
||||
{
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
glXMakeCurrent(dpy, None, NULL);
|
||||
pGL->pCurrCtx = 0;
|
||||
pGL->RenderTarget = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CStdGLCtx::PageFlip()
|
||||
{
|
||||
// flush GL buffer
|
||||
glFlush();
|
||||
if (!pWindow || !pWindow->renderwnd) return false;
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
glXSwapBuffers(dpy, pWindow->renderwnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), this_context(contexts.end()) { ctx = NULL; }
|
||||
|
@ -663,7 +516,7 @@ bool CStdGLCtx::PageFlip()
|
|||
return true;
|
||||
}
|
||||
|
||||
#endif //USE_GTK/USE_SDL_MAINLOOP
|
||||
#endif // USE_*
|
||||
|
||||
#ifdef WITH_QT_EDITOR
|
||||
#undef LineFeed // conflicts with Qt
|
||||
|
|
|
@ -22,13 +22,6 @@
|
|||
#include "game/C4Game.h"
|
||||
#include "platform/C4Window.h"
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
@ -412,7 +405,7 @@ StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool
|
|||
// for config files and such: dump scancode
|
||||
return FormatString("$%x", static_cast<unsigned int>(wCode));
|
||||
}
|
||||
#if defined(USE_WIN32_WINDOWS) || (defined(_WIN32) && defined(USE_GTK))
|
||||
#if defined(USE_WIN32_WINDOWS)
|
||||
|
||||
// Query map
|
||||
const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
|
||||
|
@ -442,20 +435,6 @@ StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool
|
|||
if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName); else ++pCheck;
|
||||
// not found: Compose as direct code
|
||||
return FormatString("\\x%x", static_cast<unsigned int>(wCode));
|
||||
#elif defined(USE_GTK)
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
KeySym keysym = (KeySym)XkbKeycodeToKeysym(dpy,wCode+8,0,0);
|
||||
char* name = NULL;
|
||||
if (keysym != NoSymbol) { // is the keycode without shift modifiers mapped to a symbol?
|
||||
name = gtk_accelerator_get_label_with_keycode(gdk_display_get_default(), keysym, wCode+8, (GdkModifierType)0);
|
||||
}
|
||||
if (name) { // is there a string representation of the keysym?
|
||||
// prevent memleak
|
||||
StdStrBuf buf;
|
||||
buf.Copy(name);
|
||||
g_free(name);
|
||||
return buf;
|
||||
}
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
StdStrBuf buf;
|
||||
buf.Copy(SDL_GetScancodeName(static_cast<SDL_Scancode>(wCode)));
|
||||
|
|
|
@ -122,11 +122,7 @@ public:
|
|||
pthread_t MainThread;
|
||||
#endif
|
||||
|
||||
#if defined(USE_GTK)
|
||||
protected:
|
||||
class C4X11AppImpl * Priv;
|
||||
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
#if defined(USE_SDL_MAINLOOP)
|
||||
public:
|
||||
void HandleSDLEvent(SDL_Event& event);
|
||||
|
||||
|
|
|
@ -1,378 +0,0 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
|
||||
*
|
||||
* Distributed under the terms of the ISC license; see accompanying file
|
||||
* "COPYING" for details.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||
* See accompanying file "TRADEMARK" for details.
|
||||
*
|
||||
* To redistribute this file separately, substitute the full license texts
|
||||
* for the above references.
|
||||
*/
|
||||
|
||||
/* A wrapper class to OS dependent event and window interfaces, X11 version */
|
||||
|
||||
#include "C4Include.h"
|
||||
#include "platform/C4App.h"
|
||||
|
||||
#include "platform/C4Window.h"
|
||||
#include "graphics/C4DrawGL.h"
|
||||
#include "graphics/C4Draw.h"
|
||||
#include "platform/StdFile.h"
|
||||
#include "lib/StdBuf.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#endif
|
||||
|
||||
class C4GLibProc: public StdSchedulerProc
|
||||
{
|
||||
public:
|
||||
C4GLibProc(GMainContext *context): context(context), query_time(C4TimeMilliseconds::NegativeInfinity) { fds.resize(1); g_main_context_ref(context); }
|
||||
~C4GLibProc()
|
||||
{
|
||||
g_main_context_unref(context);
|
||||
}
|
||||
|
||||
GMainContext *context;
|
||||
#ifdef STDSCHEDULER_USE_EVENTS
|
||||
std::vector<GPollFD> fds;
|
||||
#else
|
||||
std::vector<pollfd> fds;
|
||||
#endif
|
||||
C4TimeMilliseconds query_time;
|
||||
int timeout;
|
||||
int max_priority;
|
||||
|
||||
private:
|
||||
// Obtain the timeout and FDs from the glib mainloop. We then pass them
|
||||
// to the StdScheduler in GetFDs() and GetNextTick() so that it can
|
||||
// poll the file descriptors, along with the file descriptors from
|
||||
// other sources that it might have.
|
||||
void query(C4TimeMilliseconds Now)
|
||||
{
|
||||
// If Execute() has not yet been called, then finish the current iteration first.
|
||||
// Note that we cannot simply ignore the query() call, as new
|
||||
// FDs or Timeouts may have been added to the Glib loop in the meanwhile
|
||||
if (!query_time.IsInfinite())
|
||||
{
|
||||
//g_main_context_check(context, max_priority, fds.empty() ? NULL : (GPollFD*) &fds[0], fds.size());
|
||||
Execute();
|
||||
}
|
||||
|
||||
g_main_context_prepare (context, &max_priority);
|
||||
unsigned int fd_count;
|
||||
if (fds.empty()) fds.resize(1);
|
||||
while ((fd_count = g_main_context_query(context, max_priority, &timeout, (GPollFD*) &fds[0], fds.size())) > fds.size())
|
||||
{
|
||||
fds.resize(fd_count);
|
||||
}
|
||||
// Make sure we don't report more FDs than there are available
|
||||
fds.resize(fd_count);
|
||||
query_time = Now;
|
||||
}
|
||||
|
||||
public:
|
||||
// Iterate the Glib main loop until all pending events have been
|
||||
// processed. Don't use g_main_context_pending() directly as the
|
||||
// C4GLibProc might have initiated a loop iteration already.
|
||||
// This is mainly used to update the log in the editor window while
|
||||
// a scenario is being loaded.
|
||||
void IteratePendingEvents()
|
||||
{
|
||||
// TODO: I think we can also iterate the context manually,
|
||||
// without g_main_context_iteration. This might be less hacky.
|
||||
|
||||
// Finish current iteration first
|
||||
C4TimeMilliseconds old_query_time = C4TimeMilliseconds::NegativeInfinity;
|
||||
if (!query_time.IsInfinite())
|
||||
{
|
||||
old_query_time = query_time;
|
||||
//g_main_context_check(context, max_priority, fds.empty() ? NULL : (GPollFD*) &fds[0], fds.size());
|
||||
//query_time = C4TimeMilliseconds::NegativeInfinity;
|
||||
Execute();
|
||||
}
|
||||
|
||||
// Run the loop
|
||||
while (g_main_context_pending(context))
|
||||
g_main_context_iteration(context, false);
|
||||
|
||||
// Return to original state
|
||||
if (!old_query_time.IsInfinite())
|
||||
query(old_query_time);
|
||||
}
|
||||
|
||||
// StdSchedulerProc override
|
||||
#ifdef STDSCHEDULER_USE_EVENTS
|
||||
virtual HANDLE GetEvent()
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(fds[0].fd);
|
||||
}
|
||||
#else
|
||||
virtual void GetFDs(std::vector<struct pollfd> & rfds)
|
||||
{
|
||||
if (query_time.IsInfinite()) query(C4TimeMilliseconds::Now());
|
||||
rfds.insert(rfds.end(), fds.begin(), fds.end());
|
||||
}
|
||||
#endif
|
||||
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds Now)
|
||||
{
|
||||
query(Now);
|
||||
if (timeout < 0) return C4TimeMilliseconds::PositiveInfinity;
|
||||
return query_time + timeout;
|
||||
}
|
||||
virtual bool Execute(int iTimeout = -1, pollfd * readyfds = 0)
|
||||
{
|
||||
if (query_time.IsInfinite()) return true;
|
||||
g_main_context_check(context, max_priority, fds.empty() ? NULL : readyfds ? (GPollFD*) readyfds : (GPollFD*) &fds[0], fds.size());
|
||||
|
||||
// g_main_context_dispatch makes callbacks from the main loop.
|
||||
// We allow the callback to iterate the mainloop via
|
||||
// IteratePendingEvents so reset query_time before to not call
|
||||
// g_main_context_check() twice for the current iteration.
|
||||
// This would otherwise lead to a freeze since
|
||||
// g_main_context_check() seems to block when called twice.
|
||||
query_time = C4TimeMilliseconds::NegativeInfinity;
|
||||
g_main_context_dispatch(context);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class C4X11AppImpl
|
||||
{
|
||||
public:
|
||||
C4GLibProc GLibProc;
|
||||
C4X11AppImpl(C4AbstractApp *pApp):
|
||||
GLibProc(g_main_context_default()),
|
||||
xrandr_major_version(-1), xrandr_minor_version(-1),
|
||||
xrandr_oldmode(-1),
|
||||
xrandr_rot(0),
|
||||
xrandr_event(-1),
|
||||
argc(0), argv(0)
|
||||
{
|
||||
}
|
||||
|
||||
int xrandr_major_version, xrandr_minor_version;
|
||||
int xrandr_oldmode;
|
||||
unsigned short xrandr_rot;
|
||||
int xrandr_event;
|
||||
|
||||
int argc; char ** argv;
|
||||
};
|
||||
|
||||
C4AbstractApp::C4AbstractApp(): Active(false), fQuitMsgReceived(false),
|
||||
// main thread
|
||||
#ifdef _WIN32
|
||||
hInstance(NULL),
|
||||
idMainThread(::GetCurrentThreadId()),
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
MainThread (pthread_self()),
|
||||
#endif
|
||||
Priv(new C4X11AppImpl(this)), fDspModeSet(false)
|
||||
{
|
||||
Add(&Priv->GLibProc);
|
||||
}
|
||||
|
||||
C4AbstractApp::~C4AbstractApp()
|
||||
{
|
||||
Remove(&Priv->GLibProc);
|
||||
delete Priv;
|
||||
}
|
||||
|
||||
bool C4AbstractApp::Init(int argc, char * argv[])
|
||||
{
|
||||
// Set locale
|
||||
setlocale(LC_ALL,"");
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
GdkPixbuf* icon = gdk_pixbuf_new_from_resource("/org/openclonk/engine/oc.ico", NULL);
|
||||
gtk_window_set_default_icon(icon);
|
||||
g_object_unref(icon);
|
||||
// Try to figure out the location of the executable
|
||||
Priv->argc=argc; Priv->argv=argv;
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
int xrandr_error_base;
|
||||
if (!XRRQueryExtension(dpy, &Priv->xrandr_event, &xrandr_error_base)
|
||||
|| !XRRQueryVersion(dpy, &Priv->xrandr_major_version, &Priv->xrandr_minor_version))
|
||||
{
|
||||
Priv->xrandr_major_version = -1;
|
||||
Priv->xrandr_minor_version = 0;
|
||||
}
|
||||
if (Priv->xrandr_major_version >= 0)
|
||||
{
|
||||
XRRSelectInput(dpy, DefaultRootWindow(dpy), RRScreenChangeNotifyMask);
|
||||
}
|
||||
else
|
||||
Log("The Xrandr extension is missing. Resolution switching will not work.");
|
||||
#endif
|
||||
|
||||
// Custom initialization
|
||||
return DoInit (argc, argv);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_clipboard_store_all (void)
|
||||
{
|
||||
GtkClipboard *clipboard;
|
||||
GSList *displays, *list;
|
||||
|
||||
displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
|
||||
|
||||
list = displays;
|
||||
while (list)
|
||||
{
|
||||
GdkDisplay *display = static_cast<GdkDisplay *>(list->data);
|
||||
|
||||
clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
|
||||
|
||||
if (clipboard)
|
||||
gtk_clipboard_store (clipboard);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
g_slist_free (displays);
|
||||
|
||||
}
|
||||
|
||||
void C4AbstractApp::Clear()
|
||||
{
|
||||
gtk_clipboard_store_all();
|
||||
}
|
||||
|
||||
void C4AbstractApp::Quit()
|
||||
{
|
||||
fQuitMsgReceived = true;
|
||||
}
|
||||
|
||||
bool C4AbstractApp::FlushMessages()
|
||||
{
|
||||
// Always fail after quit message
|
||||
if (fQuitMsgReceived)
|
||||
return false;
|
||||
|
||||
Priv->GLibProc.IteratePendingEvents();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C4AbstractApp::SetVideoMode(int iXRes, int iYRes, unsigned int iRefreshRate, unsigned int iMonitor, bool fFullScreen)
|
||||
{
|
||||
if (!fFullScreen)
|
||||
{
|
||||
RestoreVideoMode();
|
||||
if (iXRes != -1)
|
||||
pWindow->SetSize(iXRes, iYRes);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
if (Priv->xrandr_major_version >= 0 && !(iXRes == -1 && iYRes == -1))
|
||||
{
|
||||
// randr spec says to always get fresh info, so don't cache.
|
||||
XRRScreenConfiguration * conf = XRRGetScreenInfo (dpy, pWindow->renderwnd);
|
||||
if (Priv->xrandr_oldmode == -1)
|
||||
Priv->xrandr_oldmode = XRRConfigCurrentConfiguration (conf, &Priv->xrandr_rot);
|
||||
int n;
|
||||
XRRScreenSize * sizes = XRRConfigSizes(conf, &n);
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (int(sizes[i].width) == iXRes && int(sizes[i].height) == iYRes)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogF("XRRSetScreenConfig %d", i);
|
||||
#endif
|
||||
fDspModeSet = XRRSetScreenConfig(dpy, conf, pWindow->renderwnd, i, Priv->xrandr_rot, CurrentTime) == RRSetConfigSuccess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XRRFreeScreenConfigInfo(conf);
|
||||
}
|
||||
#endif
|
||||
gtk_window_fullscreen(GTK_WINDOW(pWindow->window));
|
||||
return fDspModeSet || (iXRes == -1 && iYRes == -1);
|
||||
}
|
||||
|
||||
void C4AbstractApp::RestoreVideoMode()
|
||||
{
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
// Restore resolution
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
if (fDspModeSet && Priv->xrandr_major_version >= 0 && Priv->xrandr_oldmode != -1)
|
||||
{
|
||||
XRRScreenConfiguration * conf = XRRGetScreenInfo (dpy, pWindow->renderwnd);
|
||||
#ifdef _DEBUG
|
||||
LogF("XRRSetScreenConfig %d (back)", Priv->xrandr_oldmode);
|
||||
#endif
|
||||
XRRSetScreenConfig (dpy, conf, pWindow->renderwnd, Priv->xrandr_oldmode, Priv->xrandr_rot, CurrentTime);
|
||||
Priv->xrandr_oldmode = -1;
|
||||
XRRFreeScreenConfigInfo(conf);
|
||||
fDspModeSet = false;
|
||||
}
|
||||
#endif
|
||||
// pWindow may be unset when C4AbstractApp gets destroyed during the
|
||||
// initialization code, before a window has been created
|
||||
if (pWindow)
|
||||
gtk_window_unfullscreen(GTK_WINDOW(pWindow->window));
|
||||
}
|
||||
|
||||
bool C4AbstractApp::GetIndexedDisplayMode(int32_t iIndex, int32_t *piXRes, int32_t *piYRes, int32_t *piBitDepth, int32_t *piRefreshRate, uint32_t iMonitor)
|
||||
{
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
int n;
|
||||
XRRScreenSize * sizes = XRRSizes(dpy, XDefaultScreen(dpy), &n);
|
||||
if (iIndex < n && iIndex >= 0)
|
||||
{
|
||||
*piXRes = sizes[iIndex].width;
|
||||
*piYRes = sizes[iIndex].height;
|
||||
*piBitDepth = 32;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Copy the text to the clipboard or the primary selection
|
||||
bool C4AbstractApp::Copy(const StdStrBuf & text, bool fClipboard)
|
||||
{
|
||||
gtk_clipboard_set_text(gtk_clipboard_get(fClipboard ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY),
|
||||
text.getData(), text.getLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Paste the text from the clipboard or the primary selection
|
||||
StdStrBuf C4AbstractApp::Paste(bool fClipboard)
|
||||
{
|
||||
char * r = gtk_clipboard_wait_for_text(gtk_clipboard_get(fClipboard ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY));
|
||||
// gtk_clipboard_request_text(gtk_clipboard_get(fClipboard ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY),
|
||||
// GtkClipboardTextReceivedFunc callback, gpointer user_data);
|
||||
StdStrBuf rbuf;
|
||||
rbuf.Copy(r);
|
||||
g_free(r);
|
||||
return rbuf;
|
||||
}
|
||||
|
||||
// Is there something in the clipboard?
|
||||
bool C4AbstractApp::IsClipboardFull(bool fClipboard)
|
||||
{
|
||||
return gtk_clipboard_wait_is_text_available(gtk_clipboard_get(fClipboard ? GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY));
|
||||
}
|
||||
|
||||
void C4AbstractApp::MessageDialog(const char * message)
|
||||
{
|
||||
GtkWidget * dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", message);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), "OpenClonk Error");
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
|
@ -21,18 +21,7 @@
|
|||
|
||||
#include "lib/StdBuf.h"
|
||||
|
||||
#if defined(USE_GTK)
|
||||
#ifdef _WIN32
|
||||
#undef MK_CONTROL
|
||||
#undef MK_SHIFT
|
||||
#endif
|
||||
// from X.h:
|
||||
//#define ShiftMask (1<<0)
|
||||
//#define ControlMask (1<<2)
|
||||
#define MK_CONTROL (1<<2)
|
||||
#define MK_SHIFT (1<<0)
|
||||
#define MK_ALT (1<<3)
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
#if defined(USE_SDL_MAINLOOP)
|
||||
#include <SDL.h>
|
||||
#define MK_SHIFT (KMOD_LSHIFT | KMOD_RSHIFT)
|
||||
#define MK_CONTROL (KMOD_LCTRL | KMOD_RCTRL)
|
||||
|
@ -59,7 +48,7 @@ extern int MK_ALT;
|
|||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_WIN32_WINDOWS) || defined(USE_GTK) || defined(USE_CONSOLE) || defined(USE_SDL_MAINLOOP)
|
||||
#if defined(USE_WIN32_WINDOWS) || defined(USE_CONSOLE) || defined(USE_SDL_MAINLOOP)
|
||||
#define K_ESCAPE 1
|
||||
#define K_1 2
|
||||
#define K_2 3
|
||||
|
@ -267,10 +256,6 @@ extern C4KeyCode K_PRINT;
|
|||
extern C4KeyCode K_CENTER;
|
||||
#endif
|
||||
|
||||
#ifdef USE_GTK
|
||||
// Forward declaration because xlib.h is evil
|
||||
typedef struct __GLXFBConfigRec *GLXFBConfig;
|
||||
#endif
|
||||
|
||||
class C4Window
|
||||
#ifdef USE_COCOA
|
||||
|
@ -325,33 +310,17 @@ public:
|
|||
#if defined(USE_WIN32_WINDOWS)
|
||||
HWND hWindow;
|
||||
virtual bool Win32DialogMessageHandling(MSG * msg) { return false; };
|
||||
#elif defined(USE_GTK)
|
||||
/*GtkWidget*/void * window;
|
||||
// Set by Init to the widget which is used as a
|
||||
// render target, which can be the whole window.
|
||||
/*GtkWidget*/void * render_widget;
|
||||
// Mouse grabbing has to be restored when the window gains focus.
|
||||
bool mouse_was_grabbed = false;
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
SDL_Window * window;
|
||||
void HandleSDLEvent(SDL_WindowEvent &e);
|
||||
#endif
|
||||
#ifdef USE_WGL
|
||||
HWND renderwnd;
|
||||
#elif defined(USE_GTK)
|
||||
unsigned long renderwnd;
|
||||
#endif
|
||||
#ifdef WITH_QT_EDITOR
|
||||
class QOpenGLWidget *glwidget;
|
||||
#endif
|
||||
protected:
|
||||
#if defined(USE_GTK)
|
||||
bool FindFBConfig(int samples, GLXFBConfig *info);
|
||||
|
||||
// The GLXFBConfig the window was created with
|
||||
GLXFBConfig Info;
|
||||
unsigned long handlerDestroy;
|
||||
#endif
|
||||
virtual C4Window * Init(WindowKind windowKind, C4AbstractApp * pApp, const char * Title, const C4Rect * size);
|
||||
friend class C4Draw;
|
||||
friend class CStdGL;
|
||||
|
|
|
@ -1,949 +0,0 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
|
||||
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
|
||||
*
|
||||
* Distributed under the terms of the ISC license; see accompanying file
|
||||
* "COPYING" for details.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
||||
* See accompanying file "TRADEMARK" for details.
|
||||
*
|
||||
* To redistribute this file separately, substitute the full license texts
|
||||
* for the above references.
|
||||
*/
|
||||
|
||||
/* A wrapper class to OS dependent event and window interfaces, GTK+ version */
|
||||
|
||||
#include "C4Include.h"
|
||||
#include "platform/C4Window.h"
|
||||
|
||||
#include "platform/C4App.h"
|
||||
#include "C4Version.h"
|
||||
#include "config/C4Config.h"
|
||||
|
||||
#include "graphics/C4DrawGL.h"
|
||||
#include "graphics/C4Draw.h"
|
||||
#include "platform/StdFile.h"
|
||||
#include "lib/StdBuf.h"
|
||||
|
||||
#include "lib/C4Rect.h"
|
||||
|
||||
#include "editor/C4Console.h"
|
||||
#include "editor/C4ViewportWindow.h"
|
||||
#include "game/C4Viewport.h"
|
||||
#include "gui/C4MouseControl.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
// Some helper functions for choosing a proper visual
|
||||
|
||||
namespace {
|
||||
static const std::map<int, int> base_attrib_map {
|
||||
{GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT},
|
||||
{GLX_X_RENDERABLE, True},
|
||||
{GLX_RED_SIZE, 4},
|
||||
{GLX_GREEN_SIZE, 4},
|
||||
{GLX_BLUE_SIZE, 4},
|
||||
{GLX_DEPTH_SIZE, 8}
|
||||
};
|
||||
|
||||
// Turns an int->int map into an attribute list suitable for any GLX calls.
|
||||
std::unique_ptr<int[]> MakeGLXAttribList(const std::map<int, int> &map)
|
||||
{
|
||||
// We need two ints for every attribute, plus one as a sentinel
|
||||
auto list = std::make_unique<int[]>(map.size() * 2 + 1);
|
||||
int *cursor = list.get();
|
||||
for(const auto &attrib : map)
|
||||
{
|
||||
*cursor++ = attrib.first;
|
||||
*cursor++ = attrib.second;
|
||||
}
|
||||
*cursor = None;
|
||||
return list;
|
||||
}
|
||||
|
||||
// This function picks an acceptable GLXFBConfig. To do this, we first
|
||||
// request a list of framebuffer configs with no less than 4 bits per color;
|
||||
// no less than 8 bits of depth buffer; if multisampling is not -1,
|
||||
// with at least the requested number of samples; and with double buffering.
|
||||
// If that returns no suitable configs, we retry with only a single buffer.
|
||||
GLXFBConfig PickGLXFBConfig(Display* dpy, int multisampling)
|
||||
{
|
||||
std::map<int, int> attrib_map = base_attrib_map;
|
||||
|
||||
if (multisampling >= 0)
|
||||
{
|
||||
attrib_map[GLX_SAMPLE_BUFFERS] = multisampling > 0 ? 1 : 0;
|
||||
attrib_map[GLX_SAMPLES] = multisampling;
|
||||
}
|
||||
|
||||
GLXFBConfig *configs = NULL;
|
||||
int config_count;
|
||||
// Find a double-buffered FB config
|
||||
attrib_map[GLX_DOUBLEBUFFER] = True;
|
||||
std::unique_ptr<int[]> attribs = MakeGLXAttribList(attrib_map);
|
||||
configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs.get(), &config_count);
|
||||
if (config_count == 0)
|
||||
{
|
||||
// If none exists, try to find a single-buffered one
|
||||
if (configs != NULL)
|
||||
XFree(configs);
|
||||
attrib_map[GLX_DOUBLEBUFFER] = False;
|
||||
attribs = MakeGLXAttribList(attrib_map);
|
||||
configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs.get(), &config_count);
|
||||
}
|
||||
|
||||
GLXFBConfig config = NULL;
|
||||
if (config_count > 0)
|
||||
{
|
||||
config = configs[0];
|
||||
}
|
||||
|
||||
XFree(configs);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
#elif defined(GDK_WINDOWING_WIN32)
|
||||
#include "platform/C4windowswrapper.h"
|
||||
#include <gdk/gdkwin32.h>
|
||||
#endif // GDK_WINDOWING_X11
|
||||
|
||||
static void OnDestroyStatic(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
C4Window* wnd = static_cast<C4Window*>(data);
|
||||
wnd->Clear();
|
||||
}
|
||||
|
||||
static gboolean OnDelete(GtkWidget* widget, GdkEvent* event, gpointer data)
|
||||
{
|
||||
C4Window* wnd = static_cast<C4Window*>(data);
|
||||
wnd->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
static constexpr int x11scancodeoffset = 8;
|
||||
#else
|
||||
static constexpr int x11scancodeoffset = 0;
|
||||
#endif
|
||||
|
||||
static gboolean OnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer data)
|
||||
{
|
||||
C4Window* wnd = static_cast<C4Window*>(data);
|
||||
if (event->hardware_keycode <= x11scancodeoffset) return false;
|
||||
Game.DoKeyboardInput(event->hardware_keycode - x11scancodeoffset, KEYEV_Down,
|
||||
!!(event->state & GDK_MOD1_MASK),
|
||||
!!(event->state & GDK_CONTROL_MASK),
|
||||
!!(event->state & GDK_SHIFT_MASK), false, NULL);
|
||||
wnd->CharIn(event->string); // FIXME: Use GtkIMContext somehow
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnKeyRelease(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
|
||||
{
|
||||
if (event->hardware_keycode <= x11scancodeoffset) return false;
|
||||
Game.DoKeyboardInput(event->hardware_keycode - x11scancodeoffset, KEYEV_Up,
|
||||
!!(event->state & GDK_MOD1_MASK),
|
||||
!!(event->state & GDK_CONTROL_MASK),
|
||||
!!(event->state & GDK_SHIFT_MASK), false, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void OnDragDataReceivedStatic(GtkWidget* widget, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint info, guint time, gpointer user_data)
|
||||
{
|
||||
if (!Console.Editing) { Console.Message(LoadResStr("IDS_CNS_NONETEDIT")); return; }
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
|
||||
gchar** uris = gtk_selection_data_get_uris(data);
|
||||
if (!uris) return;
|
||||
|
||||
for (gchar** uri = uris; *uri != NULL; ++ uri)
|
||||
{
|
||||
gchar* file = g_filename_from_uri(*uri, NULL, NULL);
|
||||
if (!file) continue;
|
||||
|
||||
window->cvp->DropFile(file, x, y);
|
||||
g_free(file);
|
||||
}
|
||||
|
||||
g_strfreev(uris);
|
||||
}
|
||||
|
||||
static gboolean OnExposeStatic(GtkWidget* widget, void *, gpointer user_data)
|
||||
{
|
||||
C4Viewport* cvp = static_cast<C4ViewportWindow*>(user_data)->cvp;
|
||||
cvp->Execute();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void OnRealizeStatic(GtkWidget* widget, gpointer user_data)
|
||||
{
|
||||
// Initial PlayerLock
|
||||
if (static_cast<C4ViewportWindow*>(user_data)->cvp->GetPlayerLock())
|
||||
{
|
||||
gtk_widget_hide(static_cast<C4ViewportWindow*>(user_data)->h_scrollbar);
|
||||
gtk_widget_hide(static_cast<C4ViewportWindow*>(user_data)->v_scrollbar);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean OnKeyPressStatic(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
|
||||
{
|
||||
if (event->keyval == GDK_KEY_Scroll_Lock)
|
||||
{
|
||||
static_cast<C4ViewportWindow*>(user_data)->cvp->TogglePlayerLock();
|
||||
return true;
|
||||
}
|
||||
if (event->hardware_keycode <= x11scancodeoffset) return false;
|
||||
Console.EditCursor.KeyDown(event->hardware_keycode - x11scancodeoffset, event->state);
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean OnKeyReleaseStatic(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
|
||||
{
|
||||
if (event->hardware_keycode <= x11scancodeoffset) return false;
|
||||
Console.EditCursor.KeyUp(event->hardware_keycode - x11scancodeoffset, event->state);
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean OnScrollVW(GtkWidget* widget, GdkEventScroll* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
|
||||
if (::MouseControl.IsViewport(window->cvp) && (Console.EditCursor.GetMode()==C4CNS_ModePlay))
|
||||
{
|
||||
switch (event->direction)
|
||||
{
|
||||
case GDK_SCROLL_UP:
|
||||
C4GUI::MouseMove(C4MC_Button_Wheel, (int32_t)event->x, (int32_t)event->y, event->state + (short(1) << 16), window->cvp);
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
C4GUI::MouseMove(C4MC_Button_Wheel, (int32_t)event->x, (int32_t)event->y, event->state + (short(-1) << 16), window->cvp);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnButtonPressStatic(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
|
||||
if (::MouseControl.IsViewport(window->cvp) && (Console.EditCursor.GetMode()==C4CNS_ModePlay))
|
||||
{
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_LeftDown, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
else if (event->type == GDK_2BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_LeftDouble, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
case 2:
|
||||
C4GUI::MouseMove(C4MC_Button_MiddleDown, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
case 3:
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_RightDown, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
else if (event->type == GDK_2BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_RightDouble, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
Console.EditCursor.LeftButtonDown(event->state);
|
||||
break;
|
||||
case 3:
|
||||
Console.EditCursor.RightButtonDown(event->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnButtonReleaseStatic(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
|
||||
if (::MouseControl.IsViewport(window->cvp) && (Console.EditCursor.GetMode()==C4CNS_ModePlay))
|
||||
{
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
C4GUI::MouseMove(C4MC_Button_LeftUp, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
case 2:
|
||||
C4GUI::MouseMove(C4MC_Button_MiddleUp, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
case 3:
|
||||
C4GUI::MouseMove(C4MC_Button_RightUp, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
Console.EditCursor.LeftButtonUp(event->state);
|
||||
break;
|
||||
case 3:
|
||||
Console.EditCursor.RightButtonUp(event->state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnMotionNotifyStatic(GtkWidget* widget, GdkEventMotion* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
|
||||
if (::MouseControl.IsViewport(window->cvp) && (Console.EditCursor.GetMode()==C4CNS_ModePlay))
|
||||
{
|
||||
C4GUI::MouseMove(C4MC_Button_None, (int32_t)event->x, (int32_t)event->y, event->state, window->cvp);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->EditCursorMove(event->x, event->y, event->state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnConfigureStatic(GtkWidget* widget, GdkEventConfigure* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
C4Viewport* cvp = window->cvp;
|
||||
|
||||
//cvp->UpdateOutputSize();
|
||||
cvp->ScrollBarsByViewPosition();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean OnConfigureDareaStatic(GtkWidget* widget, GdkEventConfigure* event, gpointer user_data)
|
||||
{
|
||||
C4ViewportWindow* window = static_cast<C4ViewportWindow*>(user_data);
|
||||
C4Viewport* cvp = window->cvp;
|
||||
|
||||
cvp->UpdateOutputSize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void OnVScrollStatic(GtkAdjustment* adjustment, gpointer user_data)
|
||||
{
|
||||
static_cast<C4ViewportWindow*>(user_data)->cvp->ViewPositionByScrollBars();
|
||||
}
|
||||
|
||||
static void OnHScrollStatic(GtkAdjustment* adjustment, gpointer user_data)
|
||||
{
|
||||
static_cast<C4ViewportWindow*>(user_data)->cvp->ViewPositionByScrollBars();
|
||||
}
|
||||
|
||||
static GtkTargetEntry drag_drop_entries[] =
|
||||
{
|
||||
{ const_cast<gchar*>("text/uri-list"), 0, 0 }
|
||||
};
|
||||
|
||||
static gboolean OnConfigureNotify(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
||||
{
|
||||
Application.OnResolutionChanged(event->configure.width, event->configure.height);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool fullscreen_needs_restore = false;
|
||||
static gboolean fullscreen_restore(gpointer data)
|
||||
{
|
||||
if (fullscreen_needs_restore)
|
||||
Application.SetVideoMode(Application.GetConfigWidth(), Application.GetConfigHeight(), Config.Graphics.RefreshRate, Config.Graphics.Monitor, Application.FullScreenMode());
|
||||
fullscreen_needs_restore = false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool grab_mouse(GtkWidget *widget)
|
||||
{
|
||||
// This should be possible with pure GTK code as well, using
|
||||
// gdk_device_grab(). However, while gdk_device_grab() will prevent clicks
|
||||
// outside of the game window, the mouse gets stuck near the edge of the
|
||||
// window when trying to move outside.
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
Window xwindow = gdk_x11_window_get_xid(gtk_widget_get_window(widget));
|
||||
int result = XGrabPointer(dpy, xwindow, true, 0, GrabModeAsync, GrabModeAsync, xwindow, None, CurrentTime);
|
||||
return result == GrabSuccess;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ungrab_mouse()
|
||||
{
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean grab_mouse_fn(gpointer user_data)
|
||||
{
|
||||
// Grabbing may not be possible immediately after focusing the window, so
|
||||
// try again if we don't succeed.
|
||||
return !grab_mouse((GtkWidget*) user_data);
|
||||
}
|
||||
|
||||
static gboolean OnFocusInFS(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
||||
{
|
||||
Application.Active = true;
|
||||
if (Application.FullScreenMode())
|
||||
{
|
||||
fullscreen_needs_restore = true;
|
||||
gdk_threads_add_idle(fullscreen_restore, NULL);
|
||||
}
|
||||
C4Window *window = (C4Window*) user_data;
|
||||
if (window->mouse_was_grabbed)
|
||||
gdk_threads_add_timeout(50, grab_mouse_fn, widget);
|
||||
// Reset urgency hint (does nothing if unset)
|
||||
assert(widget == window->window && "OnFocusInFS callback used for something other than the main window.");
|
||||
gtk_window_set_urgency_hint(GTK_WINDOW(window->window), false);
|
||||
return false;
|
||||
}
|
||||
static gboolean OnFocusOutFS(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
||||
{
|
||||
Application.Active = false;
|
||||
if (Application.FullScreenMode() && Application.GetConfigWidth() != -1)
|
||||
{
|
||||
Application.RestoreVideoMode();
|
||||
gtk_window_iconify(GTK_WINDOW(widget));
|
||||
fullscreen_needs_restore = false;
|
||||
}
|
||||
ungrab_mouse();
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean OnButtonPressFS(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_LeftDown, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
else if (event->type == GDK_2BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_LeftDouble, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
break;
|
||||
case 2:
|
||||
C4GUI::MouseMove(C4MC_Button_MiddleDown, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
break;
|
||||
case 3:
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_RightDown, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
else if (event->type == GDK_2BUTTON_PRESS)
|
||||
C4GUI::MouseMove(C4MC_Button_RightDouble, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gboolean OnButtonRelease(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
int b;
|
||||
switch (event->button)
|
||||
{
|
||||
case 1: b = C4MC_Button_LeftUp; break;
|
||||
case 2: b = C4MC_Button_MiddleUp; break;
|
||||
case 3: b = C4MC_Button_RightUp; break;
|
||||
default: return false;
|
||||
}
|
||||
C4GUI::MouseMove(b, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::MouseMove(C4MC_Button_None, (int32_t)event->x, (int32_t)event->y, event->state, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnScroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::DialogWindow * window = static_cast<C4GUI::DialogWindow*>(user_data);
|
||||
C4GUI::Dialog *pDlg = ::pGUI->GetDialog(window);
|
||||
int idy;
|
||||
switch (event->direction)
|
||||
{
|
||||
case GDK_SCROLL_UP: idy = 32; break;
|
||||
case GDK_SCROLL_DOWN: idy = -32; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// FIXME: make the GUI api less insane here
|
||||
if (pDlg)
|
||||
::pGUI->MouseInput(C4MC_Button_Wheel, event->x, event->y, event->state + (idy << 16), pDlg, NULL);
|
||||
else
|
||||
C4GUI::MouseMove(C4MC_Button_Wheel, event->x, event->y, event->state + (idy << 16), NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnButtonPressGD(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::DialogWindow * window = static_cast<C4GUI::DialogWindow*>(user_data);
|
||||
C4GUI::Dialog *pDlg = ::pGUI->GetDialog(window);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
if (event->type == GDK_2BUTTON_PRESS)
|
||||
{
|
||||
::pGUI->MouseInput(C4MC_Button_LeftDouble, event->x, event->y, event->state, pDlg, NULL);
|
||||
}
|
||||
else if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
::pGUI->MouseInput(C4MC_Button_LeftDown,event->x, event->y, event->state, pDlg, NULL);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
::pGUI->MouseInput(C4MC_Button_MiddleDown, event->x, event->y, event->state, pDlg, NULL);
|
||||
break;
|
||||
case 3:
|
||||
if (event->type == GDK_2BUTTON_PRESS)
|
||||
{
|
||||
::pGUI->MouseInput(C4MC_Button_RightDouble, event->x, event->y, event->state, pDlg, NULL);
|
||||
}
|
||||
else if (event->type == GDK_BUTTON_PRESS)
|
||||
{
|
||||
::pGUI->MouseInput(C4MC_Button_RightDown, event->x, event->y, event->state, pDlg, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnButtonReleaseGD(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::DialogWindow * window = static_cast<C4GUI::DialogWindow*>(user_data);
|
||||
C4GUI::Dialog *pDlg = ::pGUI->GetDialog(window);
|
||||
|
||||
switch (event->button)
|
||||
{
|
||||
case 1:
|
||||
::pGUI->MouseInput(C4MC_Button_LeftUp, event->x, event->y, event->state, pDlg, NULL);
|
||||
break;
|
||||
case 2:
|
||||
::pGUI->MouseInput(C4MC_Button_MiddleUp, event->x, event->y, event->state, pDlg, NULL);
|
||||
break;
|
||||
case 3:
|
||||
::pGUI->MouseInput(C4MC_Button_RightUp, event->x, event->y, event->state, pDlg, NULL);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnMotionNotifyGD(GtkWidget* widget, GdkEventMotion* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::DialogWindow * window = static_cast<C4GUI::DialogWindow*>(user_data);
|
||||
C4GUI::Dialog *pDlg = ::pGUI->GetDialog(window);
|
||||
|
||||
::pGUI->MouseInput(C4MC_Button_None, event->x, event->y, event->state, pDlg, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean OnConfigureGD(GtkWidget* widget, GdkEventConfigure* event, gpointer user_data)
|
||||
{
|
||||
C4GUI::DialogWindow * window = static_cast<C4GUI::DialogWindow*>(user_data);
|
||||
|
||||
window->pSurface->UpdateSize(event->width, event->height);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
C4Window::C4Window ():
|
||||
Active(false), pSurface(0),
|
||||
renderwnd(0), Info(0), window(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
C4Window::~C4Window ()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
bool C4Window::FindFBConfig(int samples, GLXFBConfig *info)
|
||||
{
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
GLXFBConfig config = PickGLXFBConfig(dpy, samples);
|
||||
if (info)
|
||||
{
|
||||
*info = config;
|
||||
}
|
||||
return config != NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void C4Window::EnumerateMultiSamples(std::vector<int>& samples) const
|
||||
{
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
std::map<int, int> attribs = base_attrib_map;
|
||||
attribs[GLX_SAMPLE_BUFFERS_ARB] = 1;
|
||||
|
||||
int config_count = 0;
|
||||
GLXFBConfig *configs = glXChooseFBConfig(dpy, DefaultScreen(dpy), MakeGLXAttribList(attribs).get(), &config_count);
|
||||
|
||||
std::set<int> multisamples;
|
||||
for(int i = 0; i < config_count; ++i)
|
||||
{
|
||||
int v_samples;
|
||||
glXGetFBConfigAttrib(dpy, configs[i], GLX_SAMPLES, &v_samples);
|
||||
multisamples.insert(v_samples);
|
||||
}
|
||||
|
||||
XFree(configs);
|
||||
samples.assign(multisamples.cbegin(), multisamples.cend());
|
||||
#else
|
||||
if(pGL && pGL->pMainCtx)
|
||||
samples = pGL->pMainCtx->EnumerateMultiSamples();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool C4Window::StorePosition(const char *, const char *, bool) { return true; }
|
||||
|
||||
bool C4Window::RestorePosition(const char *, const char *, bool)
|
||||
{
|
||||
// The Windowmanager is responsible for window placement.
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4Window::FlashWindow()
|
||||
{
|
||||
gtk_window_set_urgency_hint(GTK_WINDOW(window), true);
|
||||
}
|
||||
|
||||
void C4Window::GrabMouse(bool grab)
|
||||
{
|
||||
if (grab)
|
||||
{
|
||||
// Don't grab the mouse while the game window isn't focused.
|
||||
if (Application.Active)
|
||||
grab_mouse(GTK_WIDGET(window));
|
||||
mouse_was_grabbed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ungrab_mouse();
|
||||
mouse_was_grabbed = false;
|
||||
}
|
||||
}
|
||||
|
||||
C4Window* C4Window::Init(WindowKind windowKind, C4AbstractApp * pApp, const char * Title, const C4Rect * size)
|
||||
{
|
||||
Active = true;
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
if(!FindFBConfig(Config.Graphics.MultiSampling, &Info))
|
||||
{
|
||||
// Disable multisampling if we don't find a visual which
|
||||
// supports the currently configured setting.
|
||||
if(!FindFBConfig(0, &Info)) return NULL;
|
||||
Config.Graphics.MultiSampling = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(!window);
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
if (windowKind == W_Viewport)
|
||||
{
|
||||
C4ViewportWindow * vw = static_cast<C4ViewportWindow *>(this);
|
||||
|
||||
// Cannot just use ScrolledWindow because this would just move
|
||||
// the GdkWindow of the DrawingArea.
|
||||
GtkWidget* table = gtk_grid_new();
|
||||
render_widget = gtk_drawing_area_new();
|
||||
gtk_widget_set_hexpand(GTK_WIDGET(render_widget), true);
|
||||
gtk_widget_set_vexpand(GTK_WIDGET(render_widget), true);
|
||||
gtk_grid_attach(GTK_GRID(table), GTK_WIDGET(render_widget), 0, 0, 1, 1);
|
||||
vw->h_scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
|
||||
gtk_grid_attach(GTK_GRID(table), vw->h_scrollbar, 0, 1, 1, 1);
|
||||
vw->v_scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
|
||||
gtk_grid_attach(GTK_GRID(table), vw->v_scrollbar, 1, 0, 1, 1);
|
||||
|
||||
GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(vw->h_scrollbar));
|
||||
|
||||
g_signal_connect(
|
||||
G_OBJECT(adjustment),
|
||||
"value-changed",
|
||||
G_CALLBACK(OnHScrollStatic),
|
||||
this
|
||||
);
|
||||
|
||||
adjustment = gtk_range_get_adjustment(GTK_RANGE(vw->v_scrollbar));
|
||||
|
||||
g_signal_connect(
|
||||
G_OBJECT(adjustment),
|
||||
"value-changed",
|
||||
G_CALLBACK(OnVScrollStatic),
|
||||
this
|
||||
);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), table);
|
||||
|
||||
gtk_widget_add_events(GTK_WIDGET(window), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK | GDK_POINTER_MOTION_MASK);
|
||||
|
||||
gtk_drag_dest_set(GTK_WIDGET(render_widget), GTK_DEST_DEFAULT_ALL, drag_drop_entries, 1, GDK_ACTION_COPY);
|
||||
g_signal_connect(G_OBJECT(render_widget), "drag-data-received", G_CALLBACK(OnDragDataReceivedStatic), this);
|
||||
g_signal_connect(G_OBJECT(render_widget), "draw", G_CALLBACK(OnExposeStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(OnKeyPressStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(OnKeyReleaseStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "scroll-event", G_CALLBACK(OnScrollVW), this);
|
||||
g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(OnButtonPressStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "button-release-event", G_CALLBACK(OnButtonReleaseStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "motion-notify-event", G_CALLBACK(OnMotionNotifyStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(OnKeyPress), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(OnKeyRelease), this);
|
||||
g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(OnConfigureStatic), this);
|
||||
g_signal_connect(G_OBJECT(window), "realize", G_CALLBACK(OnRealizeStatic), this);
|
||||
|
||||
g_signal_connect_after(G_OBJECT(render_widget), "configure-event", G_CALLBACK(OnConfigureDareaStatic), this);
|
||||
|
||||
#if !GTK_CHECK_VERSION(3,10,0)
|
||||
// do not draw the default background
|
||||
gtk_widget_set_double_buffered (GTK_WIDGET(render_widget), false);
|
||||
#endif
|
||||
|
||||
gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(Console.window));
|
||||
#if !GTK_CHECK_VERSION(3,14,0)
|
||||
gtk_window_set_has_resize_grip(GTK_WINDOW(window), false);
|
||||
#endif
|
||||
}
|
||||
else if (windowKind == W_Fullscreen)
|
||||
{
|
||||
render_widget = gtk_drawing_area_new();
|
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(render_widget));
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(OnConfigureNotify), this);
|
||||
g_signal_connect(G_OBJECT(window), "focus-in-event", G_CALLBACK(OnFocusInFS), this);
|
||||
g_signal_connect(G_OBJECT(window), "focus-out-event", G_CALLBACK(OnFocusOutFS), this);
|
||||
g_signal_connect(G_OBJECT(window), "unmap-event", G_CALLBACK(OnFocusOutFS), this);
|
||||
g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(OnButtonPressFS), this);
|
||||
g_signal_connect(G_OBJECT(window), "button-release-event", G_CALLBACK(OnButtonRelease), this);
|
||||
g_signal_connect(G_OBJECT(window), "motion-notify-event", G_CALLBACK(OnMotionNotify), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(OnKeyPress), this);
|
||||
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(OnKeyRelease), this);
|
||||
g_signal_connect(G_OBJECT(window), "scroll-event", G_CALLBACK(OnScroll), this);
|
||||
gtk_widget_add_events(GTK_WIDGET(window), GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
#if !GTK_CHECK_VERSION(3,10,0)
|
||||
gtk_widget_set_double_buffered (GTK_WIDGET(render_widget), false);
|
||||
#endif
|
||||
|
||||
GValue val = {0,{{0}}};
|
||||
g_value_init (&val, G_TYPE_BOOLEAN);
|
||||
g_value_set_boolean (&val, true);
|
||||
g_object_set_property (G_OBJECT (render_widget), "can-focus", &val);
|
||||
g_object_set_property (G_OBJECT (window), "can-focus", &val);
|
||||
g_value_unset (&val);
|
||||
#if !GTK_CHECK_VERSION(3,14,0)
|
||||
gtk_window_set_has_resize_grip(GTK_WINDOW(window), false);
|
||||
#endif
|
||||
}
|
||||
else if (windowKind == W_GuiWindow)
|
||||
{
|
||||
render_widget = window;
|
||||
g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(OnButtonPressGD), this);
|
||||
g_signal_connect(G_OBJECT(window), "button-release-event", G_CALLBACK(OnButtonReleaseGD), this);
|
||||
g_signal_connect(G_OBJECT(window), "motion-notify-event", G_CALLBACK(OnMotionNotifyGD), this);
|
||||
g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(OnConfigureGD), this);
|
||||
g_signal_connect(G_OBJECT(window), "scroll-event", G_CALLBACK(OnScroll), this);
|
||||
|
||||
gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(Console.window));
|
||||
#if !GTK_CHECK_VERSION(3,14,0)
|
||||
gtk_window_set_has_resize_grip(GTK_WINDOW(window), false);
|
||||
#endif
|
||||
}
|
||||
else if (windowKind == W_Console)
|
||||
{
|
||||
render_widget = window;
|
||||
}
|
||||
assert(window);
|
||||
assert(render_widget);
|
||||
// Override gtk's default to match name/class of the XLib windows
|
||||
gtk_window_set_wmclass(GTK_WINDOW(window), C4ENGINENAME, C4ENGINENAME);
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), size->Wdt, size->Hgt);
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(OnDelete), this);
|
||||
handlerDestroy = g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(OnDestroyStatic), this);
|
||||
gtk_widget_add_events(GTK_WIDGET(window), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK);
|
||||
|
||||
// TODO: It would be nice to support GDK_SCROLL_SMOOTH_MASK and
|
||||
// smooth scrolling for scrolling in menus, however that should not
|
||||
// change the scroll wheel behaviour ingame for zooming or
|
||||
// inventory change. Note that when both GDK_SCROLL_MASK and
|
||||
// GDK_SMOOTH_SCROLL_MASK are enabled, both type of scroll events
|
||||
// are reported, so one needs to make sure to not double-process them.
|
||||
// It would be nice to have smooth scrolling also e.g. for zooming
|
||||
// ingame, but it probably requires the notion of smooth scrolling
|
||||
// other parts of the engine as well.
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GdkScreen * scr = gtk_widget_get_screen(GTK_WIDGET(render_widget));
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
XVisualInfo *vis_info = glXGetVisualFromFBConfig(dpy, Info);
|
||||
assert(vis_info);
|
||||
GdkVisual * vis = gdk_x11_screen_lookup_visual(scr, vis_info->visualid);
|
||||
XFree(vis_info);
|
||||
gtk_widget_set_visual(GTK_WIDGET(render_widget),vis);
|
||||
#endif
|
||||
gtk_widget_show_all(GTK_WIDGET(window));
|
||||
|
||||
// XVisualInfo vitmpl; int blub;
|
||||
// vitmpl.visual = gdk_x11_visual_get_xvisual(gtk_widget_get_visual(window));
|
||||
// vitmpl.visualid = XVisualIDFromVisual(vitmpl.visual);
|
||||
// Info = XGetVisualInfo(dpy, VisualIDMask, &vitmpl, &blub);
|
||||
|
||||
// printf("%p\n", gtk_widget_get_visual(render_widget));
|
||||
// Info = gdk_x11_visual_get_xvisual(gtk_widget_get_visual(render_widget));
|
||||
|
||||
// Default icon has been set right after gtk_init(),
|
||||
// so we don't need to take care about setting the icon here.
|
||||
|
||||
SetTitle(Title);
|
||||
|
||||
// Wait until window is mapped to get the window's XID
|
||||
gtk_widget_show_now(GTK_WIDGET(window));
|
||||
GdkWindow* render_gdk_wnd;
|
||||
if (GTK_IS_LAYOUT(render_widget))
|
||||
render_gdk_wnd = gtk_layout_get_bin_window(GTK_LAYOUT(render_widget));
|
||||
else
|
||||
render_gdk_wnd = gtk_widget_get_window(GTK_WIDGET(render_widget));
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
renderwnd = GDK_WINDOW_XID(render_gdk_wnd);
|
||||
#elif defined(GDK_WINDOWING_WIN32)
|
||||
renderwnd = reinterpret_cast<HWND>(gdk_win32_window_get_handle(render_gdk_wnd));
|
||||
#endif
|
||||
// Make sure the window is shown and ready to be rendered into,
|
||||
// this avoids an async X error.
|
||||
gdk_flush();
|
||||
|
||||
if (windowKind == W_Fullscreen)
|
||||
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(render_widget)),
|
||||
gdk_cursor_new_for_display(gdk_display_get_default(), GDK_BLANK_CURSOR));
|
||||
return this;
|
||||
}
|
||||
|
||||
bool C4Window::ReInit(C4AbstractApp* pApp)
|
||||
{
|
||||
// Check whether multisampling settings was changed. If not then we
|
||||
// don't need to ReInit anything.
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
int value;
|
||||
Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
||||
glXGetFBConfigAttrib(dpy, Info, GLX_SAMPLES, &value);
|
||||
if(value == Config.Graphics.MultiSampling) return true;
|
||||
|
||||
// Check whether we have a visual with the requested number of samples
|
||||
GLXFBConfig new_info;
|
||||
if(!FindFBConfig(Config.Graphics.MultiSampling, &new_info)) return false;
|
||||
|
||||
GdkScreen * scr = gtk_widget_get_screen(GTK_WIDGET(render_widget));
|
||||
XVisualInfo *vis_info = glXGetVisualFromFBConfig(dpy, new_info);
|
||||
assert(vis_info);
|
||||
GdkVisual * vis = gdk_x11_screen_lookup_visual(scr, vis_info->visualid);
|
||||
XFree(vis_info);
|
||||
|
||||
// Un- and re-realizing the render_widget does not work, the window
|
||||
// remains hidden afterwards. So we re-create it from scratch.
|
||||
gtk_widget_destroy(GTK_WIDGET(render_widget));
|
||||
render_widget = gtk_drawing_area_new();
|
||||
#if !GTK_CHECK_VERSION(3,10,0)
|
||||
gtk_widget_set_double_buffered (GTK_WIDGET(render_widget), false);
|
||||
#endif
|
||||
g_object_set(G_OBJECT(render_widget), "can-focus", TRUE, NULL);
|
||||
|
||||
gtk_widget_set_visual(GTK_WIDGET(render_widget),vis);
|
||||
|
||||
Info = new_info;
|
||||
|
||||
// Wait until window is mapped to get the window's XID
|
||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(render_widget));
|
||||
gtk_widget_show_now(GTK_WIDGET(render_widget));
|
||||
|
||||
if (GTK_IS_LAYOUT(render_widget))
|
||||
{
|
||||
GdkWindow* bin_wnd = gtk_layout_get_bin_window(GTK_LAYOUT(render_widget));
|
||||
renderwnd = GDK_WINDOW_XID(bin_wnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
GdkWindow* render_wnd = gtk_widget_get_window(GTK_WIDGET(render_widget));
|
||||
renderwnd = GDK_WINDOW_XID(render_wnd);
|
||||
}
|
||||
|
||||
gdk_flush();
|
||||
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(render_widget)),
|
||||
gdk_cursor_new_for_display(gdk_display_get_default(), GDK_BLANK_CURSOR));
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void C4Window::Clear()
|
||||
{
|
||||
if (window != NULL)
|
||||
{
|
||||
g_signal_handler_disconnect(window, handlerDestroy);
|
||||
gtk_widget_destroy(GTK_WIDGET(window));
|
||||
handlerDestroy = 0;
|
||||
}
|
||||
|
||||
// Avoid that the base class tries to free these
|
||||
renderwnd = 0;
|
||||
|
||||
window = NULL;
|
||||
Active = false;
|
||||
|
||||
Info = 0;
|
||||
}
|
||||
|
||||
void C4Window::SetSize(unsigned int width, unsigned int height)
|
||||
{
|
||||
gtk_window_resize(GTK_WINDOW(window), width, height);
|
||||
}
|
||||
|
||||
bool C4Window::GetSize(C4Rect * r)
|
||||
{
|
||||
r->x = 0; r->y = 0;
|
||||
gtk_window_get_size(GTK_WINDOW(window), &r->Wdt, &r->Hgt);
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4Window::SetTitle(char const * Title)
|
||||
{
|
||||
gtk_window_set_title(GTK_WINDOW(window), Title);
|
||||
}
|
||||
|
||||
void C4Window::RequestUpdate()
|
||||
{
|
||||
// just invoke directly
|
||||
PerformUpdate();
|
||||
}
|
|
@ -62,42 +62,7 @@ bool EraseItemSafe(const char *szFilename)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_GTK
|
||||
#include <gtk/gtk.h>
|
||||
bool OpenURL(const char *szURL)
|
||||
{
|
||||
GError *error = 0;
|
||||
if (gtk_show_uri(NULL, szURL, GDK_CURRENT_TIME, &error))
|
||||
return true;
|
||||
if (error != NULL)
|
||||
{
|
||||
fprintf (stderr, "Unable to open URL: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
const char * argv[][3] =
|
||||
{
|
||||
{ "xdg-open", szURL, 0 },
|
||||
{ "sensible-browser", szURL, 0 },
|
||||
{ "firefox", szURL, 0 },
|
||||
{ "mozilla", szURL, 0 },
|
||||
{ "konqueror", szURL, 0 },
|
||||
{ "epiphany", szURL, 0 },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
for (int i = 0; argv[i][0]; ++i)
|
||||
{
|
||||
error = 0;
|
||||
if (g_spawn_async (g_get_home_dir(), const_cast<char**>(argv[i]), 0, G_SPAWN_SEARCH_PATH, 0, 0, 0, &error))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#elif defined(WITH_QT_EDITOR)
|
||||
#if defined(WITH_QT_EDITOR)
|
||||
#undef LineFeed
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#if defined(USE_WIN32_WINDOWS) || (defined(_WIN32) && defined(USE_GTK))
|
||||
#if defined(USE_WIN32_WINDOWS)
|
||||
#define USE_WGL
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue