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=3328
qteditor
Lukas Werling 2016-08-03 16:10:36 +02:00
parent c12c51b44d
commit b7359e0c27
23 changed files with 12 additions and 4504 deletions

View File

@ -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}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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().

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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()
{

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)));

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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>

View File

@ -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