00001
00002
00003
00004 #include "menu_hack.h"
00005
00006 #include <vcl_iostream.h>
00007 #include <vcl_vector.h>
00008
00009 #include <vgui/vgui_gl.h>
00010 #include <vgui/vgui_glut.h>
00011
00012 #include <X11/Xlib.h>
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 struct GLUTwindow
00029 {
00030 int num;
00031
00032
00033 #if defined(_WIN32) && !defined(__CYGWIN__)
00034 int pf;
00035 HDC hdc;
00036 #endif
00037 Window win;
00038
00039 };
00040
00041
00042 extern Display *__glutDisplay;
00043 extern GLUTwindow *__glutCurrentWindow;
00044 extern GLUTwindow *__glutMenuWindow;
00045
00046
00047
00048 int vgui_glut_menu_hack::glut_button = 0;
00049 bool vgui_glut_menu_hack::active = false;
00050 void (*vgui_glut_menu_hack::last_minute_change_callback)(int menu_id) = 0;
00051
00052
00053
00054 struct vgui_glut_menu_hack_bind_entry
00055 {
00056 int button;
00057 int mods;
00058 int menu_id;
00059 };
00060
00061 static vgui_glut_menu_hack_bind_entry default_entries[] = {
00062 {GLUT_LEFT_BUTTON ,0 ,0},
00063 {GLUT_LEFT_BUTTON ,GLUT_ACTIVE_SHIFT,0},
00064 {GLUT_LEFT_BUTTON ,GLUT_ACTIVE_CTRL ,0},
00065 {GLUT_LEFT_BUTTON ,GLUT_ACTIVE_ALT ,0},
00066 {GLUT_MIDDLE_BUTTON,0 ,0},
00067 {GLUT_MIDDLE_BUTTON,GLUT_ACTIVE_SHIFT,0},
00068 {GLUT_MIDDLE_BUTTON,GLUT_ACTIVE_CTRL ,0},
00069 {GLUT_MIDDLE_BUTTON,GLUT_ACTIVE_ALT ,0},
00070 {GLUT_RIGHT_BUTTON ,0 ,0},
00071 {GLUT_RIGHT_BUTTON ,GLUT_ACTIVE_SHIFT,0},
00072 {GLUT_RIGHT_BUTTON ,GLUT_ACTIVE_CTRL ,0},
00073 {GLUT_RIGHT_BUTTON ,GLUT_ACTIVE_ALT ,0},
00074 };
00075
00076 const unsigned int table_size = sizeof(default_entries)/sizeof(default_entries[0]);
00077
00078 struct vgui_glut_menu_hack::per_window_record
00079 {
00080 vgui_glut_menu_hack_bind_entry entries[ table_size ];
00081 per_window_record() {
00082 for (unsigned i=0;i<table_size; ++i)
00083 entries[i] = default_entries[i];
00084 }
00085 };
00086
00087 static vgui_glut_menu_hack::per_window_record * get_current_record()
00088 {
00089 static vcl_vector<vgui_glut_menu_hack::per_window_record *> records;
00090
00091 unsigned win = glutGetWindow();
00092 if (win == 0)
00093 return 0;
00094 while (win >= records.size())
00095 records.push_back( (vgui_glut_menu_hack::per_window_record*)0 );
00096
00097 if (records[win] == 0) {
00098 #ifdef DEBUG
00099 vcl_cerr << __FILE__ " : create record for window " << win << vcl_endl;
00100 #endif
00101 records[win] = new vgui_glut_menu_hack::per_window_record;
00102 }
00103
00104 return records[win];
00105 }
00106
00107
00108
00109 int vgui_glut_menu_hack::find_index(int button, int mods)
00110 {
00111 const per_window_record *rec = get_current_record();
00112 if (!rec)
00113 return -1;
00114 for (unsigned i=0; i<table_size; i++)
00115 if (button==rec->entries[i].button && mods==rec->entries[i].mods)
00116 return i;
00117 vcl_cerr << __FILE__ " : invalid button/modifier combination " << button << ' ' << mods << vcl_endl;
00118 return -1;
00119 }
00120
00121 bool vgui_glut_menu_hack::mouse(int button, int state, int x, int y)
00122 {
00123 if (state != GLUT_DOWN)
00124 return false;
00125
00126 int mods = glutGetModifiers();
00127
00128 int index = find_index(button, mods);
00129
00130 if (index<0)
00131 return false;
00132
00133 const per_window_record *rec = get_current_record();
00134 if (!rec)
00135 return false;
00136
00137 if (rec->entries[index].menu_id==0)
00138 return false;
00139
00140
00141 if (last_minute_change_callback)
00142 last_minute_change_callback(rec->entries[index].menu_id);
00143
00144 active = true;
00145 glut_button = button;
00146 #ifdef DEBUG
00147 vcl_cerr << "active\n";
00148 #endif
00149
00150
00151 {
00152 int old_id = glutGetMenu();
00153 int tmp_id = rec->entries[index].menu_id;
00154 glutSetMenu(tmp_id);
00155 glutAttachMenu(glut_button);
00156 if (old_id)
00157 glutSetMenu(old_id);
00158 }
00159
00160 {
00161 static XEvent event;
00162 event.xbutton.type = ButtonPress;
00163 event.xbutton.serial = 0x12345678;
00164 event.xbutton.send_event = 0;
00165 event.xbutton.display = __glutDisplay;
00166 event.xbutton.window = __glutCurrentWindow->win;
00167 event.xbutton.root = 0;
00168 event.xbutton.subwindow = 0;
00169 event.xbutton.time = 0;
00170 event.xbutton.x = x;
00171 event.xbutton.y = y;
00172 event.xbutton.x_root = glutGet(GLenum(GLUT_WINDOW_X)) + x;
00173 event.xbutton.y_root = glutGet(GLenum(GLUT_WINDOW_Y)) + y;
00174 event.xbutton.state = 0;
00175 if (glut_button == GLUT_LEFT_BUTTON)
00176 event.xbutton.button = Button1;
00177 if (glut_button == GLUT_MIDDLE_BUTTON)
00178 event.xbutton.button = Button2;
00179 if (glut_button == GLUT_RIGHT_BUTTON)
00180 event.xbutton.button = Button3;
00181 event.xbutton.same_screen = 1;
00182
00183 XPutBackEvent(__glutDisplay, &event);
00184 }
00185
00186
00187 return true;
00188 }
00189
00190 void vgui_glut_menu_hack::menustatus(int status,int ,int )
00191 {
00192 if (active && status == GLUT_MENU_NOT_IN_USE) {
00193 glutDetachMenu(glut_button);
00194 #ifdef DEBUG
00195 vcl_cerr << "purged\n";
00196 #endif
00197 active = false;
00198 }
00199 }
00200
00201
00202
00203 void vgui_glut_menu_hack::bind (int button, int mods, int menu_id)
00204 {
00205 int index = find_index(button, mods);
00206 if (index<0)
00207 return;
00208 else {
00209 per_window_record *rec = get_current_record();
00210 if (!rec)
00211 return;
00212 #ifdef DEBUG
00213 vcl_cerr << "bind : " << glutGetWindow() << ' ' << button << ' ' << mods << ' ' << menu_id << vcl_endl;
00214 #endif
00215 rec->entries[index].menu_id = menu_id;
00216 }
00217 }