File indexing completed on 2024-04-21 05:46:58
0001 /***************************************************************************** 0002 * Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com> * 0003 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU Lesser General Public License as * 0007 * published by the Free Software Foundation; either version 2.1 of the * 0008 * License, or (at your option) version 3, or any later version accepted * 0009 * by the membership of KDE e.V. (or its successor approved by the * 0010 * membership of KDE e.V.), which shall act as a proxy defined in * 0011 * Section 6 of version 3 of the license. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0016 * Lesser General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU Lesser General Public * 0019 * License along with this library. If not, * 0020 * see <http://www.gnu.org/licenses/>. * 0021 *****************************************************************************/ 0022 0023 #include "menu.h" 0024 0025 #include <qtcurve-utils/gtkprops.h> 0026 #include <qtcurve-utils/x11qtc.h> 0027 #include <qtcurve-cairo/utils.h> 0028 0029 #include <gdk/gdkx.h> 0030 #include <common/common.h> 0031 0032 namespace QtCurve { 0033 namespace Menu { 0034 0035 #define EXTEND_MENUBAR_ITEM_HACK 0036 0037 #ifdef EXTEND_MENUBAR_ITEM_HACK 0038 static bool 0039 isSelectable(GtkWidget *menu) 0040 { 0041 return !((!gtk_bin_get_child(GTK_BIN(menu)) && 0042 G_OBJECT_TYPE(menu) == GTK_TYPE_MENU_ITEM) || 0043 GTK_IS_SEPARATOR_MENU_ITEM(menu) || 0044 !gtk_widget_is_sensitive(menu) || 0045 !gtk_widget_get_visible(menu)); 0046 } 0047 0048 static gboolean 0049 shellButtonPress(GtkWidget *widget, GdkEventButton *event, void*) 0050 { 0051 if (GTK_IS_MENU_BAR(widget)) { 0052 // QtCurve's menubars have a 2 pixel border -> 0053 // but want the left/top to be 'active'... 0054 int nx, ny; 0055 gdk_window_get_origin(gtk_widget_get_window(widget), &nx, &ny); 0056 if ((event->x_root - nx) <= 2.0 || (event->y_root - ny) <= 2.0) { 0057 if ((event->x_root - nx) <= 2.0) { 0058 event->x_root += 2.0; 0059 } 0060 if ((event->y_root - ny) <= 2.0) { 0061 event->y_root += 2.0; 0062 } 0063 0064 GtkMenuShell *menuShell = GTK_MENU_SHELL(widget); 0065 GList *children = 0066 gtk_container_get_children(GTK_CONTAINER(menuShell)); 0067 bool rv = false; 0068 for (GList *child = children;child;child = child->next) { 0069 GtkWidget *item = (GtkWidget*)child->data; 0070 QtcRect alloc = Widget::getAllocation(item); 0071 int cx = alloc.x + nx; 0072 int cy = alloc.y + ny; 0073 int cw = alloc.width; 0074 int ch = alloc.height; 0075 if (cx <= event->x_root && cy <= event->y_root && 0076 (cx + cw) > event->x_root && (cy + ch) > event->y_root) { 0077 if (isSelectable(item)) { 0078 if (event->type == GDK_BUTTON_PRESS) { 0079 if (item != menuShell->active_menu_item) { 0080 menuShell->active = false; 0081 gtk_menu_shell_select_item(menuShell, item); 0082 menuShell->active = true; 0083 } else { 0084 menuShell->active = true; 0085 gtk_menu_shell_deselect(menuShell); 0086 menuShell->active = false; 0087 } 0088 } 0089 rv = true; 0090 } 0091 break; 0092 } 0093 } 0094 if (children) { 0095 g_list_free(children); 0096 } 0097 return rv; 0098 } 0099 } 0100 return false; 0101 } 0102 #endif 0103 0104 static void 0105 shellCleanup(GtkWidget *widget) 0106 { 0107 if (GTK_IS_MENU_BAR(widget)) { 0108 GtkWidgetProps props(widget); 0109 props->menuShellMotion.disconn(); 0110 props->menuShellLeave.disconn(); 0111 props->menuShellDestroy.disconn(); 0112 props->menuShellStyleSet.disconn(); 0113 #ifdef EXTEND_MENUBAR_ITEM_HACK 0114 props->menuShellButtonPress.disconn(); 0115 props->menuShellButtonRelease.disconn(); 0116 #endif 0117 props->menuShellHacked = true; 0118 } 0119 } 0120 0121 static gboolean 0122 shellStyleSet(GtkWidget *widget, GtkStyle*, void*) 0123 { 0124 shellCleanup(widget); 0125 return false; 0126 } 0127 0128 static gboolean 0129 shellDestroy(GtkWidget *widget, GdkEvent*, void*) 0130 { 0131 shellCleanup(widget); 0132 return false; 0133 } 0134 0135 static gboolean 0136 shellMotion(GtkWidget *widget, GdkEventMotion*, void*) 0137 { 0138 if (GTK_IS_MENU_SHELL(widget)) { 0139 int pointer_x, pointer_y; 0140 GdkModifierType pointer_mask; 0141 0142 gdk_window_get_pointer(gtk_widget_get_window(widget), &pointer_x, 0143 &pointer_y, &pointer_mask); 0144 0145 if (GTK_IS_CONTAINER(widget)) { 0146 GList *children = gtk_container_get_children(GTK_CONTAINER(widget)); 0147 for (GList *child = children;child;child = g_list_next(child)) { 0148 if ((child->data) && GTK_IS_WIDGET(child->data) && 0149 (gtk_widget_get_state(GTK_WIDGET(child->data)) != 0150 GTK_STATE_INSENSITIVE)) { 0151 QtcRect alloc = 0152 Widget::getAllocation(GTK_WIDGET(child->data)); 0153 0154 if ((pointer_x >= alloc.x) && (pointer_y >= alloc.y) && 0155 (pointer_x < (alloc.x + alloc.width)) && 0156 (pointer_y < (alloc.y + alloc.height))) { 0157 gtk_widget_set_state(GTK_WIDGET(child->data), 0158 GTK_STATE_PRELIGHT); 0159 } else { 0160 gtk_widget_set_state(GTK_WIDGET(child->data), 0161 GTK_STATE_NORMAL); 0162 } 0163 } 0164 } 0165 if (children) { 0166 g_list_free(children); 0167 } 0168 } 0169 } 0170 0171 return false; 0172 } 0173 0174 static gboolean 0175 shellLeave(GtkWidget *widget, GdkEventCrossing*, void*) 0176 { 0177 if (GTK_IS_MENU_SHELL(widget) && GTK_IS_CONTAINER(widget)) { 0178 GList *children = gtk_container_get_children(GTK_CONTAINER(widget)); 0179 for (GList *child = children;child;child = g_list_next(child)) { 0180 if ((child->data) && GTK_IS_MENU_ITEM(child->data) && 0181 (gtk_widget_get_state(GTK_WIDGET(child->data)) != 0182 GTK_STATE_INSENSITIVE)) { 0183 GtkWidget *submenu = 0184 gtk_menu_item_get_submenu(GTK_MENU_ITEM(child->data)); 0185 GtkWidget *topLevel = 0186 submenu ? gtk_widget_get_toplevel(submenu) : nullptr; 0187 0188 if (submenu && 0189 ((!GTK_IS_MENU(submenu)) || 0190 (!(gtk_widget_get_realized(submenu) && 0191 gtk_widget_get_visible(submenu) && 0192 gtk_widget_get_realized(topLevel) && 0193 gtk_widget_get_visible(topLevel))))) { 0194 gtk_widget_set_state(GTK_WIDGET(child->data), 0195 GTK_STATE_NORMAL); 0196 } 0197 } 0198 } 0199 if (children) { 0200 g_list_free(children); 0201 } 0202 } 0203 return false; 0204 } 0205 0206 void 0207 shellSetup(GtkWidget *widget) 0208 { 0209 GtkWidgetProps props(widget); 0210 if (GTK_IS_MENU_BAR(widget) && !props->menuShellHacked) { 0211 props->menuShellHacked = true; 0212 props->menuShellMotion.conn("motion-notify-event", shellMotion); 0213 props->menuShellLeave.conn("leave-notify-event", shellLeave); 0214 props->menuShellDestroy.conn("destroy-event", shellDestroy); 0215 props->menuShellStyleSet.conn("style-set", shellStyleSet); 0216 #ifdef EXTEND_MENUBAR_ITEM_HACK 0217 props->menuShellButtonPress.conn("button-press-event", 0218 shellButtonPress); 0219 props->menuShellButtonRelease.conn("button-release-event", 0220 shellButtonPress); 0221 #endif 0222 } 0223 } 0224 0225 bool 0226 emitSize(GtkWidget *w, unsigned size) 0227 { 0228 if (w) { 0229 GtkWidgetProps props(w); 0230 unsigned oldSize = props->menuBarSize; 0231 0232 if (oldSize != size) { 0233 GtkWidget *topLevel = gtk_widget_get_toplevel(w); 0234 xcb_window_t wid = 0235 GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel))); 0236 0237 if (size == 0xFFFF) { 0238 size = 0; 0239 } 0240 props->menuBarSize = size; 0241 qtcX11SetMenubarSize(wid, size); 0242 return true; 0243 } 0244 } 0245 return false; 0246 } 0247 0248 } 0249 }