UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2017 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <inttypes.h> 32 #include <stdarg.h> 33 34 #include "menu.h" 35 #include "toolkit.h" 36 #include "../common/context.h" 37 #include "../common/menu.h" 38 #include "../common/types.h" 39 #include "../ui/properties.h" 40 #include "../ui/window.h" 41 #include "container.h" 42 43 #include <cx/linked_list.h> 44 #include <cx/array_list.h> 45 46 #if GTK_MAJOR_VERSION <= 3 47 48 static ui_menu_add_f createMenuItem[] = { 49 /* UI_MENU */ add_menu_widget, 50 /* UI_MENU_ITEM */ add_menuitem_widget, 51 /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, 52 /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, 53 /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, 54 /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, 55 /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, 56 /* UI_MENU_SEPARATOR */ add_menuseparator_widget 57 }; 58 59 // private menu functions 60 GtkWidget *ui_create_menubar(UiObject *obj) { 61 UiMenu *menus_begin = uic_get_menu_list(); 62 if(menus_begin == NULL) { 63 return NULL; 64 } 65 66 GtkWidget *mb = gtk_menu_bar_new(); 67 68 UiMenu *ls = menus_begin; 69 while(ls) { 70 UiMenu *menu = ls; 71 add_menu_widget(mb, 0, &menu->item, obj); 72 73 ls = (UiMenu*)ls->item.next; 74 } 75 76 return mb; 77 } 78 79 void ui_add_menu_items(GtkWidget *parent, int i, UiMenu *menu, UiObject *obj) { 80 UiMenuItemI *it = menu->items_begin; 81 int index = 0; 82 while(it) { 83 createMenuItem[it->type](parent, index, it, obj); 84 it = it->next; 85 index++; 86 } 87 } 88 89 void add_menu_widget(GtkWidget *parent, int i, UiMenuItemI *item, UiObject *obj) { 90 UiMenu *menu = (UiMenu*)item; 91 92 GtkWidget *menu_widget = gtk_menu_new(); 93 GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(menu->label); 94 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu_widget); 95 96 ui_add_menu_items(menu_widget, i, menu, obj); 97 98 99 gtk_menu_shell_append(GTK_MENU_SHELL(parent), menu_item); 100 } 101 102 void add_menuitem_widget(GtkWidget *parent, int index, UiMenuItemI *item, UiObject *obj) { 103 UiMenuItem *i = (UiMenuItem*)item; 104 105 //GtkWidget *widget = gtk_menu_item_new_with_label(i->title); 106 GtkWidget *widget = gtk_menu_item_new_with_mnemonic(i->label); 107 108 if(i->callback != NULL) { 109 UiEventData *event = malloc(sizeof(UiEventData)); 110 event->obj = obj; 111 event->userdata = i->userdata; 112 event->callback = i->callback; 113 event->value = 0; 114 event->customdata = NULL; 115 116 g_signal_connect( 117 widget, 118 "activate", 119 G_CALLBACK(ui_menu_event_wrapper), 120 event); 121 g_signal_connect( 122 widget, 123 "destroy", 124 G_CALLBACK(ui_destroy_userdata), 125 event); 126 } 127 128 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); 129 130 if(i->groups) { 131 CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups); 132 cxListAddArray(groups, i->groups, i->ngroups); 133 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, groups); 134 cxListDestroy(groups); 135 } 136 } 137 138 /* 139 void add_menuitem_st_widget( 140 GtkWidget *parent, 141 int index, 142 UiMenuItemI *item, 143 UiObject *obj) 144 { 145 UiStMenuItem *i = (UiStMenuItem*)item; 146 147 GtkWidget *widget = gtk_image_menu_item_new_from_stock(i->stockid, obj->ctx->accel_group); 148 149 if(i->callback != NULL) { 150 UiEventData *event = malloc(sizeof(UiEventData)); 151 event->obj = obj; 152 event->userdata = i->userdata; 153 event->callback = i->callback; 154 event->value = 0; 155 156 g_signal_connect( 157 widget, 158 "activate", 159 G_CALLBACK(ui_menu_event_wrapper), 160 event); 161 g_signal_connect( 162 widget, 163 "destroy", 164 G_CALLBACK(ui_destroy_userdata), 165 event); 166 } 167 168 gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); 169 170 if(i->groups) { 171 uic_add_group_widget(obj->ctx, widget, (ui_enablefunc)ui_set_enabled, i->groups); 172 } 173 } 174 */ 175 176 void add_menuseparator_widget( 177 GtkWidget *parent, 178 int index, 179 UiMenuItemI *item, 180 UiObject *obj) 181 { 182 gtk_menu_shell_append( 183 GTK_MENU_SHELL(parent), 184 gtk_separator_menu_item_new()); 185 } 186 187 void add_checkitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 188 UiMenuCheckItem *ci = (UiMenuCheckItem*)item; 189 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); 190 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); 191 192 if(ci->callback) { 193 UiEventData *event = malloc(sizeof(UiEventData)); 194 event->obj = obj; 195 event->userdata = ci->userdata; 196 event->callback = ci->callback; 197 event->value = 0; 198 event->customdata = NULL; 199 200 g_signal_connect( 201 widget, 202 "toggled", 203 G_CALLBACK(ui_menu_event_toggled), 204 event); 205 g_signal_connect( 206 widget, 207 "destroy", 208 G_CALLBACK(ui_destroy_userdata), 209 event); 210 } 211 } 212 213 void add_radioitem_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 214 // TODO 215 } 216 217 /* 218 void add_checkitemnv_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 219 UiCheckItemNV *ci = (UiCheckItemNV*)item; 220 GtkWidget *widget = gtk_check_menu_item_new_with_mnemonic(ci->label); 221 gtk_menu_shell_append(GTK_MENU_SHELL(p), widget); 222 223 UiVar *var = uic_create_var(obj->ctx, ci->varname, UI_VAR_INTEGER); 224 if(var) { 225 UiInteger *value = var->value; 226 value->obj = widget; 227 value->get = ui_checkitem_get; 228 value->set = ui_checkitem_set; 229 value = 0; 230 } else { 231 // TODO: error 232 } 233 } 234 */ 235 236 void add_menuitem_list_widget(GtkWidget *p, int index, UiMenuItemI *item, UiObject *obj) { 237 UiMenuItemList *il = (UiMenuItemList*)item; 238 const CxAllocator *a = obj->ctx->allocator; 239 240 UiActiveMenuItemList *ls = cxMalloc( 241 a, 242 sizeof(UiActiveMenuItemList)); 243 244 ls->object = obj; 245 ls->menu = GTK_MENU_SHELL(p); 246 ls->index = index; 247 ls->oldcount = 0; 248 ls->getvalue = il->getvalue; 249 250 UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); 251 ls->list = var->value; 252 253 ls->callback = il->callback; 254 ls->userdata = il->userdata; 255 256 UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls); 257 ls->list->observers = ui_obsvlist_add(ls->list->observers, observer); 258 uic_list_register_observer_destructor(obj->ctx, ls->list, observer); 259 260 ui_update_menuitem_list(NULL, ls); 261 } 262 263 264 void ui_update_menuitem_list(UiEvent *event, UiActiveMenuItemList *list) { 265 // remove old items 266 if(list->oldcount > 0) { 267 int i = 0; 268 GList *mi = gtk_container_get_children(GTK_CONTAINER(list->menu)); 269 while(mi) { 270 if(i >= list->index && i < list->index + list->oldcount) { 271 //gtk_container_remove(GTK_CONTAINER(list->menu), mi->data); 272 gtk_widget_destroy(mi->data); 273 } 274 mi = mi->next; 275 i++; 276 } 277 } 278 279 void* elm = ui_list_first(list->list); 280 if(elm) { 281 GtkWidget *widget = gtk_separator_menu_item_new(); 282 gtk_menu_shell_insert(list->menu, widget, list->index); 283 gtk_widget_show(widget); 284 } 285 286 ui_getvaluefunc getvalue = list->getvalue; 287 int i = 1; 288 while(elm) { 289 char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); 290 291 GtkWidget *widget = gtk_menu_item_new_with_label(label); 292 gtk_menu_shell_insert(list->menu, widget, list->index + i); 293 gtk_widget_show(widget); 294 295 if(list->callback) { 296 UiEventData *event = malloc(sizeof(UiEventData)); 297 event->obj = list->object; 298 event->userdata = list->userdata; 299 event->callback = list->callback; 300 event->value = i - 1; 301 event->customdata = elm; 302 303 g_signal_connect( 304 widget, 305 "activate", 306 G_CALLBACK(ui_menu_event_wrapper), 307 event); 308 g_signal_connect( 309 widget, 310 "destroy", 311 G_CALLBACK(ui_destroy_userdata), 312 event); 313 } 314 315 elm = ui_list_next(list->list); 316 i++; 317 } 318 319 list->oldcount = i; 320 } 321 322 void ui_menu_event_wrapper(GtkMenuItem *item, UiEventData *event) { 323 UiEvent evt; 324 evt.obj = event->obj; 325 evt.window = event->obj->window; 326 evt.document = event->obj->ctx->document; 327 evt.eventdata = event->customdata; 328 evt.intval = event->value; 329 event->callback(&evt, event->userdata); 330 } 331 332 void ui_menu_event_toggled(GtkCheckMenuItem *ci, UiEventData *event) { 333 UiEvent evt; 334 evt.obj = event->obj; 335 evt.window = event->obj->window; 336 evt.document = event->obj->ctx->document; 337 evt.eventdata = NULL; 338 evt.intval = gtk_check_menu_item_get_active(ci); 339 event->callback(&evt, event->userdata); 340 } 341 342 int64_t ui_checkitem_get(UiInteger *i) { 343 int state = gtk_check_menu_item_get_active(i->obj); 344 i->value = state; 345 return state; 346 } 347 348 void ui_checkitem_set(UiInteger *i, int64_t value) { 349 i->value = value; 350 gtk_check_menu_item_set_active(i->obj, value); 351 } 352 353 354 /* 355 * widget menu functions 356 */ 357 358 UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget) { 359 GtkWidget *menu_widget = gtk_menu_new(); 360 ui_add_menu_items(menu_widget, 0, builder->menus_begin, obj); 361 return GTK_MENU(menu_widget); 362 } 363 364 static gboolean ui_button_press_event(GtkWidget *widget, GdkEvent *event, GtkMenu *menu) { 365 if(event->type == GDK_BUTTON_PRESS) { 366 GdkEventButton *e = (GdkEventButton*)event; 367 if(e->button == 3) { 368 gtk_widget_show_all(GTK_WIDGET(menu)); 369 ui_contextmenu_popup(menu, widget, 0, 0); 370 } 371 } 372 return FALSE; 373 } 374 375 void ui_widget_set_contextmenu(GtkWidget *widget, GtkMenu *menu) { 376 g_signal_connect(widget, "button-press-event", (GCallback) ui_button_press_event, menu); 377 } 378 379 void ui_contextmenu_popup(UIMENU menu, GtkWidget *widget, int x, int y) { 380 #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 16 381 gtk_menu_popup_at_pointer(menu, NULL); 382 #else 383 gtk_menu_popup(menu, NULL, NULL, 0, 0, 0, gtk_get_current_event_time()); 384 #endif 385 } 386 387 #endif /* GTK_MAJOR_VERSION <= 3 */ 388 389 390 391 #if GTK_MAJOR_VERSION >= 4 392 393 394 395 static ui_gmenu_add_f createMenuItem[] = { 396 /* UI_MENU */ ui_gmenu_add_menu, 397 /* UI_MENU_ITEM */ ui_gmenu_add_menuitem, 398 /* UI_MENU_CHECK_ITEM */ ui_gmenu_add_checkitem, 399 /* UI_MENU_RADIO_ITEM */ ui_gmenu_add_radioitem, 400 /* UI_MENU_ITEM_LIST */ ui_gmenu_add_menuitem_list, 401 /* UI_MENU_CHECKITEM_LIST */ ui_gmenu_add_menuitem_list, 402 /* UI_MENU_RADIOITEM_LIST */ ui_gmenu_add_menuitem_list, 403 /* UI_MENU_SEPARATOR */ ui_gmenu_add_menuseparator 404 }; 405 406 void ui_gmenu_add_menu_items(GMenu *parent, int i, UiMenu *menu, UiObject *obj) { 407 UiMenuItemI *it = menu->items_begin; 408 int index = 0; 409 int index_section = 0; 410 GMenu *section = NULL; 411 while(it) { 412 if(it->type == UI_MENU_SEPARATOR) { 413 section = g_menu_new(); 414 g_menu_append_section(parent, NULL, G_MENU_MODEL(section)); 415 index++; 416 index_section = 0; 417 } else { 418 if(section) { 419 createMenuItem[it->type](section, index_section++, it, obj); 420 } else { 421 createMenuItem[it->type](parent, index++, it, obj); 422 } 423 } 424 it = it->next; 425 } 426 } 427 428 void ui_gmenu_add_menu(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { 429 UiMenu *mi = (UiMenu*)item; 430 GMenu *menu = g_menu_new(); 431 ui_gmenu_add_menu_items(menu, 0, mi, obj); 432 g_menu_append_submenu(parent, mi->label, G_MENU_MODEL(menu)); 433 } 434 435 static void action_enable(GSimpleAction *action, int enabled) { 436 g_simple_action_set_enabled(action, enabled); 437 } 438 439 void ui_gmenu_add_menuitem(GMenu *parent, int index, UiMenuItemI *item, UiObject *obj) { 440 UiMenuItem *i = (UiMenuItem*)item; 441 442 GSimpleAction *action = g_simple_action_new(item->id, NULL); 443 g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); 444 445 if(i->groups) { 446 CxList *groups = cxArrayListCreateSimple(sizeof(int), i->ngroups); 447 cxListAddArray(groups, i->groups, i->ngroups); 448 uic_add_group_widget(obj->ctx, action, (ui_enablefunc)action_enable, groups); 449 cxListDestroy(groups); 450 } 451 452 if(i->callback != NULL) { 453 UiEventData *event = malloc(sizeof(UiEventData)); 454 event->obj = obj; 455 event->userdata = i->userdata; 456 event->callback = i->callback; 457 event->value = 0; 458 event->customdata = NULL; 459 460 g_signal_connect( 461 action, 462 "activate", 463 G_CALLBACK(ui_activate_event_wrapper), 464 event); 465 g_signal_connect( 466 obj->widget, 467 "destroy", 468 G_CALLBACK(ui_destroy_userdata), 469 event); 470 } 471 472 char action_name[32]; 473 snprintf(action_name, 32, "win.%s", item->id); 474 g_menu_append(parent, i->label, action_name); 475 } 476 477 void ui_gmenu_add_menuseparator(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { 478 479 } 480 481 void ui_gmenu_add_checkitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { 482 UiMenuCheckItem *checkitem = (UiMenuCheckItem*)item; 483 484 // TODO 485 } 486 487 void ui_gmenu_add_radioitem(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { 488 489 } 490 491 void ui_gmenu_add_menuitem_list(GMenu *p, int index, UiMenuItemI *item, UiObject *obj) { 492 UiMenuItemList *il = (UiMenuItemList*)item; 493 494 const CxAllocator *a = obj->ctx->allocator; 495 496 UiActiveGMenuItemList *ls = cxMalloc( 497 a, 498 sizeof(UiActiveGMenuItemList)); 499 500 ls->object = obj; 501 ls->menu = p; 502 ls->index = index; 503 ls->oldcount = 0; 504 ls->getvalue = il->getvalue; 505 506 UiVar* var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); 507 ls->var = var; 508 UiList *list = var->value; 509 510 ls->callback = il->callback; 511 ls->userdata = il->userdata; 512 513 UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls); 514 list->observers = ui_obsvlist_add(list->observers, observer); 515 uic_list_register_observer_destructor(obj->ctx, list, observer); 516 517 GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i")); 518 g_action_map_add_action(obj->ctx->action_map, G_ACTION(action)); 519 snprintf(ls->action, 32, "win.%s", item->id); 520 521 522 UiEventData *event = malloc(sizeof(UiEventData)); 523 event->obj = obj; 524 event->userdata = il->userdata; 525 event->callback = il->callback; 526 event->customdata = var; 527 event->value = 0; 528 529 g_signal_connect( 530 action, 531 "activate", 532 G_CALLBACK(ui_menu_list_item_activate_event_wrapper), 533 event); 534 g_signal_connect( 535 obj->widget, 536 "destroy", 537 G_CALLBACK(ui_destroy_userdata), 538 event); 539 540 ui_update_gmenu_item_list(NULL, ls); 541 } 542 543 void ui_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { 544 int intval = event->value; 545 if(parameter && g_variant_is_of_type(parameter, G_VARIANT_TYPE_INT32)) { 546 intval = g_variant_get_int32(parameter); 547 } 548 549 UiEvent evt; 550 evt.obj = event->obj; 551 evt.window = event->obj->window; 552 evt.document = event->obj->ctx->document; 553 evt.eventdata = event->customdata; 554 evt.intval = intval; 555 event->callback(&evt, event->userdata); 556 } 557 558 void ui_menu_list_item_activate_event_wrapper(GSimpleAction* self, GVariant* parameter, UiEventData *event) { 559 int index = g_variant_get_int32(parameter); 560 UiVar *var = event->customdata; 561 UiList *list = var->value; 562 563 UiEvent evt; 564 evt.obj = event->obj; 565 evt.window = event->obj->window; 566 evt.document = event->obj->ctx->document; 567 evt.eventdata = ui_list_get(list, index); 568 evt.intval = index; 569 event->callback(&evt, event->userdata); 570 571 } 572 573 void ui_update_gmenu_item_list(UiEvent *event, UiActiveGMenuItemList *list) { 574 // remove old items 575 for(int i=0;i<list->oldcount;i++) { 576 g_menu_remove(list->menu, list->index); 577 } 578 UiList *ls = list->var->value; 579 580 // add list items 581 ui_getvaluefunc getvalue = list->getvalue; 582 int i = 0; 583 void* elm = ui_list_first(ls); 584 while(elm) { 585 char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); 586 587 GMenuItem *item = g_menu_item_new(label, NULL); 588 GVariant *v = g_variant_new("i", i); 589 g_menu_item_set_action_and_target_value(item, list->action, v); 590 g_menu_insert_item(list->menu, list->index+i, item); 591 592 elm = ui_list_next(ls); 593 i++; 594 } 595 596 list->oldcount = i; 597 } 598 599 600 /* --------------------- context menu / menubuilder --------------------- */ 601 602 static void remove_popover(GtkWidget *object, GtkPopoverMenu *menu) { 603 gtk_widget_unparent(GTK_WIDGET(menu)); 604 } 605 606 UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, GtkWidget *widget) { 607 GMenu *menu = g_menu_new(); 608 ui_gmenu_add_menu_items(menu, 0, builder->menus_begin, obj); 609 GtkWidget *contextmenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu)); 610 gtk_popover_set_has_arrow(GTK_POPOVER(contextmenu), FALSE); 611 gtk_widget_set_halign(contextmenu, GTK_ALIGN_START); 612 gtk_widget_set_parent(GTK_WIDGET(contextmenu), widget); 613 g_signal_connect( 614 widget, 615 "destroy", 616 G_CALLBACK(remove_popover), 617 contextmenu); 618 return GTK_POPOVER_MENU(contextmenu); 619 } 620 621 static void gesture_button_press(GtkGestureClick *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { 622 gtk_popover_set_pointing_to(GTK_POPOVER(user_data), &(GdkRectangle){ x, y, 0, 0 }); 623 gtk_popover_popup(GTK_POPOVER(user_data)); 624 } 625 626 void ui_widget_set_contextmenu(GtkWidget *widget, GtkPopoverMenu *menu) { 627 GtkGesture *gesture = gtk_gesture_click_new(); 628 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3); 629 gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); 630 g_signal_connect(gesture, "pressed", G_CALLBACK(gesture_button_press), menu); 631 } 632 633 void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y) { 634 gtk_popover_set_pointing_to(GTK_POPOVER(menu), &(GdkRectangle){ x, y, 0, 0 }); 635 gtk_popover_popup(GTK_POPOVER(menu)); 636 } 637 638 #endif 639